7020 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.4 * Copyright (c) 2014- QLogic Corporation.5 * All rights reserved6 * www.qlogic.com7 *8 * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.9 */10 11#include "bfad_drv.h"12#include "bfad_im.h"13#include "bfa_ioc.h"14#include "bfi_reg.h"15#include "bfa_defs.h"16#include "bfa_defs_svc.h"17#include "bfi.h"18 19BFA_TRC_FILE(CNA, IOC);20 21/*22 * IOC local definitions23 */24#define BFA_IOC_TOV 3000 /* msecs */25#define BFA_IOC_HWSEM_TOV 500 /* msecs */26#define BFA_IOC_HB_TOV 500 /* msecs */27#define BFA_IOC_TOV_RECOVER BFA_IOC_HB_TOV28#define BFA_IOC_POLL_TOV BFA_TIMER_FREQ29 30#define bfa_ioc_timer_start(__ioc) \31 bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \32 bfa_ioc_timeout, (__ioc), BFA_IOC_TOV)33#define bfa_ioc_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->ioc_timer)34 35#define bfa_hb_timer_start(__ioc) \36 bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->hb_timer, \37 bfa_ioc_hb_check, (__ioc), BFA_IOC_HB_TOV)38#define bfa_hb_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->hb_timer)39 40#define BFA_DBG_FWTRC_OFF(_fn) (BFI_IOC_TRC_OFF + BFA_DBG_FWTRC_LEN * (_fn))41 42#define bfa_ioc_state_disabled(__sm) \43 (((__sm) == BFI_IOC_UNINIT) || \44 ((__sm) == BFI_IOC_INITING) || \45 ((__sm) == BFI_IOC_HWINIT) || \46 ((__sm) == BFI_IOC_DISABLED) || \47 ((__sm) == BFI_IOC_FAIL) || \48 ((__sm) == BFI_IOC_CFG_DISABLED))49 50/*51 * Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details.52 */53 54#define bfa_ioc_firmware_lock(__ioc) \55 ((__ioc)->ioc_hwif->ioc_firmware_lock(__ioc))56#define bfa_ioc_firmware_unlock(__ioc) \57 ((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc))58#define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc))59#define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc))60#define bfa_ioc_notify_fail(__ioc) \61 ((__ioc)->ioc_hwif->ioc_notify_fail(__ioc))62#define bfa_ioc_sync_start(__ioc) \63 ((__ioc)->ioc_hwif->ioc_sync_start(__ioc))64#define bfa_ioc_sync_join(__ioc) \65 ((__ioc)->ioc_hwif->ioc_sync_join(__ioc))66#define bfa_ioc_sync_leave(__ioc) \67 ((__ioc)->ioc_hwif->ioc_sync_leave(__ioc))68#define bfa_ioc_sync_ack(__ioc) \69 ((__ioc)->ioc_hwif->ioc_sync_ack(__ioc))70#define bfa_ioc_sync_complete(__ioc) \71 ((__ioc)->ioc_hwif->ioc_sync_complete(__ioc))72#define bfa_ioc_set_cur_ioc_fwstate(__ioc, __fwstate) \73 ((__ioc)->ioc_hwif->ioc_set_fwstate(__ioc, __fwstate))74#define bfa_ioc_get_cur_ioc_fwstate(__ioc) \75 ((__ioc)->ioc_hwif->ioc_get_fwstate(__ioc))76#define bfa_ioc_set_alt_ioc_fwstate(__ioc, __fwstate) \77 ((__ioc)->ioc_hwif->ioc_set_alt_fwstate(__ioc, __fwstate))78#define bfa_ioc_get_alt_ioc_fwstate(__ioc) \79 ((__ioc)->ioc_hwif->ioc_get_alt_fwstate(__ioc))80 81#define bfa_ioc_mbox_cmd_pending(__ioc) \82 (!list_empty(&((__ioc)->mbox_mod.cmd_q)) || \83 readl((__ioc)->ioc_regs.hfn_mbox_cmd))84 85bfa_boolean_t bfa_auto_recover = BFA_TRUE;86 87/*88 * forward declarations89 */90static void bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc);91static void bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force);92static void bfa_ioc_timeout(void *ioc);93static void bfa_ioc_poll_fwinit(struct bfa_ioc_s *ioc);94static void bfa_ioc_send_enable(struct bfa_ioc_s *ioc);95static void bfa_ioc_send_disable(struct bfa_ioc_s *ioc);96static void bfa_ioc_send_getattr(struct bfa_ioc_s *ioc);97static void bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc);98static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc);99static void bfa_ioc_mbox_flush(struct bfa_ioc_s *ioc);100static void bfa_ioc_recover(struct bfa_ioc_s *ioc);101static void bfa_ioc_event_notify(struct bfa_ioc_s *ioc ,102 enum bfa_ioc_event_e event);103static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc);104static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc);105static void bfa_ioc_fail_notify(struct bfa_ioc_s *ioc);106static void bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc);107static enum bfi_ioc_img_ver_cmp_e bfa_ioc_fw_ver_patch_cmp(108 struct bfi_ioc_image_hdr_s *base_fwhdr,109 struct bfi_ioc_image_hdr_s *fwhdr_to_cmp);110static enum bfi_ioc_img_ver_cmp_e bfa_ioc_flash_fwver_cmp(111 struct bfa_ioc_s *ioc,112 struct bfi_ioc_image_hdr_s *base_fwhdr);113 114/*115 * IOC state machine definitions/declarations116 */117bfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc_s, enum ioc_event);118bfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc_s, enum ioc_event);119bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc_s, enum ioc_event);120bfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc_s, enum ioc_event);121bfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc_s, enum ioc_event);122bfa_fsm_state_decl(bfa_ioc, fail_retry, struct bfa_ioc_s, enum ioc_event);123bfa_fsm_state_decl(bfa_ioc, fail, struct bfa_ioc_s, enum ioc_event);124bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event);125bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event);126bfa_fsm_state_decl(bfa_ioc, hwfail, struct bfa_ioc_s, enum ioc_event);127 128struct bfa_ioc_sm_table {129 bfa_ioc_sm_t sm; /* state machine function */130 enum bfa_ioc_state state; /* state machine encoding */131 char *name; /* state name for display */132};133 134static struct bfa_ioc_sm_table ioc_sm_table[] = {135 {BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT},136 {BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET},137 {BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_ENABLING},138 {BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR},139 {BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL},140 {BFA_SM(bfa_ioc_sm_fail_retry), BFA_IOC_INITFAIL},141 {BFA_SM(bfa_ioc_sm_fail), BFA_IOC_FAIL},142 {BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},143 {BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},144 {BFA_SM(bfa_ioc_sm_hwfail), BFA_IOC_HWFAIL},145};146 147static inline enum bfa_ioc_state148bfa_ioc_sm_to_state(struct bfa_ioc_sm_table *smt, bfa_ioc_sm_t sm)149{150 int i = 0;151 152 while (smt[i].sm && smt[i].sm != sm)153 i++;154 return smt[i].state;155}156 157/*158 * IOCPF state machine definitions/declarations159 */160 161#define bfa_iocpf_timer_start(__ioc) \162 bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \163 bfa_iocpf_timeout, (__ioc), BFA_IOC_TOV)164#define bfa_iocpf_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->ioc_timer)165 166#define bfa_iocpf_poll_timer_start(__ioc) \167 bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \168 bfa_iocpf_poll_timeout, (__ioc), BFA_IOC_POLL_TOV)169 170#define bfa_sem_timer_start(__ioc) \171 bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->sem_timer, \172 bfa_iocpf_sem_timeout, (__ioc), BFA_IOC_HWSEM_TOV)173#define bfa_sem_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->sem_timer)174 175/*176 * Forward declareations for iocpf state machine177 */178static void bfa_iocpf_timeout(void *ioc_arg);179static void bfa_iocpf_sem_timeout(void *ioc_arg);180static void bfa_iocpf_poll_timeout(void *ioc_arg);181 182/*183 * IOCPF states184 */185enum bfa_iocpf_state {186 BFA_IOCPF_RESET = 1, /* IOC is in reset state */187 BFA_IOCPF_SEMWAIT = 2, /* Waiting for IOC h/w semaphore */188 BFA_IOCPF_HWINIT = 3, /* IOC h/w is being initialized */189 BFA_IOCPF_READY = 4, /* IOCPF is initialized */190 BFA_IOCPF_INITFAIL = 5, /* IOCPF failed */191 BFA_IOCPF_FAIL = 6, /* IOCPF failed */192 BFA_IOCPF_DISABLING = 7, /* IOCPF is being disabled */193 BFA_IOCPF_DISABLED = 8, /* IOCPF is disabled */194 BFA_IOCPF_FWMISMATCH = 9, /* IOC f/w different from drivers */195};196 197bfa_fsm_state_decl(bfa_iocpf, reset, struct bfa_iocpf_s, enum iocpf_event);198bfa_fsm_state_decl(bfa_iocpf, fwcheck, struct bfa_iocpf_s, enum iocpf_event);199bfa_fsm_state_decl(bfa_iocpf, mismatch, struct bfa_iocpf_s, enum iocpf_event);200bfa_fsm_state_decl(bfa_iocpf, semwait, struct bfa_iocpf_s, enum iocpf_event);201bfa_fsm_state_decl(bfa_iocpf, hwinit, struct bfa_iocpf_s, enum iocpf_event);202bfa_fsm_state_decl(bfa_iocpf, enabling, struct bfa_iocpf_s, enum iocpf_event);203bfa_fsm_state_decl(bfa_iocpf, ready, struct bfa_iocpf_s, enum iocpf_event);204bfa_fsm_state_decl(bfa_iocpf, initfail_sync, struct bfa_iocpf_s,205 enum iocpf_event);206bfa_fsm_state_decl(bfa_iocpf, initfail, struct bfa_iocpf_s, enum iocpf_event);207bfa_fsm_state_decl(bfa_iocpf, fail_sync, struct bfa_iocpf_s, enum iocpf_event);208bfa_fsm_state_decl(bfa_iocpf, fail, struct bfa_iocpf_s, enum iocpf_event);209bfa_fsm_state_decl(bfa_iocpf, disabling, struct bfa_iocpf_s, enum iocpf_event);210bfa_fsm_state_decl(bfa_iocpf, disabling_sync, struct bfa_iocpf_s,211 enum iocpf_event);212bfa_fsm_state_decl(bfa_iocpf, disabled, struct bfa_iocpf_s, enum iocpf_event);213 214struct bfa_iocpf_sm_table {215 bfa_iocpf_sm_t sm; /* state machine function */216 enum bfa_iocpf_state state; /* state machine encoding */217 char *name; /* state name for display */218};219 220static inline enum bfa_iocpf_state221bfa_iocpf_sm_to_state(struct bfa_iocpf_sm_table *smt, bfa_iocpf_sm_t sm)222{223 int i = 0;224 225 while (smt[i].sm && smt[i].sm != sm)226 i++;227 return smt[i].state;228}229 230static struct bfa_iocpf_sm_table iocpf_sm_table[] = {231 {BFA_SM(bfa_iocpf_sm_reset), BFA_IOCPF_RESET},232 {BFA_SM(bfa_iocpf_sm_fwcheck), BFA_IOCPF_FWMISMATCH},233 {BFA_SM(bfa_iocpf_sm_mismatch), BFA_IOCPF_FWMISMATCH},234 {BFA_SM(bfa_iocpf_sm_semwait), BFA_IOCPF_SEMWAIT},235 {BFA_SM(bfa_iocpf_sm_hwinit), BFA_IOCPF_HWINIT},236 {BFA_SM(bfa_iocpf_sm_enabling), BFA_IOCPF_HWINIT},237 {BFA_SM(bfa_iocpf_sm_ready), BFA_IOCPF_READY},238 {BFA_SM(bfa_iocpf_sm_initfail_sync), BFA_IOCPF_INITFAIL},239 {BFA_SM(bfa_iocpf_sm_initfail), BFA_IOCPF_INITFAIL},240 {BFA_SM(bfa_iocpf_sm_fail_sync), BFA_IOCPF_FAIL},241 {BFA_SM(bfa_iocpf_sm_fail), BFA_IOCPF_FAIL},242 {BFA_SM(bfa_iocpf_sm_disabling), BFA_IOCPF_DISABLING},243 {BFA_SM(bfa_iocpf_sm_disabling_sync), BFA_IOCPF_DISABLING},244 {BFA_SM(bfa_iocpf_sm_disabled), BFA_IOCPF_DISABLED},245};246 247/*248 * IOC State Machine249 */250 251/*252 * Beginning state. IOC uninit state.253 */254 255static void256bfa_ioc_sm_uninit_entry(struct bfa_ioc_s *ioc)257{258}259 260/*261 * IOC is in uninit state.262 */263static void264bfa_ioc_sm_uninit(struct bfa_ioc_s *ioc, enum ioc_event event)265{266 bfa_trc(ioc, event);267 268 switch (event) {269 case IOC_E_RESET:270 bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);271 break;272 273 default:274 bfa_sm_fault(ioc, event);275 }276}277/*278 * Reset entry actions -- initialize state machine279 */280static void281bfa_ioc_sm_reset_entry(struct bfa_ioc_s *ioc)282{283 bfa_fsm_set_state(&ioc->iocpf, bfa_iocpf_sm_reset);284}285 286/*287 * IOC is in reset state.288 */289static void290bfa_ioc_sm_reset(struct bfa_ioc_s *ioc, enum ioc_event event)291{292 bfa_trc(ioc, event);293 294 switch (event) {295 case IOC_E_ENABLE:296 bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);297 break;298 299 case IOC_E_DISABLE:300 bfa_ioc_disable_comp(ioc);301 break;302 303 case IOC_E_DETACH:304 bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);305 break;306 307 default:308 bfa_sm_fault(ioc, event);309 }310}311 312 313static void314bfa_ioc_sm_enabling_entry(struct bfa_ioc_s *ioc)315{316 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_ENABLE);317}318 319/*320 * Host IOC function is being enabled, awaiting response from firmware.321 * Semaphore is acquired.322 */323static void324bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event)325{326 bfa_trc(ioc, event);327 328 switch (event) {329 case IOC_E_ENABLED:330 bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);331 break;332 333 case IOC_E_PFFAILED:334 /* !!! fall through !!! */335 case IOC_E_HWERROR:336 ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);337 bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);338 if (event != IOC_E_PFFAILED)339 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL);340 break;341 342 case IOC_E_HWFAILED:343 ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);344 bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);345 break;346 347 case IOC_E_DISABLE:348 bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);349 break;350 351 case IOC_E_DETACH:352 bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);353 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);354 break;355 356 case IOC_E_ENABLE:357 break;358 359 default:360 bfa_sm_fault(ioc, event);361 }362}363 364 365static void366bfa_ioc_sm_getattr_entry(struct bfa_ioc_s *ioc)367{368 bfa_ioc_timer_start(ioc);369 bfa_ioc_send_getattr(ioc);370}371 372/*373 * IOC configuration in progress. Timer is active.374 */375static void376bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event)377{378 bfa_trc(ioc, event);379 380 switch (event) {381 case IOC_E_FWRSP_GETATTR:382 bfa_ioc_timer_stop(ioc);383 bfa_fsm_set_state(ioc, bfa_ioc_sm_op);384 break;385 386 case IOC_E_PFFAILED:387 case IOC_E_HWERROR:388 bfa_ioc_timer_stop(ioc);389 fallthrough;390 case IOC_E_TIMEOUT:391 ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);392 bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);393 if (event != IOC_E_PFFAILED)394 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL);395 break;396 397 case IOC_E_DISABLE:398 bfa_ioc_timer_stop(ioc);399 bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);400 break;401 402 case IOC_E_ENABLE:403 break;404 405 default:406 bfa_sm_fault(ioc, event);407 }408}409 410static void411bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc)412{413 struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;414 415 ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);416 bfa_ioc_event_notify(ioc, BFA_IOC_E_ENABLED);417 bfa_ioc_hb_monitor(ioc);418 BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC enabled\n");419 bfa_ioc_aen_post(ioc, BFA_IOC_AEN_ENABLE);420}421 422static void423bfa_ioc_sm_op(struct bfa_ioc_s *ioc, enum ioc_event event)424{425 bfa_trc(ioc, event);426 427 switch (event) {428 case IOC_E_ENABLE:429 break;430 431 case IOC_E_DISABLE:432 bfa_hb_timer_stop(ioc);433 bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);434 break;435 436 case IOC_E_PFFAILED:437 case IOC_E_HWERROR:438 bfa_hb_timer_stop(ioc);439 fallthrough;440 case IOC_E_HBFAIL:441 if (ioc->iocpf.auto_recover)442 bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry);443 else444 bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);445 446 bfa_ioc_fail_notify(ioc);447 448 if (event != IOC_E_PFFAILED)449 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL);450 break;451 452 default:453 bfa_sm_fault(ioc, event);454 }455}456 457 458static void459bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc)460{461 struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;462 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_DISABLE);463 BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC disabled\n");464 bfa_ioc_aen_post(ioc, BFA_IOC_AEN_DISABLE);465}466 467/*468 * IOC is being disabled469 */470static void471bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event)472{473 bfa_trc(ioc, event);474 475 switch (event) {476 case IOC_E_DISABLED:477 bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);478 break;479 480 case IOC_E_HWERROR:481 /*482 * No state change. Will move to disabled state483 * after iocpf sm completes failure processing and484 * moves to disabled state.485 */486 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL);487 break;488 489 case IOC_E_HWFAILED:490 bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);491 bfa_ioc_disable_comp(ioc);492 break;493 494 default:495 bfa_sm_fault(ioc, event);496 }497}498 499/*500 * IOC disable completion entry.501 */502static void503bfa_ioc_sm_disabled_entry(struct bfa_ioc_s *ioc)504{505 bfa_ioc_disable_comp(ioc);506}507 508static void509bfa_ioc_sm_disabled(struct bfa_ioc_s *ioc, enum ioc_event event)510{511 bfa_trc(ioc, event);512 513 switch (event) {514 case IOC_E_ENABLE:515 bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);516 break;517 518 case IOC_E_DISABLE:519 ioc->cbfn->disable_cbfn(ioc->bfa);520 break;521 522 case IOC_E_DETACH:523 bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);524 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);525 break;526 527 default:528 bfa_sm_fault(ioc, event);529 }530}531 532 533static void534bfa_ioc_sm_fail_retry_entry(struct bfa_ioc_s *ioc)535{536 bfa_trc(ioc, 0);537}538 539/*540 * Hardware initialization retry.541 */542static void543bfa_ioc_sm_fail_retry(struct bfa_ioc_s *ioc, enum ioc_event event)544{545 bfa_trc(ioc, event);546 547 switch (event) {548 case IOC_E_ENABLED:549 bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);550 break;551 552 case IOC_E_PFFAILED:553 case IOC_E_HWERROR:554 /*555 * Initialization retry failed.556 */557 ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);558 bfa_fsm_set_state(ioc, bfa_ioc_sm_fail);559 if (event != IOC_E_PFFAILED)560 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL);561 break;562 563 case IOC_E_HWFAILED:564 ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);565 bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail);566 break;567 568 case IOC_E_ENABLE:569 break;570 571 case IOC_E_DISABLE:572 bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);573 break;574 575 case IOC_E_DETACH:576 bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);577 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);578 break;579 580 default:581 bfa_sm_fault(ioc, event);582 }583}584 585 586static void587bfa_ioc_sm_fail_entry(struct bfa_ioc_s *ioc)588{589 bfa_trc(ioc, 0);590}591 592/*593 * IOC failure.594 */595static void596bfa_ioc_sm_fail(struct bfa_ioc_s *ioc, enum ioc_event event)597{598 bfa_trc(ioc, event);599 600 switch (event) {601 602 case IOC_E_ENABLE:603 ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);604 break;605 606 case IOC_E_DISABLE:607 bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);608 break;609 610 case IOC_E_DETACH:611 bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);612 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP);613 break;614 615 case IOC_E_HWERROR:616 case IOC_E_HWFAILED:617 /*618 * HB failure / HW error notification, ignore.619 */620 break;621 default:622 bfa_sm_fault(ioc, event);623 }624}625 626static void627bfa_ioc_sm_hwfail_entry(struct bfa_ioc_s *ioc)628{629 bfa_trc(ioc, 0);630}631 632static void633bfa_ioc_sm_hwfail(struct bfa_ioc_s *ioc, enum ioc_event event)634{635 bfa_trc(ioc, event);636 637 switch (event) {638 case IOC_E_ENABLE:639 ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);640 break;641 642 case IOC_E_DISABLE:643 ioc->cbfn->disable_cbfn(ioc->bfa);644 break;645 646 case IOC_E_DETACH:647 bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);648 break;649 650 case IOC_E_HWERROR:651 /* Ignore - already in hwfail state */652 break;653 654 default:655 bfa_sm_fault(ioc, event);656 }657}658 659/*660 * IOCPF State Machine661 */662 663/*664 * Reset entry actions -- initialize state machine665 */666static void667bfa_iocpf_sm_reset_entry(struct bfa_iocpf_s *iocpf)668{669 iocpf->fw_mismatch_notified = BFA_FALSE;670 iocpf->auto_recover = bfa_auto_recover;671}672 673/*674 * Beginning state. IOC is in reset state.675 */676static void677bfa_iocpf_sm_reset(struct bfa_iocpf_s *iocpf, enum iocpf_event event)678{679 struct bfa_ioc_s *ioc = iocpf->ioc;680 681 bfa_trc(ioc, event);682 683 switch (event) {684 case IOCPF_E_ENABLE:685 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fwcheck);686 break;687 688 case IOCPF_E_STOP:689 break;690 691 default:692 bfa_sm_fault(ioc, event);693 }694}695 696/*697 * Semaphore should be acquired for version check.698 */699static void700bfa_iocpf_sm_fwcheck_entry(struct bfa_iocpf_s *iocpf)701{702 struct bfi_ioc_image_hdr_s fwhdr;703 u32 r32, fwstate, pgnum, loff = 0;704 int i;705 706 /*707 * Spin on init semaphore to serialize.708 */709 r32 = readl(iocpf->ioc->ioc_regs.ioc_init_sem_reg);710 while (r32 & 0x1) {711 udelay(20);712 r32 = readl(iocpf->ioc->ioc_regs.ioc_init_sem_reg);713 }714 715 /* h/w sem init */716 fwstate = bfa_ioc_get_cur_ioc_fwstate(iocpf->ioc);717 if (fwstate == BFI_IOC_UNINIT) {718 writel(1, iocpf->ioc->ioc_regs.ioc_init_sem_reg);719 goto sem_get;720 }721 722 bfa_ioc_fwver_get(iocpf->ioc, &fwhdr);723 724 if (swab32(fwhdr.exec) == BFI_FWBOOT_TYPE_NORMAL) {725 writel(1, iocpf->ioc->ioc_regs.ioc_init_sem_reg);726 goto sem_get;727 }728 729 /*730 * Clear fwver hdr731 */732 pgnum = PSS_SMEM_PGNUM(iocpf->ioc->ioc_regs.smem_pg0, loff);733 writel(pgnum, iocpf->ioc->ioc_regs.host_page_num_fn);734 735 for (i = 0; i < sizeof(struct bfi_ioc_image_hdr_s) / sizeof(u32); i++) {736 bfa_mem_write(iocpf->ioc->ioc_regs.smem_page_start, loff, 0);737 loff += sizeof(u32);738 }739 740 bfa_trc(iocpf->ioc, fwstate);741 bfa_trc(iocpf->ioc, swab32(fwhdr.exec));742 bfa_ioc_set_cur_ioc_fwstate(iocpf->ioc, BFI_IOC_UNINIT);743 bfa_ioc_set_alt_ioc_fwstate(iocpf->ioc, BFI_IOC_UNINIT);744 745 /*746 * Unlock the hw semaphore. Should be here only once per boot.747 */748 bfa_ioc_ownership_reset(iocpf->ioc);749 750 /*751 * unlock init semaphore.752 */753 writel(1, iocpf->ioc->ioc_regs.ioc_init_sem_reg);754 755sem_get:756 bfa_ioc_hw_sem_get(iocpf->ioc);757}758 759/*760 * Awaiting h/w semaphore to continue with version check.761 */762static void763bfa_iocpf_sm_fwcheck(struct bfa_iocpf_s *iocpf, enum iocpf_event event)764{765 struct bfa_ioc_s *ioc = iocpf->ioc;766 767 bfa_trc(ioc, event);768 769 switch (event) {770 case IOCPF_E_SEMLOCKED:771 if (bfa_ioc_firmware_lock(ioc)) {772 if (bfa_ioc_sync_start(ioc)) {773 bfa_ioc_sync_join(ioc);774 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);775 } else {776 bfa_ioc_firmware_unlock(ioc);777 writel(1, ioc->ioc_regs.ioc_sem_reg);778 bfa_sem_timer_start(ioc);779 }780 } else {781 writel(1, ioc->ioc_regs.ioc_sem_reg);782 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_mismatch);783 }784 break;785 786 case IOCPF_E_SEM_ERROR:787 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);788 bfa_fsm_send_event(ioc, IOC_E_HWFAILED);789 break;790 791 case IOCPF_E_DISABLE:792 bfa_sem_timer_stop(ioc);793 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);794 bfa_fsm_send_event(ioc, IOC_E_DISABLED);795 break;796 797 case IOCPF_E_STOP:798 bfa_sem_timer_stop(ioc);799 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);800 break;801 802 default:803 bfa_sm_fault(ioc, event);804 }805}806 807/*808 * Notify enable completion callback.809 */810static void811bfa_iocpf_sm_mismatch_entry(struct bfa_iocpf_s *iocpf)812{813 /*814 * Call only the first time sm enters fwmismatch state.815 */816 if (iocpf->fw_mismatch_notified == BFA_FALSE)817 bfa_ioc_pf_fwmismatch(iocpf->ioc);818 819 iocpf->fw_mismatch_notified = BFA_TRUE;820 bfa_iocpf_timer_start(iocpf->ioc);821}822 823/*824 * Awaiting firmware version match.825 */826static void827bfa_iocpf_sm_mismatch(struct bfa_iocpf_s *iocpf, enum iocpf_event event)828{829 struct bfa_ioc_s *ioc = iocpf->ioc;830 831 bfa_trc(ioc, event);832 833 switch (event) {834 case IOCPF_E_TIMEOUT:835 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fwcheck);836 break;837 838 case IOCPF_E_DISABLE:839 bfa_iocpf_timer_stop(ioc);840 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);841 bfa_fsm_send_event(ioc, IOC_E_DISABLED);842 break;843 844 case IOCPF_E_STOP:845 bfa_iocpf_timer_stop(ioc);846 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);847 break;848 849 default:850 bfa_sm_fault(ioc, event);851 }852}853 854/*855 * Request for semaphore.856 */857static void858bfa_iocpf_sm_semwait_entry(struct bfa_iocpf_s *iocpf)859{860 bfa_ioc_hw_sem_get(iocpf->ioc);861}862 863/*864 * Awaiting semaphore for h/w initialzation.865 */866static void867bfa_iocpf_sm_semwait(struct bfa_iocpf_s *iocpf, enum iocpf_event event)868{869 struct bfa_ioc_s *ioc = iocpf->ioc;870 871 bfa_trc(ioc, event);872 873 switch (event) {874 case IOCPF_E_SEMLOCKED:875 if (bfa_ioc_sync_complete(ioc)) {876 bfa_ioc_sync_join(ioc);877 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);878 } else {879 writel(1, ioc->ioc_regs.ioc_sem_reg);880 bfa_sem_timer_start(ioc);881 }882 break;883 884 case IOCPF_E_SEM_ERROR:885 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);886 bfa_fsm_send_event(ioc, IOC_E_HWFAILED);887 break;888 889 case IOCPF_E_DISABLE:890 bfa_sem_timer_stop(ioc);891 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);892 break;893 894 default:895 bfa_sm_fault(ioc, event);896 }897}898 899static void900bfa_iocpf_sm_hwinit_entry(struct bfa_iocpf_s *iocpf)901{902 iocpf->poll_time = 0;903 bfa_ioc_hwinit(iocpf->ioc, BFA_FALSE);904}905 906/*907 * Hardware is being initialized. Interrupts are enabled.908 * Holding hardware semaphore lock.909 */910static void911bfa_iocpf_sm_hwinit(struct bfa_iocpf_s *iocpf, enum iocpf_event event)912{913 struct bfa_ioc_s *ioc = iocpf->ioc;914 915 bfa_trc(ioc, event);916 917 switch (event) {918 case IOCPF_E_FWREADY:919 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_enabling);920 break;921 922 case IOCPF_E_TIMEOUT:923 writel(1, ioc->ioc_regs.ioc_sem_reg);924 bfa_fsm_send_event(ioc, IOC_E_PFFAILED);925 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);926 break;927 928 case IOCPF_E_DISABLE:929 bfa_iocpf_timer_stop(ioc);930 bfa_ioc_sync_leave(ioc);931 writel(1, ioc->ioc_regs.ioc_sem_reg);932 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);933 break;934 935 default:936 bfa_sm_fault(ioc, event);937 }938}939 940static void941bfa_iocpf_sm_enabling_entry(struct bfa_iocpf_s *iocpf)942{943 bfa_iocpf_timer_start(iocpf->ioc);944 /*945 * Enable Interrupts before sending fw IOC ENABLE cmd.946 */947 iocpf->ioc->cbfn->reset_cbfn(iocpf->ioc->bfa);948 bfa_ioc_send_enable(iocpf->ioc);949}950 951/*952 * Host IOC function is being enabled, awaiting response from firmware.953 * Semaphore is acquired.954 */955static void956bfa_iocpf_sm_enabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event)957{958 struct bfa_ioc_s *ioc = iocpf->ioc;959 960 bfa_trc(ioc, event);961 962 switch (event) {963 case IOCPF_E_FWRSP_ENABLE:964 bfa_iocpf_timer_stop(ioc);965 writel(1, ioc->ioc_regs.ioc_sem_reg);966 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_ready);967 break;968 969 case IOCPF_E_INITFAIL:970 bfa_iocpf_timer_stop(ioc);971 fallthrough;972 973 case IOCPF_E_TIMEOUT:974 writel(1, ioc->ioc_regs.ioc_sem_reg);975 if (event == IOCPF_E_TIMEOUT)976 bfa_fsm_send_event(ioc, IOC_E_PFFAILED);977 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);978 break;979 980 case IOCPF_E_DISABLE:981 bfa_iocpf_timer_stop(ioc);982 writel(1, ioc->ioc_regs.ioc_sem_reg);983 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling);984 break;985 986 default:987 bfa_sm_fault(ioc, event);988 }989}990 991static void992bfa_iocpf_sm_ready_entry(struct bfa_iocpf_s *iocpf)993{994 bfa_fsm_send_event(iocpf->ioc, IOC_E_ENABLED);995}996 997static void998bfa_iocpf_sm_ready(struct bfa_iocpf_s *iocpf, enum iocpf_event event)999{1000 struct bfa_ioc_s *ioc = iocpf->ioc;1001 1002 bfa_trc(ioc, event);1003 1004 switch (event) {1005 case IOCPF_E_DISABLE:1006 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling);1007 break;1008 1009 case IOCPF_E_GETATTRFAIL:1010 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync);1011 break;1012 1013 case IOCPF_E_FAIL:1014 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync);1015 break;1016 1017 default:1018 bfa_sm_fault(ioc, event);1019 }1020}1021 1022static void1023bfa_iocpf_sm_disabling_entry(struct bfa_iocpf_s *iocpf)1024{1025 bfa_iocpf_timer_start(iocpf->ioc);1026 bfa_ioc_send_disable(iocpf->ioc);1027}1028 1029/*1030 * IOC is being disabled1031 */1032static void1033bfa_iocpf_sm_disabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event)1034{1035 struct bfa_ioc_s *ioc = iocpf->ioc;1036 1037 bfa_trc(ioc, event);1038 1039 switch (event) {1040 case IOCPF_E_FWRSP_DISABLE:1041 bfa_iocpf_timer_stop(ioc);1042 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);1043 break;1044 1045 case IOCPF_E_FAIL:1046 bfa_iocpf_timer_stop(ioc);1047 fallthrough;1048 1049 case IOCPF_E_TIMEOUT:1050 bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);1051 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);1052 break;1053 1054 case IOCPF_E_FWRSP_ENABLE:1055 break;1056 1057 default:1058 bfa_sm_fault(ioc, event);1059 }1060}1061 1062static void1063bfa_iocpf_sm_disabling_sync_entry(struct bfa_iocpf_s *iocpf)1064{1065 bfa_ioc_hw_sem_get(iocpf->ioc);1066}1067 1068/*1069 * IOC hb ack request is being removed.1070 */1071static void1072bfa_iocpf_sm_disabling_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)1073{1074 struct bfa_ioc_s *ioc = iocpf->ioc;1075 1076 bfa_trc(ioc, event);1077 1078 switch (event) {1079 case IOCPF_E_SEMLOCKED:1080 bfa_ioc_sync_leave(ioc);1081 writel(1, ioc->ioc_regs.ioc_sem_reg);1082 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);1083 break;1084 1085 case IOCPF_E_SEM_ERROR:1086 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);1087 bfa_fsm_send_event(ioc, IOC_E_HWFAILED);1088 break;1089 1090 case IOCPF_E_FAIL:1091 break;1092 1093 default:1094 bfa_sm_fault(ioc, event);1095 }1096}1097 1098/*1099 * IOC disable completion entry.1100 */1101static void1102bfa_iocpf_sm_disabled_entry(struct bfa_iocpf_s *iocpf)1103{1104 bfa_ioc_mbox_flush(iocpf->ioc);1105 bfa_fsm_send_event(iocpf->ioc, IOC_E_DISABLED);1106}1107 1108static void1109bfa_iocpf_sm_disabled(struct bfa_iocpf_s *iocpf, enum iocpf_event event)1110{1111 struct bfa_ioc_s *ioc = iocpf->ioc;1112 1113 bfa_trc(ioc, event);1114 1115 switch (event) {1116 case IOCPF_E_ENABLE:1117 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);1118 break;1119 1120 case IOCPF_E_STOP:1121 bfa_ioc_firmware_unlock(ioc);1122 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);1123 break;1124 1125 default:1126 bfa_sm_fault(ioc, event);1127 }1128}1129 1130static void1131bfa_iocpf_sm_initfail_sync_entry(struct bfa_iocpf_s *iocpf)1132{1133 bfa_ioc_debug_save_ftrc(iocpf->ioc);1134 bfa_ioc_hw_sem_get(iocpf->ioc);1135}1136 1137/*1138 * Hardware initialization failed.1139 */1140static void1141bfa_iocpf_sm_initfail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)1142{1143 struct bfa_ioc_s *ioc = iocpf->ioc;1144 1145 bfa_trc(ioc, event);1146 1147 switch (event) {1148 case IOCPF_E_SEMLOCKED:1149 bfa_ioc_notify_fail(ioc);1150 bfa_ioc_sync_leave(ioc);1151 bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);1152 writel(1, ioc->ioc_regs.ioc_sem_reg);1153 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail);1154 break;1155 1156 case IOCPF_E_SEM_ERROR:1157 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);1158 bfa_fsm_send_event(ioc, IOC_E_HWFAILED);1159 break;1160 1161 case IOCPF_E_DISABLE:1162 bfa_sem_timer_stop(ioc);1163 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);1164 break;1165 1166 case IOCPF_E_STOP:1167 bfa_sem_timer_stop(ioc);1168 bfa_ioc_firmware_unlock(ioc);1169 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);1170 break;1171 1172 case IOCPF_E_FAIL:1173 break;1174 1175 default:1176 bfa_sm_fault(ioc, event);1177 }1178}1179 1180static void1181bfa_iocpf_sm_initfail_entry(struct bfa_iocpf_s *iocpf)1182{1183 bfa_trc(iocpf->ioc, 0);1184}1185 1186/*1187 * Hardware initialization failed.1188 */1189static void1190bfa_iocpf_sm_initfail(struct bfa_iocpf_s *iocpf, enum iocpf_event event)1191{1192 struct bfa_ioc_s *ioc = iocpf->ioc;1193 1194 bfa_trc(ioc, event);1195 1196 switch (event) {1197 case IOCPF_E_DISABLE:1198 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);1199 break;1200 1201 case IOCPF_E_STOP:1202 bfa_ioc_firmware_unlock(ioc);1203 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset);1204 break;1205 1206 default:1207 bfa_sm_fault(ioc, event);1208 }1209}1210 1211static void1212bfa_iocpf_sm_fail_sync_entry(struct bfa_iocpf_s *iocpf)1213{1214 /*1215 * Mark IOC as failed in hardware and stop firmware.1216 */1217 bfa_ioc_lpu_stop(iocpf->ioc);1218 1219 /*1220 * Flush any queued up mailbox requests.1221 */1222 bfa_ioc_mbox_flush(iocpf->ioc);1223 1224 bfa_ioc_hw_sem_get(iocpf->ioc);1225}1226 1227static void1228bfa_iocpf_sm_fail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event)1229{1230 struct bfa_ioc_s *ioc = iocpf->ioc;1231 1232 bfa_trc(ioc, event);1233 1234 switch (event) {1235 case IOCPF_E_SEMLOCKED:1236 bfa_ioc_sync_ack(ioc);1237 bfa_ioc_notify_fail(ioc);1238 if (!iocpf->auto_recover) {1239 bfa_ioc_sync_leave(ioc);1240 bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_FAIL);1241 writel(1, ioc->ioc_regs.ioc_sem_reg);1242 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);1243 } else {1244 if (bfa_ioc_sync_complete(ioc))1245 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit);1246 else {1247 writel(1, ioc->ioc_regs.ioc_sem_reg);1248 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait);1249 }1250 }1251 break;1252 1253 case IOCPF_E_SEM_ERROR:1254 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail);1255 bfa_fsm_send_event(ioc, IOC_E_HWFAILED);1256 break;1257 1258 case IOCPF_E_DISABLE:1259 bfa_sem_timer_stop(ioc);1260 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync);1261 break;1262 1263 case IOCPF_E_FAIL:1264 break;1265 1266 default:1267 bfa_sm_fault(ioc, event);1268 }1269}1270 1271static void1272bfa_iocpf_sm_fail_entry(struct bfa_iocpf_s *iocpf)1273{1274 bfa_trc(iocpf->ioc, 0);1275}1276 1277/*1278 * IOC is in failed state.1279 */1280static void1281bfa_iocpf_sm_fail(struct bfa_iocpf_s *iocpf, enum iocpf_event event)1282{1283 struct bfa_ioc_s *ioc = iocpf->ioc;1284 1285 bfa_trc(ioc, event);1286 1287 switch (event) {1288 case IOCPF_E_DISABLE:1289 bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled);1290 break;1291 1292 default:1293 bfa_sm_fault(ioc, event);1294 }1295}1296 1297/*1298 * BFA IOC private functions1299 */1300 1301/*1302 * Notify common modules registered for notification.1303 */1304static void1305bfa_ioc_event_notify(struct bfa_ioc_s *ioc, enum bfa_ioc_event_e event)1306{1307 struct bfa_ioc_notify_s *notify;1308 struct list_head *qe;1309 1310 list_for_each(qe, &ioc->notify_q) {1311 notify = (struct bfa_ioc_notify_s *)qe;1312 notify->cbfn(notify->cbarg, event);1313 }1314}1315 1316static void1317bfa_ioc_disable_comp(struct bfa_ioc_s *ioc)1318{1319 ioc->cbfn->disable_cbfn(ioc->bfa);1320 bfa_ioc_event_notify(ioc, BFA_IOC_E_DISABLED);1321}1322 1323bfa_boolean_t1324bfa_ioc_sem_get(void __iomem *sem_reg)1325{1326 u32 r32;1327 int cnt = 0;1328#define BFA_SEM_SPINCNT 30001329 1330 r32 = readl(sem_reg);1331 1332 while ((r32 & 1) && (cnt < BFA_SEM_SPINCNT)) {1333 cnt++;1334 udelay(2);1335 r32 = readl(sem_reg);1336 }1337 1338 if (!(r32 & 1))1339 return BFA_TRUE;1340 1341 return BFA_FALSE;1342}1343 1344static void1345bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc)1346{1347 u32 r32;1348 1349 /*1350 * First read to the semaphore register will return 0, subsequent reads1351 * will return 1. Semaphore is released by writing 1 to the register1352 */1353 r32 = readl(ioc->ioc_regs.ioc_sem_reg);1354 if (r32 == ~0) {1355 WARN_ON(r32 == ~0);1356 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEM_ERROR);1357 return;1358 }1359 if (!(r32 & 1)) {1360 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEMLOCKED);1361 return;1362 }1363 1364 bfa_sem_timer_start(ioc);1365}1366 1367/*1368 * Initialize LPU local memory (aka secondary memory / SRAM)1369 */1370static void1371bfa_ioc_lmem_init(struct bfa_ioc_s *ioc)1372{1373 u32 pss_ctl;1374 int i;1375#define PSS_LMEM_INIT_TIME 100001376 1377 pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);1378 pss_ctl &= ~__PSS_LMEM_RESET;1379 pss_ctl |= __PSS_LMEM_INIT_EN;1380 1381 /*1382 * i2c workaround 12.5khz clock1383 */1384 pss_ctl |= __PSS_I2C_CLK_DIV(3UL);1385 writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);1386 1387 /*1388 * wait for memory initialization to be complete1389 */1390 i = 0;1391 do {1392 pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);1393 i++;1394 } while (!(pss_ctl & __PSS_LMEM_INIT_DONE) && (i < PSS_LMEM_INIT_TIME));1395 1396 /*1397 * If memory initialization is not successful, IOC timeout will catch1398 * such failures.1399 */1400 WARN_ON(!(pss_ctl & __PSS_LMEM_INIT_DONE));1401 bfa_trc(ioc, pss_ctl);1402 1403 pss_ctl &= ~(__PSS_LMEM_INIT_DONE | __PSS_LMEM_INIT_EN);1404 writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);1405}1406 1407static void1408bfa_ioc_lpu_start(struct bfa_ioc_s *ioc)1409{1410 u32 pss_ctl;1411 1412 /*1413 * Take processor out of reset.1414 */1415 pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);1416 pss_ctl &= ~__PSS_LPU0_RESET;1417 1418 writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);1419}1420 1421static void1422bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc)1423{1424 u32 pss_ctl;1425 1426 /*1427 * Put processors in reset.1428 */1429 pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg);1430 pss_ctl |= (__PSS_LPU0_RESET | __PSS_LPU1_RESET);1431 1432 writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg);1433}1434 1435/*1436 * Get driver and firmware versions.1437 */1438void1439bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)1440{1441 u32 pgnum;1442 u32 loff = 0;1443 int i;1444 u32 *fwsig = (u32 *) fwhdr;1445 1446 pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff);1447 writel(pgnum, ioc->ioc_regs.host_page_num_fn);1448 1449 for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr_s) / sizeof(u32));1450 i++) {1451 fwsig[i] =1452 bfa_mem_read(ioc->ioc_regs.smem_page_start, loff);1453 loff += sizeof(u32);1454 }1455}1456 1457/*1458 * Returns TRUE if driver is willing to work with current smem f/w version.1459 */1460bfa_boolean_t1461bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc,1462 struct bfi_ioc_image_hdr_s *smem_fwhdr)1463{1464 struct bfi_ioc_image_hdr_s *drv_fwhdr;1465 enum bfi_ioc_img_ver_cmp_e smem_flash_cmp, drv_smem_cmp;1466 1467 drv_fwhdr = (struct bfi_ioc_image_hdr_s *)1468 bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0);1469 1470 /*1471 * If smem is incompatible or old, driver should not work with it.1472 */1473 drv_smem_cmp = bfa_ioc_fw_ver_patch_cmp(drv_fwhdr, smem_fwhdr);1474 if (drv_smem_cmp == BFI_IOC_IMG_VER_INCOMP ||1475 drv_smem_cmp == BFI_IOC_IMG_VER_OLD) {1476 return BFA_FALSE;1477 }1478 1479 /*1480 * IF Flash has a better F/W than smem do not work with smem.1481 * If smem f/w == flash f/w, as smem f/w not old | incmp, work with it.1482 * If Flash is old or incomp work with smem iff smem f/w == drv f/w.1483 */1484 smem_flash_cmp = bfa_ioc_flash_fwver_cmp(ioc, smem_fwhdr);1485 1486 if (smem_flash_cmp == BFI_IOC_IMG_VER_BETTER) {1487 return BFA_FALSE;1488 } else if (smem_flash_cmp == BFI_IOC_IMG_VER_SAME) {1489 return BFA_TRUE;1490 } else {1491 return (drv_smem_cmp == BFI_IOC_IMG_VER_SAME) ?1492 BFA_TRUE : BFA_FALSE;1493 }1494}1495 1496/*1497 * Return true if current running version is valid. Firmware signature and1498 * execution context (driver/bios) must match.1499 */1500static bfa_boolean_t1501bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env)1502{1503 struct bfi_ioc_image_hdr_s fwhdr;1504 1505 bfa_ioc_fwver_get(ioc, &fwhdr);1506 1507 if (swab32(fwhdr.bootenv) != boot_env) {1508 bfa_trc(ioc, fwhdr.bootenv);1509 bfa_trc(ioc, boot_env);1510 return BFA_FALSE;1511 }1512 1513 return bfa_ioc_fwver_cmp(ioc, &fwhdr);1514}1515 1516static bfa_boolean_t1517bfa_ioc_fwver_md5_check(struct bfi_ioc_image_hdr_s *fwhdr_1,1518 struct bfi_ioc_image_hdr_s *fwhdr_2)1519{1520 int i;1521 1522 for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++)1523 if (fwhdr_1->md5sum[i] != fwhdr_2->md5sum[i])1524 return BFA_FALSE;1525 1526 return BFA_TRUE;1527}1528 1529/*1530 * Returns TRUE if major minor and maintainence are same.1531 * If patch versions are same, check for MD5 Checksum to be same.1532 */1533static bfa_boolean_t1534bfa_ioc_fw_ver_compatible(struct bfi_ioc_image_hdr_s *drv_fwhdr,1535 struct bfi_ioc_image_hdr_s *fwhdr_to_cmp)1536{1537 if (drv_fwhdr->signature != fwhdr_to_cmp->signature)1538 return BFA_FALSE;1539 1540 if (drv_fwhdr->fwver.major != fwhdr_to_cmp->fwver.major)1541 return BFA_FALSE;1542 1543 if (drv_fwhdr->fwver.minor != fwhdr_to_cmp->fwver.minor)1544 return BFA_FALSE;1545 1546 if (drv_fwhdr->fwver.maint != fwhdr_to_cmp->fwver.maint)1547 return BFA_FALSE;1548 1549 if (drv_fwhdr->fwver.patch == fwhdr_to_cmp->fwver.patch &&1550 drv_fwhdr->fwver.phase == fwhdr_to_cmp->fwver.phase &&1551 drv_fwhdr->fwver.build == fwhdr_to_cmp->fwver.build) {1552 return bfa_ioc_fwver_md5_check(drv_fwhdr, fwhdr_to_cmp);1553 }1554 1555 return BFA_TRUE;1556}1557 1558static bfa_boolean_t1559bfa_ioc_flash_fwver_valid(struct bfi_ioc_image_hdr_s *flash_fwhdr)1560{1561 if (flash_fwhdr->fwver.major == 0 || flash_fwhdr->fwver.major == 0xFF)1562 return BFA_FALSE;1563 1564 return BFA_TRUE;1565}1566 1567static bfa_boolean_t fwhdr_is_ga(struct bfi_ioc_image_hdr_s *fwhdr)1568{1569 if (fwhdr->fwver.phase == 0 &&1570 fwhdr->fwver.build == 0)1571 return BFA_TRUE;1572 1573 return BFA_FALSE;1574}1575 1576/*1577 * Returns TRUE if both are compatible and patch of fwhdr_to_cmp is better.1578 */1579static enum bfi_ioc_img_ver_cmp_e1580bfa_ioc_fw_ver_patch_cmp(struct bfi_ioc_image_hdr_s *base_fwhdr,1581 struct bfi_ioc_image_hdr_s *fwhdr_to_cmp)1582{1583 if (bfa_ioc_fw_ver_compatible(base_fwhdr, fwhdr_to_cmp) == BFA_FALSE)1584 return BFI_IOC_IMG_VER_INCOMP;1585 1586 if (fwhdr_to_cmp->fwver.patch > base_fwhdr->fwver.patch)1587 return BFI_IOC_IMG_VER_BETTER;1588 1589 else if (fwhdr_to_cmp->fwver.patch < base_fwhdr->fwver.patch)1590 return BFI_IOC_IMG_VER_OLD;1591 1592 /*1593 * GA takes priority over internal builds of the same patch stream.1594 * At this point major minor maint and patch numbers are same.1595 */1596 1597 if (fwhdr_is_ga(base_fwhdr) == BFA_TRUE) {1598 if (fwhdr_is_ga(fwhdr_to_cmp))1599 return BFI_IOC_IMG_VER_SAME;1600 else1601 return BFI_IOC_IMG_VER_OLD;1602 } else {1603 if (fwhdr_is_ga(fwhdr_to_cmp))1604 return BFI_IOC_IMG_VER_BETTER;1605 }1606 1607 if (fwhdr_to_cmp->fwver.phase > base_fwhdr->fwver.phase)1608 return BFI_IOC_IMG_VER_BETTER;1609 else if (fwhdr_to_cmp->fwver.phase < base_fwhdr->fwver.phase)1610 return BFI_IOC_IMG_VER_OLD;1611 1612 if (fwhdr_to_cmp->fwver.build > base_fwhdr->fwver.build)1613 return BFI_IOC_IMG_VER_BETTER;1614 else if (fwhdr_to_cmp->fwver.build < base_fwhdr->fwver.build)1615 return BFI_IOC_IMG_VER_OLD;1616 1617 /*1618 * All Version Numbers are equal.1619 * Md5 check to be done as a part of compatibility check.1620 */1621 return BFI_IOC_IMG_VER_SAME;1622}1623 1624#define BFA_FLASH_PART_FWIMG_ADDR 0x100000 /* fw image address */1625 1626bfa_status_t1627bfa_ioc_flash_img_get_chnk(struct bfa_ioc_s *ioc, u32 off,1628 u32 *fwimg)1629{1630 return bfa_flash_raw_read(ioc->pcidev.pci_bar_kva,1631 BFA_FLASH_PART_FWIMG_ADDR + (off * sizeof(u32)),1632 (char *)fwimg, BFI_FLASH_CHUNK_SZ);1633}1634 1635static enum bfi_ioc_img_ver_cmp_e1636bfa_ioc_flash_fwver_cmp(struct bfa_ioc_s *ioc,1637 struct bfi_ioc_image_hdr_s *base_fwhdr)1638{1639 struct bfi_ioc_image_hdr_s *flash_fwhdr;1640 bfa_status_t status;1641 u32 fwimg[BFI_FLASH_CHUNK_SZ_WORDS];1642 1643 status = bfa_ioc_flash_img_get_chnk(ioc, 0, fwimg);1644 if (status != BFA_STATUS_OK)1645 return BFI_IOC_IMG_VER_INCOMP;1646 1647 flash_fwhdr = (struct bfi_ioc_image_hdr_s *) fwimg;1648 if (bfa_ioc_flash_fwver_valid(flash_fwhdr) == BFA_TRUE)1649 return bfa_ioc_fw_ver_patch_cmp(base_fwhdr, flash_fwhdr);1650 else1651 return BFI_IOC_IMG_VER_INCOMP;1652}1653 1654 1655/*1656 * Invalidate fwver signature1657 */1658bfa_status_t1659bfa_ioc_fwsig_invalidate(struct bfa_ioc_s *ioc)1660{1661 1662 u32 pgnum;1663 u32 loff = 0;1664 enum bfi_ioc_state ioc_fwstate;1665 1666 ioc_fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);1667 if (!bfa_ioc_state_disabled(ioc_fwstate))1668 return BFA_STATUS_ADAPTER_ENABLED;1669 1670 pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff);1671 writel(pgnum, ioc->ioc_regs.host_page_num_fn);1672 bfa_mem_write(ioc->ioc_regs.smem_page_start, loff, BFA_IOC_FW_INV_SIGN);1673 1674 return BFA_STATUS_OK;1675}1676 1677/*1678 * Conditionally flush any pending message from firmware at start.1679 */1680static void1681bfa_ioc_msgflush(struct bfa_ioc_s *ioc)1682{1683 u32 r32;1684 1685 r32 = readl(ioc->ioc_regs.lpu_mbox_cmd);1686 if (r32)1687 writel(1, ioc->ioc_regs.lpu_mbox_cmd);1688}1689 1690static void1691bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)1692{1693 enum bfi_ioc_state ioc_fwstate;1694 bfa_boolean_t fwvalid;1695 u32 boot_type;1696 u32 boot_env;1697 1698 ioc_fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);1699 1700 if (force)1701 ioc_fwstate = BFI_IOC_UNINIT;1702 1703 bfa_trc(ioc, ioc_fwstate);1704 1705 boot_type = BFI_FWBOOT_TYPE_NORMAL;1706 boot_env = BFI_FWBOOT_ENV_OS;1707 1708 /*1709 * check if firmware is valid1710 */1711 fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ?1712 BFA_FALSE : bfa_ioc_fwver_valid(ioc, boot_env);1713 1714 if (!fwvalid) {1715 if (bfa_ioc_boot(ioc, boot_type, boot_env) == BFA_STATUS_OK)1716 bfa_ioc_poll_fwinit(ioc);1717 return;1718 }1719 1720 /*1721 * If hardware initialization is in progress (initialized by other IOC),1722 * just wait for an initialization completion interrupt.1723 */1724 if (ioc_fwstate == BFI_IOC_INITING) {1725 bfa_ioc_poll_fwinit(ioc);1726 return;1727 }1728 1729 /*1730 * If IOC function is disabled and firmware version is same,1731 * just re-enable IOC.1732 *1733 * If option rom, IOC must not be in operational state. With1734 * convergence, IOC will be in operational state when 2nd driver1735 * is loaded.1736 */1737 if (ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP) {1738 1739 /*1740 * When using MSI-X any pending firmware ready event should1741 * be flushed. Otherwise MSI-X interrupts are not delivered.1742 */1743 bfa_ioc_msgflush(ioc);1744 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY);1745 return;1746 }1747 1748 /*1749 * Initialize the h/w for any other states.1750 */1751 if (bfa_ioc_boot(ioc, boot_type, boot_env) == BFA_STATUS_OK)1752 bfa_ioc_poll_fwinit(ioc);1753}1754 1755static void1756bfa_ioc_timeout(void *ioc_arg)1757{1758 struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg;1759 1760 bfa_trc(ioc, 0);1761 bfa_fsm_send_event(ioc, IOC_E_TIMEOUT);1762}1763 1764void1765bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len)1766{1767 u32 *msgp = (u32 *) ioc_msg;1768 u32 i;1769 1770 bfa_trc(ioc, msgp[0]);1771 bfa_trc(ioc, len);1772 1773 WARN_ON(len > BFI_IOC_MSGLEN_MAX);1774 1775 /*1776 * first write msg to mailbox registers1777 */1778 for (i = 0; i < len / sizeof(u32); i++)1779 writel(cpu_to_le32(msgp[i]),1780 ioc->ioc_regs.hfn_mbox + i * sizeof(u32));1781 1782 for (; i < BFI_IOC_MSGLEN_MAX / sizeof(u32); i++)1783 writel(0, ioc->ioc_regs.hfn_mbox + i * sizeof(u32));1784 1785 /*1786 * write 1 to mailbox CMD to trigger LPU event1787 */1788 writel(1, ioc->ioc_regs.hfn_mbox_cmd);1789 (void) readl(ioc->ioc_regs.hfn_mbox_cmd);1790}1791 1792static void1793bfa_ioc_send_enable(struct bfa_ioc_s *ioc)1794{1795 struct bfi_ioc_ctrl_req_s enable_req;1796 1797 bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ,1798 bfa_ioc_portid(ioc));1799 enable_req.clscode = cpu_to_be16(ioc->clscode);1800 /* unsigned 32-bit time_t overflow in y2106 */1801 enable_req.tv_sec = be32_to_cpu(ktime_get_real_seconds());1802 bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req_s));1803}1804 1805static void1806bfa_ioc_send_disable(struct bfa_ioc_s *ioc)1807{1808 struct bfi_ioc_ctrl_req_s disable_req;1809 1810 bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ,1811 bfa_ioc_portid(ioc));1812 disable_req.clscode = cpu_to_be16(ioc->clscode);1813 /* unsigned 32-bit time_t overflow in y2106 */1814 disable_req.tv_sec = be32_to_cpu(ktime_get_real_seconds());1815 bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req_s));1816}1817 1818static void1819bfa_ioc_send_getattr(struct bfa_ioc_s *ioc)1820{1821 struct bfi_ioc_getattr_req_s attr_req;1822 1823 bfi_h2i_set(attr_req.mh, BFI_MC_IOC, BFI_IOC_H2I_GETATTR_REQ,1824 bfa_ioc_portid(ioc));1825 bfa_dma_be_addr_set(attr_req.attr_addr, ioc->attr_dma.pa);1826 bfa_ioc_mbox_send(ioc, &attr_req, sizeof(attr_req));1827}1828 1829static void1830bfa_ioc_hb_check(void *cbarg)1831{1832 struct bfa_ioc_s *ioc = cbarg;1833 u32 hb_count;1834 1835 hb_count = readl(ioc->ioc_regs.heartbeat);1836 if (ioc->hb_count == hb_count) {1837 bfa_ioc_recover(ioc);1838 return;1839 } else {1840 ioc->hb_count = hb_count;1841 }1842 1843 bfa_ioc_mbox_poll(ioc);1844 bfa_hb_timer_start(ioc);1845}1846 1847static void1848bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc)1849{1850 ioc->hb_count = readl(ioc->ioc_regs.heartbeat);1851 bfa_hb_timer_start(ioc);1852}1853 1854/*1855 * Initiate a full firmware download.1856 */1857static bfa_status_t1858bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,1859 u32 boot_env)1860{1861 u32 *fwimg;1862 u32 pgnum;1863 u32 loff = 0;1864 u32 chunkno = 0;1865 u32 i;1866 u32 asicmode;1867 u32 fwimg_size;1868 u32 fwimg_buf[BFI_FLASH_CHUNK_SZ_WORDS];1869 bfa_status_t status;1870 1871 if (boot_env == BFI_FWBOOT_ENV_OS &&1872 boot_type == BFI_FWBOOT_TYPE_FLASH) {1873 fwimg_size = BFI_FLASH_IMAGE_SZ/sizeof(u32);1874 1875 status = bfa_ioc_flash_img_get_chnk(ioc,1876 BFA_IOC_FLASH_CHUNK_ADDR(chunkno), fwimg_buf);1877 if (status != BFA_STATUS_OK)1878 return status;1879 1880 fwimg = fwimg_buf;1881 } else {1882 fwimg_size = bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc));1883 fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc),1884 BFA_IOC_FLASH_CHUNK_ADDR(chunkno));1885 }1886 1887 bfa_trc(ioc, fwimg_size);1888 1889 1890 pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff);1891 writel(pgnum, ioc->ioc_regs.host_page_num_fn);1892 1893 for (i = 0; i < fwimg_size; i++) {1894 1895 if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) {1896 chunkno = BFA_IOC_FLASH_CHUNK_NO(i);1897 1898 if (boot_env == BFI_FWBOOT_ENV_OS &&1899 boot_type == BFI_FWBOOT_TYPE_FLASH) {1900 status = bfa_ioc_flash_img_get_chnk(ioc,1901 BFA_IOC_FLASH_CHUNK_ADDR(chunkno),1902 fwimg_buf);1903 if (status != BFA_STATUS_OK)1904 return status;1905 1906 fwimg = fwimg_buf;1907 } else {1908 fwimg = bfa_cb_image_get_chunk(1909 bfa_ioc_asic_gen(ioc),1910 BFA_IOC_FLASH_CHUNK_ADDR(chunkno));1911 }1912 }1913 1914 /*1915 * write smem1916 */1917 bfa_mem_write(ioc->ioc_regs.smem_page_start, loff,1918 fwimg[BFA_IOC_FLASH_OFFSET_IN_CHUNK(i)]);1919 1920 loff += sizeof(u32);1921 1922 /*1923 * handle page offset wrap around1924 */1925 loff = PSS_SMEM_PGOFF(loff);1926 if (loff == 0) {1927 pgnum++;1928 writel(pgnum, ioc->ioc_regs.host_page_num_fn);1929 }1930 }1931 1932 writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0),1933 ioc->ioc_regs.host_page_num_fn);1934 1935 /*1936 * Set boot type, env and device mode at the end.1937 */1938 if (boot_env == BFI_FWBOOT_ENV_OS &&1939 boot_type == BFI_FWBOOT_TYPE_FLASH) {1940 boot_type = BFI_FWBOOT_TYPE_NORMAL;1941 }1942 asicmode = BFI_FWBOOT_DEVMODE(ioc->asic_gen, ioc->asic_mode,1943 ioc->port0_mode, ioc->port1_mode);1944 bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_FWBOOT_DEVMODE_OFF,1945 swab32(asicmode));1946 bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_FWBOOT_TYPE_OFF,1947 swab32(boot_type));1948 bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_FWBOOT_ENV_OFF,1949 swab32(boot_env));1950 return BFA_STATUS_OK;1951}1952 1953 1954/*1955 * Update BFA configuration from firmware configuration.1956 */1957static void1958bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc)1959{1960 struct bfi_ioc_attr_s *attr = ioc->attr;1961 1962 attr->adapter_prop = be32_to_cpu(attr->adapter_prop);1963 attr->card_type = be32_to_cpu(attr->card_type);1964 attr->maxfrsize = be16_to_cpu(attr->maxfrsize);1965 ioc->fcmode = (attr->port_mode == BFI_PORT_MODE_FC);1966 attr->mfg_year = be16_to_cpu(attr->mfg_year);1967 1968 bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);1969}1970 1971/*1972 * Attach time initialization of mbox logic.1973 */1974static void1975bfa_ioc_mbox_attach(struct bfa_ioc_s *ioc)1976{1977 struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;1978 int mc;1979 1980 INIT_LIST_HEAD(&mod->cmd_q);1981 for (mc = 0; mc < BFI_MC_MAX; mc++) {1982 mod->mbhdlr[mc].cbfn = NULL;1983 mod->mbhdlr[mc].cbarg = ioc->bfa;1984 }1985}1986 1987/*1988 * Mbox poll timer -- restarts any pending mailbox requests.1989 */1990static void1991bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc)1992{1993 struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;1994 struct bfa_mbox_cmd_s *cmd;1995 u32 stat;1996 1997 /*1998 * If no command pending, do nothing1999 */2000 if (list_empty(&mod->cmd_q))2001 return;2002 2003 /*2004 * If previous command is not yet fetched by firmware, do nothing2005 */2006 stat = readl(ioc->ioc_regs.hfn_mbox_cmd);2007 if (stat)2008 return;2009 2010 /*2011 * Enqueue command to firmware.2012 */2013 bfa_q_deq(&mod->cmd_q, &cmd);2014 bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));2015}2016 2017/*2018 * Cleanup any pending requests.2019 */2020static void2021bfa_ioc_mbox_flush(struct bfa_ioc_s *ioc)2022{2023 struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;2024 struct bfa_mbox_cmd_s *cmd;2025 2026 while (!list_empty(&mod->cmd_q))2027 bfa_q_deq(&mod->cmd_q, &cmd);2028}2029 2030/*2031 * Read data from SMEM to host through PCI memmap2032 *2033 * @param[in] ioc memory for IOC2034 * @param[in] tbuf app memory to store data from smem2035 * @param[in] soff smem offset2036 * @param[in] sz size of smem in bytes2037 */2038static bfa_status_t2039bfa_ioc_smem_read(struct bfa_ioc_s *ioc, void *tbuf, u32 soff, u32 sz)2040{2041 u32 pgnum, loff;2042 __be32 r32;2043 int i, len;2044 u32 *buf = tbuf;2045 2046 pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, soff);2047 loff = PSS_SMEM_PGOFF(soff);2048 bfa_trc(ioc, pgnum);2049 bfa_trc(ioc, loff);2050 bfa_trc(ioc, sz);2051 2052 /*2053 * Hold semaphore to serialize pll init and fwtrc.2054 */2055 if (BFA_FALSE == bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg)) {2056 bfa_trc(ioc, 0);2057 return BFA_STATUS_FAILED;2058 }2059 2060 writel(pgnum, ioc->ioc_regs.host_page_num_fn);2061 2062 len = sz/sizeof(u32);2063 bfa_trc(ioc, len);2064 for (i = 0; i < len; i++) {2065 r32 = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff);2066 buf[i] = swab32(r32);2067 loff += sizeof(u32);2068 2069 /*2070 * handle page offset wrap around2071 */2072 loff = PSS_SMEM_PGOFF(loff);2073 if (loff == 0) {2074 pgnum++;2075 writel(pgnum, ioc->ioc_regs.host_page_num_fn);2076 }2077 }2078 writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0),2079 ioc->ioc_regs.host_page_num_fn);2080 /*2081 * release semaphore.2082 */2083 readl(ioc->ioc_regs.ioc_init_sem_reg);2084 writel(1, ioc->ioc_regs.ioc_init_sem_reg);2085 2086 bfa_trc(ioc, pgnum);2087 return BFA_STATUS_OK;2088}2089 2090/*2091 * Clear SMEM data from host through PCI memmap2092 *2093 * @param[in] ioc memory for IOC2094 * @param[in] soff smem offset2095 * @param[in] sz size of smem in bytes2096 */2097static bfa_status_t2098bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz)2099{2100 int i, len;2101 u32 pgnum, loff;2102 2103 pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, soff);2104 loff = PSS_SMEM_PGOFF(soff);2105 bfa_trc(ioc, pgnum);2106 bfa_trc(ioc, loff);2107 bfa_trc(ioc, sz);2108 2109 /*2110 * Hold semaphore to serialize pll init and fwtrc.2111 */2112 if (BFA_FALSE == bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg)) {2113 bfa_trc(ioc, 0);2114 return BFA_STATUS_FAILED;2115 }2116 2117 writel(pgnum, ioc->ioc_regs.host_page_num_fn);2118 2119 len = sz/sizeof(u32); /* len in words */2120 bfa_trc(ioc, len);2121 for (i = 0; i < len; i++) {2122 bfa_mem_write(ioc->ioc_regs.smem_page_start, loff, 0);2123 loff += sizeof(u32);2124 2125 /*2126 * handle page offset wrap around2127 */2128 loff = PSS_SMEM_PGOFF(loff);2129 if (loff == 0) {2130 pgnum++;2131 writel(pgnum, ioc->ioc_regs.host_page_num_fn);2132 }2133 }2134 writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0),2135 ioc->ioc_regs.host_page_num_fn);2136 2137 /*2138 * release semaphore.2139 */2140 readl(ioc->ioc_regs.ioc_init_sem_reg);2141 writel(1, ioc->ioc_regs.ioc_init_sem_reg);2142 bfa_trc(ioc, pgnum);2143 return BFA_STATUS_OK;2144}2145 2146static void2147bfa_ioc_fail_notify(struct bfa_ioc_s *ioc)2148{2149 struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;2150 2151 /*2152 * Notify driver and common modules registered for notification.2153 */2154 ioc->cbfn->hbfail_cbfn(ioc->bfa);2155 bfa_ioc_event_notify(ioc, BFA_IOC_E_FAILED);2156 2157 bfa_ioc_debug_save_ftrc(ioc);2158 2159 BFA_LOG(KERN_CRIT, bfad, bfa_log_level,2160 "Heart Beat of IOC has failed\n");2161 bfa_ioc_aen_post(ioc, BFA_IOC_AEN_HBFAIL);2162 2163}2164 2165static void2166bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc)2167{2168 struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;2169 /*2170 * Provide enable completion callback.2171 */2172 ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);2173 BFA_LOG(KERN_WARNING, bfad, bfa_log_level,2174 "Running firmware version is incompatible "2175 "with the driver version\n");2176 bfa_ioc_aen_post(ioc, BFA_IOC_AEN_FWMISMATCH);2177}2178 2179bfa_status_t2180bfa_ioc_pll_init(struct bfa_ioc_s *ioc)2181{2182 2183 /*2184 * Hold semaphore so that nobody can access the chip during init.2185 */2186 bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg);2187 2188 bfa_ioc_pll_init_asic(ioc);2189 2190 ioc->pllinit = BFA_TRUE;2191 2192 /*2193 * Initialize LMEM2194 */2195 bfa_ioc_lmem_init(ioc);2196 2197 /*2198 * release semaphore.2199 */2200 readl(ioc->ioc_regs.ioc_init_sem_reg);2201 writel(1, ioc->ioc_regs.ioc_init_sem_reg);2202 2203 return BFA_STATUS_OK;2204}2205 2206/*2207 * Interface used by diag module to do firmware boot with memory test2208 * as the entry vector.2209 */2210bfa_status_t2211bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_env)2212{2213 struct bfi_ioc_image_hdr_s *drv_fwhdr;2214 bfa_status_t status;2215 bfa_ioc_stats(ioc, ioc_boots);2216 2217 if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK)2218 return BFA_STATUS_FAILED;2219 2220 if (boot_env == BFI_FWBOOT_ENV_OS &&2221 boot_type == BFI_FWBOOT_TYPE_NORMAL) {2222 2223 drv_fwhdr = (struct bfi_ioc_image_hdr_s *)2224 bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0);2225 2226 /*2227 * Work with Flash iff flash f/w is better than driver f/w.2228 * Otherwise push drivers firmware.2229 */2230 if (bfa_ioc_flash_fwver_cmp(ioc, drv_fwhdr) ==2231 BFI_IOC_IMG_VER_BETTER)2232 boot_type = BFI_FWBOOT_TYPE_FLASH;2233 }2234 2235 /*2236 * Initialize IOC state of all functions on a chip reset.2237 */2238 if (boot_type == BFI_FWBOOT_TYPE_MEMTEST) {2239 bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_MEMTEST);2240 bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_MEMTEST);2241 } else {2242 bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_INITING);2243 bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_INITING);2244 }2245 2246 bfa_ioc_msgflush(ioc);2247 status = bfa_ioc_download_fw(ioc, boot_type, boot_env);2248 if (status == BFA_STATUS_OK)2249 bfa_ioc_lpu_start(ioc);2250 else {2251 WARN_ON(boot_type == BFI_FWBOOT_TYPE_MEMTEST);2252 bfa_iocpf_timeout(ioc);2253 }2254 return status;2255}2256 2257/*2258 * Enable/disable IOC failure auto recovery.2259 */2260void2261bfa_ioc_auto_recover(bfa_boolean_t auto_recover)2262{2263 bfa_auto_recover = auto_recover;2264}2265 2266 2267 2268bfa_boolean_t2269bfa_ioc_is_operational(struct bfa_ioc_s *ioc)2270{2271 return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op);2272}2273 2274bfa_boolean_t2275bfa_ioc_is_initialized(struct bfa_ioc_s *ioc)2276{2277 u32 r32 = bfa_ioc_get_cur_ioc_fwstate(ioc);2278 2279 return ((r32 != BFI_IOC_UNINIT) &&2280 (r32 != BFI_IOC_INITING) &&2281 (r32 != BFI_IOC_MEMTEST));2282}2283 2284bfa_boolean_t2285bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg)2286{2287 __be32 *msgp = mbmsg;2288 u32 r32;2289 int i;2290 2291 r32 = readl(ioc->ioc_regs.lpu_mbox_cmd);2292 if ((r32 & 1) == 0)2293 return BFA_FALSE;2294 2295 /*2296 * read the MBOX msg2297 */2298 for (i = 0; i < (sizeof(union bfi_ioc_i2h_msg_u) / sizeof(u32));2299 i++) {2300 r32 = readl(ioc->ioc_regs.lpu_mbox +2301 i * sizeof(u32));2302 msgp[i] = cpu_to_be32(r32);2303 }2304 2305 /*2306 * turn off mailbox interrupt by clearing mailbox status2307 */2308 writel(1, ioc->ioc_regs.lpu_mbox_cmd);2309 readl(ioc->ioc_regs.lpu_mbox_cmd);2310 2311 return BFA_TRUE;2312}2313 2314void2315bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m)2316{2317 union bfi_ioc_i2h_msg_u *msg;2318 struct bfa_iocpf_s *iocpf = &ioc->iocpf;2319 2320 msg = (union bfi_ioc_i2h_msg_u *) m;2321 2322 bfa_ioc_stats(ioc, ioc_isrs);2323 2324 switch (msg->mh.msg_id) {2325 case BFI_IOC_I2H_HBEAT:2326 break;2327 2328 case BFI_IOC_I2H_ENABLE_REPLY:2329 ioc->port_mode = ioc->port_mode_cfg =2330 (enum bfa_mode_s)msg->fw_event.port_mode;2331 ioc->ad_cap_bm = msg->fw_event.cap_bm;2332 bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_ENABLE);2333 break;2334 2335 case BFI_IOC_I2H_DISABLE_REPLY:2336 bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_DISABLE);2337 break;2338 2339 case BFI_IOC_I2H_GETATTR_REPLY:2340 bfa_ioc_getattr_reply(ioc);2341 break;2342 2343 default:2344 bfa_trc(ioc, msg->mh.msg_id);2345 WARN_ON(1);2346 }2347}2348 2349/*2350 * IOC attach time initialization and setup.2351 *2352 * @param[in] ioc memory for IOC2353 * @param[in] bfa driver instance structure2354 */2355void2356bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn,2357 struct bfa_timer_mod_s *timer_mod)2358{2359 ioc->bfa = bfa;2360 ioc->cbfn = cbfn;2361 ioc->timer_mod = timer_mod;2362 ioc->fcmode = BFA_FALSE;2363 ioc->pllinit = BFA_FALSE;2364 ioc->dbg_fwsave_once = BFA_TRUE;2365 ioc->iocpf.ioc = ioc;2366 2367 bfa_ioc_mbox_attach(ioc);2368 INIT_LIST_HEAD(&ioc->notify_q);2369 2370 bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit);2371 bfa_fsm_send_event(ioc, IOC_E_RESET);2372}2373 2374/*2375 * Driver detach time IOC cleanup.2376 */2377void2378bfa_ioc_detach(struct bfa_ioc_s *ioc)2379{2380 bfa_fsm_send_event(ioc, IOC_E_DETACH);2381 INIT_LIST_HEAD(&ioc->notify_q);2382}2383 2384/*2385 * Setup IOC PCI properties.2386 *2387 * @param[in] pcidev PCI device information for this IOC2388 */2389void2390bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,2391 enum bfi_pcifn_class clscode)2392{2393 ioc->clscode = clscode;2394 ioc->pcidev = *pcidev;2395 2396 /*2397 * Initialize IOC and device personality2398 */2399 ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_FC;2400 ioc->asic_mode = BFI_ASIC_MODE_FC;2401 2402 switch (pcidev->device_id) {2403 case BFA_PCI_DEVICE_ID_FC_8G1P:2404 case BFA_PCI_DEVICE_ID_FC_8G2P:2405 ioc->asic_gen = BFI_ASIC_GEN_CB;2406 ioc->fcmode = BFA_TRUE;2407 ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA;2408 ioc->ad_cap_bm = BFA_CM_HBA;2409 break;2410 2411 case BFA_PCI_DEVICE_ID_CT:2412 ioc->asic_gen = BFI_ASIC_GEN_CT;2413 ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH;2414 ioc->asic_mode = BFI_ASIC_MODE_ETH;2415 ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_CNA;2416 ioc->ad_cap_bm = BFA_CM_CNA;2417 break;2418 2419 case BFA_PCI_DEVICE_ID_CT_FC:2420 ioc->asic_gen = BFI_ASIC_GEN_CT;2421 ioc->fcmode = BFA_TRUE;2422 ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA;2423 ioc->ad_cap_bm = BFA_CM_HBA;2424 break;2425 2426 case BFA_PCI_DEVICE_ID_CT2:2427 case BFA_PCI_DEVICE_ID_CT2_QUAD:2428 ioc->asic_gen = BFI_ASIC_GEN_CT2;2429 if (clscode == BFI_PCIFN_CLASS_FC &&2430 pcidev->ssid == BFA_PCI_CT2_SSID_FC) {2431 ioc->asic_mode = BFI_ASIC_MODE_FC16;2432 ioc->fcmode = BFA_TRUE;2433 ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA;2434 ioc->ad_cap_bm = BFA_CM_HBA;2435 } else {2436 ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH;2437 ioc->asic_mode = BFI_ASIC_MODE_ETH;2438 if (pcidev->ssid == BFA_PCI_CT2_SSID_FCoE) {2439 ioc->port_mode =2440 ioc->port_mode_cfg = BFA_MODE_CNA;2441 ioc->ad_cap_bm = BFA_CM_CNA;2442 } else {2443 ioc->port_mode =2444 ioc->port_mode_cfg = BFA_MODE_NIC;2445 ioc->ad_cap_bm = BFA_CM_NIC;2446 }2447 }2448 break;2449 2450 default:2451 WARN_ON(1);2452 }2453 2454 /*2455 * Set asic specific interfaces. See bfa_ioc_cb.c and bfa_ioc_ct.c2456 */2457 if (ioc->asic_gen == BFI_ASIC_GEN_CB)2458 bfa_ioc_set_cb_hwif(ioc);2459 else if (ioc->asic_gen == BFI_ASIC_GEN_CT)2460 bfa_ioc_set_ct_hwif(ioc);2461 else {2462 WARN_ON(ioc->asic_gen != BFI_ASIC_GEN_CT2);2463 bfa_ioc_set_ct2_hwif(ioc);2464 bfa_ioc_ct2_poweron(ioc);2465 }2466 2467 bfa_ioc_map_port(ioc);2468 bfa_ioc_reg_init(ioc);2469}2470 2471/*2472 * Initialize IOC dma memory2473 *2474 * @param[in] dm_kva kernel virtual address of IOC dma memory2475 * @param[in] dm_pa physical address of IOC dma memory2476 */2477void2478bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa)2479{2480 /*2481 * dma memory for firmware attribute2482 */2483 ioc->attr_dma.kva = dm_kva;2484 ioc->attr_dma.pa = dm_pa;2485 ioc->attr = (struct bfi_ioc_attr_s *) dm_kva;2486}2487 2488void2489bfa_ioc_enable(struct bfa_ioc_s *ioc)2490{2491 bfa_ioc_stats(ioc, ioc_enables);2492 ioc->dbg_fwsave_once = BFA_TRUE;2493 2494 bfa_fsm_send_event(ioc, IOC_E_ENABLE);2495}2496 2497void2498bfa_ioc_disable(struct bfa_ioc_s *ioc)2499{2500 bfa_ioc_stats(ioc, ioc_disables);2501 bfa_fsm_send_event(ioc, IOC_E_DISABLE);2502}2503 2504void2505bfa_ioc_suspend(struct bfa_ioc_s *ioc)2506{2507 ioc->dbg_fwsave_once = BFA_TRUE;2508 bfa_fsm_send_event(ioc, IOC_E_HWERROR);2509}2510 2511/*2512 * Initialize memory for saving firmware trace. Driver must initialize2513 * trace memory before call bfa_ioc_enable().2514 */2515void2516bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave)2517{2518 ioc->dbg_fwsave = dbg_fwsave;2519 ioc->dbg_fwsave_len = BFA_DBG_FWTRC_LEN;2520}2521 2522/*2523 * Register mailbox message handler functions2524 *2525 * @param[in] ioc IOC instance2526 * @param[in] mcfuncs message class handler functions2527 */2528void2529bfa_ioc_mbox_register(struct bfa_ioc_s *ioc, bfa_ioc_mbox_mcfunc_t *mcfuncs)2530{2531 struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;2532 int mc;2533 2534 for (mc = 0; mc < BFI_MC_MAX; mc++)2535 mod->mbhdlr[mc].cbfn = mcfuncs[mc];2536}2537 2538/*2539 * Register mailbox message handler function, to be called by common modules2540 */2541void2542bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,2543 bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg)2544{2545 struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;2546 2547 mod->mbhdlr[mc].cbfn = cbfn;2548 mod->mbhdlr[mc].cbarg = cbarg;2549}2550 2551/*2552 * Queue a mailbox command request to firmware. Waits if mailbox is busy.2553 * Responsibility of caller to serialize2554 *2555 * @param[in] ioc IOC instance2556 * @param[i] cmd Mailbox command2557 */2558void2559bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd)2560{2561 struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;2562 u32 stat;2563 2564 /*2565 * If a previous command is pending, queue new command2566 */2567 if (!list_empty(&mod->cmd_q)) {2568 list_add_tail(&cmd->qe, &mod->cmd_q);2569 return;2570 }2571 2572 /*2573 * If mailbox is busy, queue command for poll timer2574 */2575 stat = readl(ioc->ioc_regs.hfn_mbox_cmd);2576 if (stat) {2577 list_add_tail(&cmd->qe, &mod->cmd_q);2578 return;2579 }2580 2581 /*2582 * mailbox is free -- queue command to firmware2583 */2584 bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));2585}2586 2587/*2588 * Handle mailbox interrupts2589 */2590void2591bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc)2592{2593 struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;2594 struct bfi_mbmsg_s m;2595 int mc;2596 2597 if (bfa_ioc_msgget(ioc, &m)) {2598 /*2599 * Treat IOC message class as special.2600 */2601 mc = m.mh.msg_class;2602 if (mc == BFI_MC_IOC) {2603 bfa_ioc_isr(ioc, &m);2604 return;2605 }2606 2607 if ((mc >= BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL))2608 return;2609 2610 mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m);2611 }2612 2613 bfa_ioc_lpu_read_stat(ioc);2614 2615 /*2616 * Try to send pending mailbox commands2617 */2618 bfa_ioc_mbox_poll(ioc);2619}2620 2621void2622bfa_ioc_error_isr(struct bfa_ioc_s *ioc)2623{2624 bfa_ioc_stats(ioc, ioc_hbfails);2625 ioc->stats.hb_count = ioc->hb_count;2626 bfa_fsm_send_event(ioc, IOC_E_HWERROR);2627}2628 2629/*2630 * return true if IOC is disabled2631 */2632bfa_boolean_t2633bfa_ioc_is_disabled(struct bfa_ioc_s *ioc)2634{2635 return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling) ||2636 bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled);2637}2638 2639/*2640 * return true if IOC firmware is different.2641 */2642bfa_boolean_t2643bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc)2644{2645 return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_reset) ||2646 bfa_fsm_cmp_state(&ioc->iocpf, bfa_iocpf_sm_fwcheck) ||2647 bfa_fsm_cmp_state(&ioc->iocpf, bfa_iocpf_sm_mismatch);2648}2649 2650/*2651 * Check if adapter is disabled -- both IOCs should be in a disabled2652 * state.2653 */2654bfa_boolean_t2655bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc)2656{2657 u32 ioc_state;2658 2659 if (!bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled))2660 return BFA_FALSE;2661 2662 ioc_state = bfa_ioc_get_cur_ioc_fwstate(ioc);2663 if (!bfa_ioc_state_disabled(ioc_state))2664 return BFA_FALSE;2665 2666 if (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_FC_8G1P) {2667 ioc_state = bfa_ioc_get_cur_ioc_fwstate(ioc);2668 if (!bfa_ioc_state_disabled(ioc_state))2669 return BFA_FALSE;2670 }2671 2672 return BFA_TRUE;2673}2674 2675/*2676 * Reset IOC fwstate registers.2677 */2678void2679bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc)2680{2681 bfa_ioc_set_cur_ioc_fwstate(ioc, BFI_IOC_UNINIT);2682 bfa_ioc_set_alt_ioc_fwstate(ioc, BFI_IOC_UNINIT);2683}2684 2685#define BFA_MFG_NAME "QLogic"2686void2687bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,2688 struct bfa_adapter_attr_s *ad_attr)2689{2690 struct bfi_ioc_attr_s *ioc_attr;2691 2692 ioc_attr = ioc->attr;2693 2694 bfa_ioc_get_adapter_serial_num(ioc, ad_attr->serial_num);2695 bfa_ioc_get_adapter_fw_ver(ioc, ad_attr->fw_ver);2696 bfa_ioc_get_adapter_optrom_ver(ioc, ad_attr->optrom_ver);2697 bfa_ioc_get_adapter_manufacturer(ioc, ad_attr->manufacturer);2698 memcpy(&ad_attr->vpd, &ioc_attr->vpd,2699 sizeof(struct bfa_mfg_vpd_s));2700 2701 ad_attr->nports = bfa_ioc_get_nports(ioc);2702 ad_attr->max_speed = bfa_ioc_speed_sup(ioc);2703 2704 bfa_ioc_get_adapter_model(ioc, ad_attr->model);2705 /* For now, model descr uses same model string */2706 bfa_ioc_get_adapter_model(ioc, ad_attr->model_descr);2707 2708 ad_attr->card_type = ioc_attr->card_type;2709 ad_attr->is_mezz = bfa_mfg_is_mezz(ioc_attr->card_type);2710 2711 if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop))2712 ad_attr->prototype = 1;2713 else2714 ad_attr->prototype = 0;2715 2716 ad_attr->pwwn = ioc->attr->pwwn;2717 ad_attr->mac = bfa_ioc_get_mac(ioc);2718 2719 ad_attr->pcie_gen = ioc_attr->pcie_gen;2720 ad_attr->pcie_lanes = ioc_attr->pcie_lanes;2721 ad_attr->pcie_lanes_orig = ioc_attr->pcie_lanes_orig;2722 ad_attr->asic_rev = ioc_attr->asic_rev;2723 2724 bfa_ioc_get_pci_chip_rev(ioc, ad_attr->hw_ver);2725 2726 ad_attr->cna_capable = bfa_ioc_is_cna(ioc);2727 ad_attr->trunk_capable = (ad_attr->nports > 1) &&2728 !bfa_ioc_is_cna(ioc) && !ad_attr->is_mezz;2729 ad_attr->mfg_day = ioc_attr->mfg_day;2730 ad_attr->mfg_month = ioc_attr->mfg_month;2731 ad_attr->mfg_year = ioc_attr->mfg_year;2732 memcpy(ad_attr->uuid, ioc_attr->uuid, BFA_ADAPTER_UUID_LEN);2733}2734 2735enum bfa_ioc_type_e2736bfa_ioc_get_type(struct bfa_ioc_s *ioc)2737{2738 if (ioc->clscode == BFI_PCIFN_CLASS_ETH)2739 return BFA_IOC_TYPE_LL;2740 2741 WARN_ON(ioc->clscode != BFI_PCIFN_CLASS_FC);2742 2743 return (ioc->attr->port_mode == BFI_PORT_MODE_FC)2744 ? BFA_IOC_TYPE_FC : BFA_IOC_TYPE_FCoE;2745}2746 2747void2748bfa_ioc_get_adapter_serial_num(struct bfa_ioc_s *ioc, char *serial_num)2749{2750 memset((void *)serial_num, 0, BFA_ADAPTER_SERIAL_NUM_LEN);2751 memcpy((void *)serial_num,2752 (void *)ioc->attr->brcd_serialnum,2753 BFA_ADAPTER_SERIAL_NUM_LEN);2754}2755 2756void2757bfa_ioc_get_adapter_fw_ver(struct bfa_ioc_s *ioc, char *fw_ver)2758{2759 memset((void *)fw_ver, 0, BFA_VERSION_LEN);2760 memcpy(fw_ver, ioc->attr->fw_version, BFA_VERSION_LEN);2761}2762 2763void2764bfa_ioc_get_pci_chip_rev(struct bfa_ioc_s *ioc, char *chip_rev)2765{2766 WARN_ON(!chip_rev);2767 2768 memset((void *)chip_rev, 0, BFA_IOC_CHIP_REV_LEN);2769 2770 chip_rev[0] = 'R';2771 chip_rev[1] = 'e';2772 chip_rev[2] = 'v';2773 chip_rev[3] = '-';2774 chip_rev[4] = ioc->attr->asic_rev;2775 chip_rev[5] = '\0';2776}2777 2778void2779bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc_s *ioc, char *optrom_ver)2780{2781 memset((void *)optrom_ver, 0, BFA_VERSION_LEN);2782 memcpy(optrom_ver, ioc->attr->optrom_version,2783 BFA_VERSION_LEN);2784}2785 2786void2787bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, char *manufacturer)2788{2789 memset((void *)manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN);2790 strscpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);2791}2792 2793void2794bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model)2795{2796 struct bfi_ioc_attr_s *ioc_attr;2797 u8 nports = bfa_ioc_get_nports(ioc);2798 2799 WARN_ON(!model);2800 memset((void *)model, 0, BFA_ADAPTER_MODEL_NAME_LEN);2801 2802 ioc_attr = ioc->attr;2803 2804 if (bfa_asic_id_ct2(ioc->pcidev.device_id) &&2805 (!bfa_mfg_is_mezz(ioc_attr->card_type)))2806 snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u-%u%s",2807 BFA_MFG_NAME, ioc_attr->card_type, nports, "p");2808 else2809 snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u",2810 BFA_MFG_NAME, ioc_attr->card_type);2811}2812 2813enum bfa_ioc_state2814bfa_ioc_get_state(struct bfa_ioc_s *ioc)2815{2816 enum bfa_iocpf_state iocpf_st;2817 enum bfa_ioc_state ioc_st = bfa_ioc_sm_to_state(ioc_sm_table, ioc->fsm);2818 2819 if (ioc_st == BFA_IOC_ENABLING ||2820 ioc_st == BFA_IOC_FAIL || ioc_st == BFA_IOC_INITFAIL) {2821 2822 iocpf_st = bfa_iocpf_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm);2823 2824 switch (iocpf_st) {2825 case BFA_IOCPF_SEMWAIT:2826 ioc_st = BFA_IOC_SEMWAIT;2827 break;2828 2829 case BFA_IOCPF_HWINIT:2830 ioc_st = BFA_IOC_HWINIT;2831 break;2832 2833 case BFA_IOCPF_FWMISMATCH:2834 ioc_st = BFA_IOC_FWMISMATCH;2835 break;2836 2837 case BFA_IOCPF_FAIL:2838 ioc_st = BFA_IOC_FAIL;2839 break;2840 2841 case BFA_IOCPF_INITFAIL:2842 ioc_st = BFA_IOC_INITFAIL;2843 break;2844 2845 default:2846 break;2847 }2848 }2849 2850 return ioc_st;2851}2852 2853void2854bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr)2855{2856 memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr_s));2857 2858 ioc_attr->state = bfa_ioc_get_state(ioc);2859 ioc_attr->port_id = bfa_ioc_portid(ioc);2860 ioc_attr->port_mode = ioc->port_mode;2861 ioc_attr->port_mode_cfg = ioc->port_mode_cfg;2862 ioc_attr->cap_bm = ioc->ad_cap_bm;2863 2864 ioc_attr->ioc_type = bfa_ioc_get_type(ioc);2865 2866 bfa_ioc_get_adapter_attr(ioc, &ioc_attr->adapter_attr);2867 2868 ioc_attr->pci_attr.device_id = bfa_ioc_devid(ioc);2869 ioc_attr->pci_attr.pcifn = bfa_ioc_pcifn(ioc);2870 ioc_attr->def_fn = (bfa_ioc_pcifn(ioc) == bfa_ioc_portid(ioc));2871 bfa_ioc_get_pci_chip_rev(ioc, ioc_attr->pci_attr.chip_rev);2872}2873 2874mac_t2875bfa_ioc_get_mac(struct bfa_ioc_s *ioc)2876{2877 /*2878 * Check the IOC type and return the appropriate MAC2879 */2880 if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_FCoE)2881 return ioc->attr->fcoe_mac;2882 else2883 return ioc->attr->mac;2884}2885 2886mac_t2887bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc)2888{2889 mac_t m;2890 2891 m = ioc->attr->mfg_mac;2892 if (bfa_mfg_is_old_wwn_mac_model(ioc->attr->card_type))2893 m.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc);2894 else2895 bfa_mfg_increment_wwn_mac(&(m.mac[MAC_ADDRLEN-3]),2896 bfa_ioc_pcifn(ioc));2897 2898 return m;2899}2900 2901/*2902 * Send AEN notification2903 */2904void2905bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)2906{2907 struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;2908 struct bfa_aen_entry_s *aen_entry;2909 enum bfa_ioc_type_e ioc_type;2910 2911 bfad_get_aen_entry(bfad, aen_entry);2912 if (!aen_entry)2913 return;2914 2915 ioc_type = bfa_ioc_get_type(ioc);2916 switch (ioc_type) {2917 case BFA_IOC_TYPE_FC:2918 aen_entry->aen_data.ioc.pwwn = ioc->attr->pwwn;2919 break;2920 case BFA_IOC_TYPE_FCoE:2921 aen_entry->aen_data.ioc.pwwn = ioc->attr->pwwn;2922 aen_entry->aen_data.ioc.mac = bfa_ioc_get_mac(ioc);2923 break;2924 case BFA_IOC_TYPE_LL:2925 aen_entry->aen_data.ioc.mac = bfa_ioc_get_mac(ioc);2926 break;2927 default:2928 WARN_ON(ioc_type != BFA_IOC_TYPE_FC);2929 break;2930 }2931 2932 /* Send the AEN notification */2933 aen_entry->aen_data.ioc.ioc_type = ioc_type;2934 bfad_im_post_vendor_event(aen_entry, bfad, ++ioc->ioc_aen_seq,2935 BFA_AEN_CAT_IOC, event);2936}2937 2938/*2939 * Retrieve saved firmware trace from a prior IOC failure.2940 */2941bfa_status_t2942bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata, int *trclen)2943{2944 int tlen;2945 2946 if (ioc->dbg_fwsave_len == 0)2947 return BFA_STATUS_ENOFSAVE;2948 2949 tlen = *trclen;2950 if (tlen > ioc->dbg_fwsave_len)2951 tlen = ioc->dbg_fwsave_len;2952 2953 memcpy(trcdata, ioc->dbg_fwsave, tlen);2954 *trclen = tlen;2955 return BFA_STATUS_OK;2956}2957 2958 2959/*2960 * Retrieve saved firmware trace from a prior IOC failure.2961 */2962bfa_status_t2963bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, int *trclen)2964{2965 u32 loff = BFA_DBG_FWTRC_OFF(bfa_ioc_portid(ioc));2966 int tlen;2967 bfa_status_t status;2968 2969 bfa_trc(ioc, *trclen);2970 2971 tlen = *trclen;2972 if (tlen > BFA_DBG_FWTRC_LEN)2973 tlen = BFA_DBG_FWTRC_LEN;2974 2975 status = bfa_ioc_smem_read(ioc, trcdata, loff, tlen);2976 *trclen = tlen;2977 return status;2978}2979 2980static void2981bfa_ioc_send_fwsync(struct bfa_ioc_s *ioc)2982{2983 struct bfa_mbox_cmd_s cmd;2984 struct bfi_ioc_ctrl_req_s *req = (struct bfi_ioc_ctrl_req_s *) cmd.msg;2985 2986 bfi_h2i_set(req->mh, BFI_MC_IOC, BFI_IOC_H2I_DBG_SYNC,2987 bfa_ioc_portid(ioc));2988 req->clscode = cpu_to_be16(ioc->clscode);2989 bfa_ioc_mbox_queue(ioc, &cmd);2990}2991 2992static void2993bfa_ioc_fwsync(struct bfa_ioc_s *ioc)2994{2995 u32 fwsync_iter = 1000;2996 2997 bfa_ioc_send_fwsync(ioc);2998 2999 /*3000 * After sending a fw sync mbox command wait for it to3001 * take effect. We will not wait for a response because3002 * 1. fw_sync mbox cmd doesn't have a response.3003 * 2. Even if we implement that, interrupts might not3004 * be enabled when we call this function.3005 * So, just keep checking if any mbox cmd is pending, and3006 * after waiting for a reasonable amount of time, go ahead.3007 * It is possible that fw has crashed and the mbox command3008 * is never acknowledged.3009 */3010 while (bfa_ioc_mbox_cmd_pending(ioc) && fwsync_iter > 0)3011 fwsync_iter--;3012}3013 3014/*3015 * Dump firmware smem3016 */3017bfa_status_t3018bfa_ioc_debug_fwcore(struct bfa_ioc_s *ioc, void *buf,3019 u32 *offset, int *buflen)3020{3021 u32 loff;3022 int dlen;3023 bfa_status_t status;3024 u32 smem_len = BFA_IOC_FW_SMEM_SIZE(ioc);3025 3026 if (*offset >= smem_len) {3027 *offset = *buflen = 0;3028 return BFA_STATUS_EINVAL;3029 }3030 3031 loff = *offset;3032 dlen = *buflen;3033 3034 /*3035 * First smem read, sync smem before proceeding3036 * No need to sync before reading every chunk.3037 */3038 if (loff == 0)3039 bfa_ioc_fwsync(ioc);3040 3041 if ((loff + dlen) >= smem_len)3042 dlen = smem_len - loff;3043 3044 status = bfa_ioc_smem_read(ioc, buf, loff, dlen);3045 3046 if (status != BFA_STATUS_OK) {3047 *offset = *buflen = 0;3048 return status;3049 }3050 3051 *offset += dlen;3052 3053 if (*offset >= smem_len)3054 *offset = 0;3055 3056 *buflen = dlen;3057 3058 return status;3059}3060 3061/*3062 * Firmware statistics3063 */3064bfa_status_t3065bfa_ioc_fw_stats_get(struct bfa_ioc_s *ioc, void *stats)3066{3067 u32 loff = BFI_IOC_FWSTATS_OFF + \3068 BFI_IOC_FWSTATS_SZ * (bfa_ioc_portid(ioc));3069 int tlen;3070 bfa_status_t status;3071 3072 if (ioc->stats_busy) {3073 bfa_trc(ioc, ioc->stats_busy);3074 return BFA_STATUS_DEVBUSY;3075 }3076 ioc->stats_busy = BFA_TRUE;3077 3078 tlen = sizeof(struct bfa_fw_stats_s);3079 status = bfa_ioc_smem_read(ioc, stats, loff, tlen);3080 3081 ioc->stats_busy = BFA_FALSE;3082 return status;3083}3084 3085bfa_status_t3086bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc)3087{3088 u32 loff = BFI_IOC_FWSTATS_OFF + \3089 BFI_IOC_FWSTATS_SZ * (bfa_ioc_portid(ioc));3090 int tlen;3091 bfa_status_t status;3092 3093 if (ioc->stats_busy) {3094 bfa_trc(ioc, ioc->stats_busy);3095 return BFA_STATUS_DEVBUSY;3096 }3097 ioc->stats_busy = BFA_TRUE;3098 3099 tlen = sizeof(struct bfa_fw_stats_s);3100 status = bfa_ioc_smem_clr(ioc, loff, tlen);3101 3102 ioc->stats_busy = BFA_FALSE;3103 return status;3104}3105 3106/*3107 * Save firmware trace if configured.3108 */3109void3110bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc)3111{3112 int tlen;3113 3114 if (ioc->dbg_fwsave_once) {3115 ioc->dbg_fwsave_once = BFA_FALSE;3116 if (ioc->dbg_fwsave_len) {3117 tlen = ioc->dbg_fwsave_len;3118 bfa_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen);3119 }3120 }3121}3122 3123/*3124 * Firmware failure detected. Start recovery actions.3125 */3126static void3127bfa_ioc_recover(struct bfa_ioc_s *ioc)3128{3129 bfa_ioc_stats(ioc, ioc_hbfails);3130 ioc->stats.hb_count = ioc->hb_count;3131 bfa_fsm_send_event(ioc, IOC_E_HBFAIL);3132}3133 3134/*3135 * BFA IOC PF private functions3136 */3137static void3138bfa_iocpf_timeout(void *ioc_arg)3139{3140 struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg;3141 3142 bfa_trc(ioc, 0);3143 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT);3144}3145 3146static void3147bfa_iocpf_sem_timeout(void *ioc_arg)3148{3149 struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg;3150 3151 bfa_ioc_hw_sem_get(ioc);3152}3153 3154static void3155bfa_ioc_poll_fwinit(struct bfa_ioc_s *ioc)3156{3157 u32 fwstate = bfa_ioc_get_cur_ioc_fwstate(ioc);3158 3159 bfa_trc(ioc, fwstate);3160 3161 if (fwstate == BFI_IOC_DISABLED) {3162 bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY);3163 return;3164 }3165 3166 if (ioc->iocpf.poll_time >= (3 * BFA_IOC_TOV))3167 bfa_iocpf_timeout(ioc);3168 else {3169 ioc->iocpf.poll_time += BFA_IOC_POLL_TOV;3170 bfa_iocpf_poll_timer_start(ioc);3171 }3172}3173 3174static void3175bfa_iocpf_poll_timeout(void *ioc_arg)3176{3177 struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg;3178 3179 bfa_ioc_poll_fwinit(ioc);3180}3181 3182/*3183 * bfa timer function3184 */3185void3186bfa_timer_beat(struct bfa_timer_mod_s *mod)3187{3188 struct list_head *qh = &mod->timer_q;3189 struct list_head *qe, *qe_next;3190 struct bfa_timer_s *elem;3191 struct list_head timedout_q;3192 3193 INIT_LIST_HEAD(&timedout_q);3194 3195 qe = bfa_q_next(qh);3196 3197 while (qe != qh) {3198 qe_next = bfa_q_next(qe);3199 3200 elem = (struct bfa_timer_s *) qe;3201 if (elem->timeout <= BFA_TIMER_FREQ) {3202 elem->timeout = 0;3203 list_del(&elem->qe);3204 list_add_tail(&elem->qe, &timedout_q);3205 } else {3206 elem->timeout -= BFA_TIMER_FREQ;3207 }3208 3209 qe = qe_next; /* go to next elem */3210 }3211 3212 /*3213 * Pop all the timeout entries3214 */3215 while (!list_empty(&timedout_q)) {3216 bfa_q_deq(&timedout_q, &elem);3217 elem->timercb(elem->arg);3218 }3219}3220 3221/*3222 * Should be called with lock protection3223 */3224void3225bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer,3226 void (*timercb) (void *), void *arg, unsigned int timeout)3227{3228 3229 WARN_ON(timercb == NULL);3230 WARN_ON(bfa_q_is_on_q(&mod->timer_q, timer));3231 3232 timer->timeout = timeout;3233 timer->timercb = timercb;3234 timer->arg = arg;3235 3236 list_add_tail(&timer->qe, &mod->timer_q);3237}3238 3239/*3240 * Should be called with lock protection3241 */3242void3243bfa_timer_stop(struct bfa_timer_s *timer)3244{3245 WARN_ON(list_empty(&timer->qe));3246 3247 list_del(&timer->qe);3248}3249 3250/*3251 * ASIC block related3252 */3253static void3254bfa_ablk_config_swap(struct bfa_ablk_cfg_s *cfg)3255{3256 struct bfa_ablk_cfg_inst_s *cfg_inst;3257 int i, j;3258 u16 be16;3259 3260 for (i = 0; i < BFA_ABLK_MAX; i++) {3261 cfg_inst = &cfg->inst[i];3262 for (j = 0; j < BFA_ABLK_MAX_PFS; j++) {3263 be16 = cfg_inst->pf_cfg[j].pers;3264 cfg_inst->pf_cfg[j].pers = be16_to_cpu(be16);3265 be16 = cfg_inst->pf_cfg[j].num_qpairs;3266 cfg_inst->pf_cfg[j].num_qpairs = be16_to_cpu(be16);3267 be16 = cfg_inst->pf_cfg[j].num_vectors;3268 cfg_inst->pf_cfg[j].num_vectors = be16_to_cpu(be16);3269 be16 = cfg_inst->pf_cfg[j].bw_min;3270 cfg_inst->pf_cfg[j].bw_min = be16_to_cpu(be16);3271 be16 = cfg_inst->pf_cfg[j].bw_max;3272 cfg_inst->pf_cfg[j].bw_max = be16_to_cpu(be16);3273 }3274 }3275}3276 3277static void3278bfa_ablk_isr(void *cbarg, struct bfi_mbmsg_s *msg)3279{3280 struct bfa_ablk_s *ablk = (struct bfa_ablk_s *)cbarg;3281 struct bfi_ablk_i2h_rsp_s *rsp = (struct bfi_ablk_i2h_rsp_s *)msg;3282 bfa_ablk_cbfn_t cbfn;3283 3284 WARN_ON(msg->mh.msg_class != BFI_MC_ABLK);3285 bfa_trc(ablk->ioc, msg->mh.msg_id);3286 3287 switch (msg->mh.msg_id) {3288 case BFI_ABLK_I2H_QUERY:3289 if (rsp->status == BFA_STATUS_OK) {3290 memcpy(ablk->cfg, ablk->dma_addr.kva,3291 sizeof(struct bfa_ablk_cfg_s));3292 bfa_ablk_config_swap(ablk->cfg);3293 ablk->cfg = NULL;3294 }3295 break;3296 3297 case BFI_ABLK_I2H_ADPT_CONFIG:3298 case BFI_ABLK_I2H_PORT_CONFIG:3299 /* update config port mode */3300 ablk->ioc->port_mode_cfg = rsp->port_mode;3301 break;3302 3303 case BFI_ABLK_I2H_PF_DELETE:3304 case BFI_ABLK_I2H_PF_UPDATE:3305 case BFI_ABLK_I2H_OPTROM_ENABLE:3306 case BFI_ABLK_I2H_OPTROM_DISABLE:3307 /* No-op */3308 break;3309 3310 case BFI_ABLK_I2H_PF_CREATE:3311 *(ablk->pcifn) = rsp->pcifn;3312 ablk->pcifn = NULL;3313 break;3314 3315 default:3316 WARN_ON(1);3317 }3318 3319 ablk->busy = BFA_FALSE;3320 if (ablk->cbfn) {3321 cbfn = ablk->cbfn;3322 ablk->cbfn = NULL;3323 cbfn(ablk->cbarg, rsp->status);3324 }3325}3326 3327static void3328bfa_ablk_notify(void *cbarg, enum bfa_ioc_event_e event)3329{3330 struct bfa_ablk_s *ablk = (struct bfa_ablk_s *)cbarg;3331 3332 bfa_trc(ablk->ioc, event);3333 3334 switch (event) {3335 case BFA_IOC_E_ENABLED:3336 WARN_ON(ablk->busy != BFA_FALSE);3337 break;3338 3339 case BFA_IOC_E_DISABLED:3340 case BFA_IOC_E_FAILED:3341 /* Fail any pending requests */3342 ablk->pcifn = NULL;3343 if (ablk->busy) {3344 if (ablk->cbfn)3345 ablk->cbfn(ablk->cbarg, BFA_STATUS_FAILED);3346 ablk->cbfn = NULL;3347 ablk->busy = BFA_FALSE;3348 }3349 break;3350 3351 default:3352 WARN_ON(1);3353 break;3354 }3355}3356 3357u323358bfa_ablk_meminfo(void)3359{3360 return BFA_ROUNDUP(sizeof(struct bfa_ablk_cfg_s), BFA_DMA_ALIGN_SZ);3361}3362 3363void3364bfa_ablk_memclaim(struct bfa_ablk_s *ablk, u8 *dma_kva, u64 dma_pa)3365{3366 ablk->dma_addr.kva = dma_kva;3367 ablk->dma_addr.pa = dma_pa;3368}3369 3370void3371bfa_ablk_attach(struct bfa_ablk_s *ablk, struct bfa_ioc_s *ioc)3372{3373 ablk->ioc = ioc;3374 3375 bfa_ioc_mbox_regisr(ablk->ioc, BFI_MC_ABLK, bfa_ablk_isr, ablk);3376 bfa_q_qe_init(&ablk->ioc_notify);3377 bfa_ioc_notify_init(&ablk->ioc_notify, bfa_ablk_notify, ablk);3378 list_add_tail(&ablk->ioc_notify.qe, &ablk->ioc->notify_q);3379}3380 3381bfa_status_t3382bfa_ablk_query(struct bfa_ablk_s *ablk, struct bfa_ablk_cfg_s *ablk_cfg,3383 bfa_ablk_cbfn_t cbfn, void *cbarg)3384{3385 struct bfi_ablk_h2i_query_s *m;3386 3387 WARN_ON(!ablk_cfg);3388 3389 if (!bfa_ioc_is_operational(ablk->ioc)) {3390 bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE);3391 return BFA_STATUS_IOC_FAILURE;3392 }3393 3394 if (ablk->busy) {3395 bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY);3396 return BFA_STATUS_DEVBUSY;3397 }3398 3399 ablk->cfg = ablk_cfg;3400 ablk->cbfn = cbfn;3401 ablk->cbarg = cbarg;3402 ablk->busy = BFA_TRUE;3403 3404 m = (struct bfi_ablk_h2i_query_s *)ablk->mb.msg;3405 bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_QUERY,3406 bfa_ioc_portid(ablk->ioc));3407 bfa_dma_be_addr_set(m->addr, ablk->dma_addr.pa);3408 bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb);3409 3410 return BFA_STATUS_OK;3411}3412 3413bfa_status_t3414bfa_ablk_pf_create(struct bfa_ablk_s *ablk, u16 *pcifn,3415 u8 port, enum bfi_pcifn_class personality,3416 u16 bw_min, u16 bw_max,3417 bfa_ablk_cbfn_t cbfn, void *cbarg)3418{3419 struct bfi_ablk_h2i_pf_req_s *m;3420 3421 if (!bfa_ioc_is_operational(ablk->ioc)) {3422 bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE);3423 return BFA_STATUS_IOC_FAILURE;3424 }3425 3426 if (ablk->busy) {3427 bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY);3428 return BFA_STATUS_DEVBUSY;3429 }3430 3431 ablk->pcifn = pcifn;3432 ablk->cbfn = cbfn;3433 ablk->cbarg = cbarg;3434 ablk->busy = BFA_TRUE;3435 3436 m = (struct bfi_ablk_h2i_pf_req_s *)ablk->mb.msg;3437 bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_CREATE,3438 bfa_ioc_portid(ablk->ioc));3439 m->pers = cpu_to_be16((u16)personality);3440 m->bw_min = cpu_to_be16(bw_min);3441 m->bw_max = cpu_to_be16(bw_max);3442 m->port = port;3443 bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb);3444 3445 return BFA_STATUS_OK;3446}3447 3448bfa_status_t3449bfa_ablk_pf_delete(struct bfa_ablk_s *ablk, int pcifn,3450 bfa_ablk_cbfn_t cbfn, void *cbarg)3451{3452 struct bfi_ablk_h2i_pf_req_s *m;3453 3454 if (!bfa_ioc_is_operational(ablk->ioc)) {3455 bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE);3456 return BFA_STATUS_IOC_FAILURE;3457 }3458 3459 if (ablk->busy) {3460 bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY);3461 return BFA_STATUS_DEVBUSY;3462 }3463 3464 ablk->cbfn = cbfn;3465 ablk->cbarg = cbarg;3466 ablk->busy = BFA_TRUE;3467 3468 m = (struct bfi_ablk_h2i_pf_req_s *)ablk->mb.msg;3469 bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_DELETE,3470 bfa_ioc_portid(ablk->ioc));3471 m->pcifn = (u8)pcifn;3472 bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb);3473 3474 return BFA_STATUS_OK;3475}3476 3477bfa_status_t3478bfa_ablk_adapter_config(struct bfa_ablk_s *ablk, enum bfa_mode_s mode,3479 int max_pf, int max_vf, bfa_ablk_cbfn_t cbfn, void *cbarg)3480{3481 struct bfi_ablk_h2i_cfg_req_s *m;3482 3483 if (!bfa_ioc_is_operational(ablk->ioc)) {3484 bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE);3485 return BFA_STATUS_IOC_FAILURE;3486 }3487 3488 if (ablk->busy) {3489 bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY);3490 return BFA_STATUS_DEVBUSY;3491 }3492 3493 ablk->cbfn = cbfn;3494 ablk->cbarg = cbarg;3495 ablk->busy = BFA_TRUE;3496 3497 m = (struct bfi_ablk_h2i_cfg_req_s *)ablk->mb.msg;3498 bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_ADPT_CONFIG,3499 bfa_ioc_portid(ablk->ioc));3500 m->mode = (u8)mode;3501 m->max_pf = (u8)max_pf;3502 m->max_vf = (u8)max_vf;3503 bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb);3504 3505 return BFA_STATUS_OK;3506}3507 3508bfa_status_t3509bfa_ablk_port_config(struct bfa_ablk_s *ablk, int port, enum bfa_mode_s mode,3510 int max_pf, int max_vf, bfa_ablk_cbfn_t cbfn, void *cbarg)3511{3512 struct bfi_ablk_h2i_cfg_req_s *m;3513 3514 if (!bfa_ioc_is_operational(ablk->ioc)) {3515 bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE);3516 return BFA_STATUS_IOC_FAILURE;3517 }3518 3519 if (ablk->busy) {3520 bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY);3521 return BFA_STATUS_DEVBUSY;3522 }3523 3524 ablk->cbfn = cbfn;3525 ablk->cbarg = cbarg;3526 ablk->busy = BFA_TRUE;3527 3528 m = (struct bfi_ablk_h2i_cfg_req_s *)ablk->mb.msg;3529 bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PORT_CONFIG,3530 bfa_ioc_portid(ablk->ioc));3531 m->port = (u8)port;3532 m->mode = (u8)mode;3533 m->max_pf = (u8)max_pf;3534 m->max_vf = (u8)max_vf;3535 bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb);3536 3537 return BFA_STATUS_OK;3538}3539 3540bfa_status_t3541bfa_ablk_pf_update(struct bfa_ablk_s *ablk, int pcifn, u16 bw_min,3542 u16 bw_max, bfa_ablk_cbfn_t cbfn, void *cbarg)3543{3544 struct bfi_ablk_h2i_pf_req_s *m;3545 3546 if (!bfa_ioc_is_operational(ablk->ioc)) {3547 bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE);3548 return BFA_STATUS_IOC_FAILURE;3549 }3550 3551 if (ablk->busy) {3552 bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY);3553 return BFA_STATUS_DEVBUSY;3554 }3555 3556 ablk->cbfn = cbfn;3557 ablk->cbarg = cbarg;3558 ablk->busy = BFA_TRUE;3559 3560 m = (struct bfi_ablk_h2i_pf_req_s *)ablk->mb.msg;3561 bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_UPDATE,3562 bfa_ioc_portid(ablk->ioc));3563 m->pcifn = (u8)pcifn;3564 m->bw_min = cpu_to_be16(bw_min);3565 m->bw_max = cpu_to_be16(bw_max);3566 bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb);3567 3568 return BFA_STATUS_OK;3569}3570 3571bfa_status_t3572bfa_ablk_optrom_en(struct bfa_ablk_s *ablk, bfa_ablk_cbfn_t cbfn, void *cbarg)3573{3574 struct bfi_ablk_h2i_optrom_s *m;3575 3576 if (!bfa_ioc_is_operational(ablk->ioc)) {3577 bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE);3578 return BFA_STATUS_IOC_FAILURE;3579 }3580 3581 if (ablk->busy) {3582 bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY);3583 return BFA_STATUS_DEVBUSY;3584 }3585 3586 ablk->cbfn = cbfn;3587 ablk->cbarg = cbarg;3588 ablk->busy = BFA_TRUE;3589 3590 m = (struct bfi_ablk_h2i_optrom_s *)ablk->mb.msg;3591 bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_OPTROM_ENABLE,3592 bfa_ioc_portid(ablk->ioc));3593 bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb);3594 3595 return BFA_STATUS_OK;3596}3597 3598bfa_status_t3599bfa_ablk_optrom_dis(struct bfa_ablk_s *ablk, bfa_ablk_cbfn_t cbfn, void *cbarg)3600{3601 struct bfi_ablk_h2i_optrom_s *m;3602 3603 if (!bfa_ioc_is_operational(ablk->ioc)) {3604 bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE);3605 return BFA_STATUS_IOC_FAILURE;3606 }3607 3608 if (ablk->busy) {3609 bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY);3610 return BFA_STATUS_DEVBUSY;3611 }3612 3613 ablk->cbfn = cbfn;3614 ablk->cbarg = cbarg;3615 ablk->busy = BFA_TRUE;3616 3617 m = (struct bfi_ablk_h2i_optrom_s *)ablk->mb.msg;3618 bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_OPTROM_DISABLE,3619 bfa_ioc_portid(ablk->ioc));3620 bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb);3621 3622 return BFA_STATUS_OK;3623}3624 3625/*3626 * SFP module specific3627 */3628 3629/* forward declarations */3630static void bfa_sfp_getdata_send(struct bfa_sfp_s *sfp);3631static void bfa_sfp_media_get(struct bfa_sfp_s *sfp);3632static bfa_status_t bfa_sfp_speed_valid(struct bfa_sfp_s *sfp,3633 enum bfa_port_speed portspeed);3634 3635static void3636bfa_cb_sfp_show(struct bfa_sfp_s *sfp)3637{3638 bfa_trc(sfp, sfp->lock);3639 if (sfp->cbfn)3640 sfp->cbfn(sfp->cbarg, sfp->status);3641 sfp->lock = 0;3642 sfp->cbfn = NULL;3643}3644 3645static void3646bfa_cb_sfp_state_query(struct bfa_sfp_s *sfp)3647{3648 bfa_trc(sfp, sfp->portspeed);3649 if (sfp->media) {3650 bfa_sfp_media_get(sfp);3651 if (sfp->state_query_cbfn)3652 sfp->state_query_cbfn(sfp->state_query_cbarg,3653 sfp->status);3654 sfp->media = NULL;3655 }3656 3657 if (sfp->portspeed) {3658 sfp->status = bfa_sfp_speed_valid(sfp, sfp->portspeed);3659 if (sfp->state_query_cbfn)3660 sfp->state_query_cbfn(sfp->state_query_cbarg,3661 sfp->status);3662 sfp->portspeed = BFA_PORT_SPEED_UNKNOWN;3663 }3664 3665 sfp->state_query_lock = 0;3666 sfp->state_query_cbfn = NULL;3667}3668 3669/*3670 * IOC event handler.3671 */3672static void3673bfa_sfp_notify(void *sfp_arg, enum bfa_ioc_event_e event)3674{3675 struct bfa_sfp_s *sfp = sfp_arg;3676 3677 bfa_trc(sfp, event);3678 bfa_trc(sfp, sfp->lock);3679 bfa_trc(sfp, sfp->state_query_lock);3680 3681 switch (event) {3682 case BFA_IOC_E_DISABLED:3683 case BFA_IOC_E_FAILED:3684 if (sfp->lock) {3685 sfp->status = BFA_STATUS_IOC_FAILURE;3686 bfa_cb_sfp_show(sfp);3687 }3688 3689 if (sfp->state_query_lock) {3690 sfp->status = BFA_STATUS_IOC_FAILURE;3691 bfa_cb_sfp_state_query(sfp);3692 }3693 break;3694 3695 default:3696 break;3697 }3698}3699 3700/*3701 * SFP's State Change Notification post to AEN3702 */3703static void3704bfa_sfp_scn_aen_post(struct bfa_sfp_s *sfp, struct bfi_sfp_scn_s *rsp)3705{3706 struct bfad_s *bfad = (struct bfad_s *)sfp->ioc->bfa->bfad;3707 struct bfa_aen_entry_s *aen_entry;3708 enum bfa_port_aen_event aen_evt = 0;3709 3710 bfa_trc(sfp, (((u64)rsp->pomlvl) << 16) | (((u64)rsp->sfpid) << 8) |3711 ((u64)rsp->event));3712 3713 bfad_get_aen_entry(bfad, aen_entry);3714 if (!aen_entry)3715 return;3716 3717 aen_entry->aen_data.port.ioc_type = bfa_ioc_get_type(sfp->ioc);3718 aen_entry->aen_data.port.pwwn = sfp->ioc->attr->pwwn;3719 aen_entry->aen_data.port.mac = bfa_ioc_get_mac(sfp->ioc);3720 3721 switch (rsp->event) {3722 case BFA_SFP_SCN_INSERTED:3723 aen_evt = BFA_PORT_AEN_SFP_INSERT;3724 break;3725 case BFA_SFP_SCN_REMOVED:3726 aen_evt = BFA_PORT_AEN_SFP_REMOVE;3727 break;3728 case BFA_SFP_SCN_FAILED:3729 aen_evt = BFA_PORT_AEN_SFP_ACCESS_ERROR;3730 break;3731 case BFA_SFP_SCN_UNSUPPORT:3732 aen_evt = BFA_PORT_AEN_SFP_UNSUPPORT;3733 break;3734 case BFA_SFP_SCN_POM:3735 aen_evt = BFA_PORT_AEN_SFP_POM;3736 aen_entry->aen_data.port.level = rsp->pomlvl;3737 break;3738 default:3739 bfa_trc(sfp, rsp->event);3740 WARN_ON(1);3741 }3742 3743 /* Send the AEN notification */3744 bfad_im_post_vendor_event(aen_entry, bfad, ++sfp->ioc->ioc_aen_seq,3745 BFA_AEN_CAT_PORT, aen_evt);3746}3747 3748/*3749 * SFP get data send3750 */3751static void3752bfa_sfp_getdata_send(struct bfa_sfp_s *sfp)3753{3754 struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg;3755 3756 bfa_trc(sfp, req->memtype);3757 3758 /* build host command */3759 bfi_h2i_set(req->mh, BFI_MC_SFP, BFI_SFP_H2I_SHOW,3760 bfa_ioc_portid(sfp->ioc));3761 3762 /* send mbox cmd */3763 bfa_ioc_mbox_queue(sfp->ioc, &sfp->mbcmd);3764}3765 3766/*3767 * SFP is valid, read sfp data3768 */3769static void3770bfa_sfp_getdata(struct bfa_sfp_s *sfp, enum bfi_sfp_mem_e memtype)3771{3772 struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg;3773 3774 WARN_ON(sfp->lock != 0);3775 bfa_trc(sfp, sfp->state);3776 3777 sfp->lock = 1;3778 sfp->memtype = memtype;3779 req->memtype = memtype;3780 3781 /* Setup SG list */3782 bfa_alen_set(&req->alen, sizeof(struct sfp_mem_s), sfp->dbuf_pa);3783 3784 bfa_sfp_getdata_send(sfp);3785}3786 3787/*3788 * SFP scn handler3789 */3790static void3791bfa_sfp_scn(struct bfa_sfp_s *sfp, struct bfi_mbmsg_s *msg)3792{3793 struct bfi_sfp_scn_s *rsp = (struct bfi_sfp_scn_s *) msg;3794 3795 switch (rsp->event) {3796 case BFA_SFP_SCN_INSERTED:3797 sfp->state = BFA_SFP_STATE_INSERTED;3798 sfp->data_valid = 0;3799 bfa_sfp_scn_aen_post(sfp, rsp);3800 break;3801 case BFA_SFP_SCN_REMOVED:3802 sfp->state = BFA_SFP_STATE_REMOVED;3803 sfp->data_valid = 0;3804 bfa_sfp_scn_aen_post(sfp, rsp);3805 break;3806 case BFA_SFP_SCN_FAILED:3807 sfp->state = BFA_SFP_STATE_FAILED;3808 sfp->data_valid = 0;3809 bfa_sfp_scn_aen_post(sfp, rsp);3810 break;3811 case BFA_SFP_SCN_UNSUPPORT:3812 sfp->state = BFA_SFP_STATE_UNSUPPORT;3813 bfa_sfp_scn_aen_post(sfp, rsp);3814 if (!sfp->lock)3815 bfa_sfp_getdata(sfp, BFI_SFP_MEM_ALL);3816 break;3817 case BFA_SFP_SCN_POM:3818 bfa_sfp_scn_aen_post(sfp, rsp);3819 break;3820 case BFA_SFP_SCN_VALID:3821 sfp->state = BFA_SFP_STATE_VALID;3822 if (!sfp->lock)3823 bfa_sfp_getdata(sfp, BFI_SFP_MEM_ALL);3824 break;3825 default:3826 bfa_trc(sfp, rsp->event);3827 WARN_ON(1);3828 }3829}3830 3831/*3832 * SFP show complete3833 */3834static void3835bfa_sfp_show_comp(struct bfa_sfp_s *sfp, struct bfi_mbmsg_s *msg)3836{3837 struct bfi_sfp_rsp_s *rsp = (struct bfi_sfp_rsp_s *) msg;3838 3839 if (!sfp->lock) {3840 /*3841 * receiving response after ioc failure3842 */3843 bfa_trc(sfp, sfp->lock);3844 return;3845 }3846 3847 bfa_trc(sfp, rsp->status);3848 if (rsp->status == BFA_STATUS_OK) {3849 sfp->data_valid = 1;3850 if (sfp->state == BFA_SFP_STATE_VALID)3851 sfp->status = BFA_STATUS_OK;3852 else if (sfp->state == BFA_SFP_STATE_UNSUPPORT)3853 sfp->status = BFA_STATUS_SFP_UNSUPP;3854 else3855 bfa_trc(sfp, sfp->state);3856 } else {3857 sfp->data_valid = 0;3858 sfp->status = rsp->status;3859 /* sfpshow shouldn't change sfp state */3860 }3861 3862 bfa_trc(sfp, sfp->memtype);3863 if (sfp->memtype == BFI_SFP_MEM_DIAGEXT) {3864 bfa_trc(sfp, sfp->data_valid);3865 if (sfp->data_valid) {3866 u32 size = sizeof(struct sfp_mem_s);3867 u8 *des = (u8 *)(sfp->sfpmem);3868 memcpy(des, sfp->dbuf_kva, size);3869 }3870 /*3871 * Queue completion callback.3872 */3873 bfa_cb_sfp_show(sfp);3874 } else3875 sfp->lock = 0;3876 3877 bfa_trc(sfp, sfp->state_query_lock);3878 if (sfp->state_query_lock) {3879 sfp->state = rsp->state;3880 /* Complete callback */3881 bfa_cb_sfp_state_query(sfp);3882 }3883}3884 3885/*3886 * SFP query fw sfp state3887 */3888static void3889bfa_sfp_state_query(struct bfa_sfp_s *sfp)3890{3891 struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg;3892 3893 /* Should not be doing query if not in _INIT state */3894 WARN_ON(sfp->state != BFA_SFP_STATE_INIT);3895 WARN_ON(sfp->state_query_lock != 0);3896 bfa_trc(sfp, sfp->state);3897 3898 sfp->state_query_lock = 1;3899 req->memtype = 0;3900 3901 if (!sfp->lock)3902 bfa_sfp_getdata(sfp, BFI_SFP_MEM_ALL);3903}3904 3905static void3906bfa_sfp_media_get(struct bfa_sfp_s *sfp)3907{3908 enum bfa_defs_sfp_media_e *media = sfp->media;3909 3910 *media = BFA_SFP_MEDIA_UNKNOWN;3911 3912 if (sfp->state == BFA_SFP_STATE_UNSUPPORT)3913 *media = BFA_SFP_MEDIA_UNSUPPORT;3914 else if (sfp->state == BFA_SFP_STATE_VALID) {3915 union sfp_xcvr_e10g_code_u e10g;3916 struct sfp_mem_s *sfpmem = (struct sfp_mem_s *)sfp->dbuf_kva;3917 u16 xmtr_tech = (sfpmem->srlid_base.xcvr[4] & 0x3) << 7 |3918 (sfpmem->srlid_base.xcvr[5] >> 1);3919 3920 e10g.b = sfpmem->srlid_base.xcvr[0];3921 bfa_trc(sfp, e10g.b);3922 bfa_trc(sfp, xmtr_tech);3923 /* check fc transmitter tech */3924 if ((xmtr_tech & SFP_XMTR_TECH_CU) ||3925 (xmtr_tech & SFP_XMTR_TECH_CP) ||3926 (xmtr_tech & SFP_XMTR_TECH_CA))3927 *media = BFA_SFP_MEDIA_CU;3928 else if ((xmtr_tech & SFP_XMTR_TECH_EL_INTRA) ||3929 (xmtr_tech & SFP_XMTR_TECH_EL_INTER))3930 *media = BFA_SFP_MEDIA_EL;3931 else if ((xmtr_tech & SFP_XMTR_TECH_LL) ||3932 (xmtr_tech & SFP_XMTR_TECH_LC))3933 *media = BFA_SFP_MEDIA_LW;3934 else if ((xmtr_tech & SFP_XMTR_TECH_SL) ||3935 (xmtr_tech & SFP_XMTR_TECH_SN) ||3936 (xmtr_tech & SFP_XMTR_TECH_SA))3937 *media = BFA_SFP_MEDIA_SW;3938 /* Check 10G Ethernet Compilance code */3939 else if (e10g.r.e10g_sr)3940 *media = BFA_SFP_MEDIA_SW;3941 else if (e10g.r.e10g_lrm && e10g.r.e10g_lr)3942 *media = BFA_SFP_MEDIA_LW;3943 else if (e10g.r.e10g_unall)3944 *media = BFA_SFP_MEDIA_UNKNOWN;3945 else3946 bfa_trc(sfp, 0);3947 } else3948 bfa_trc(sfp, sfp->state);3949}3950 3951static bfa_status_t3952bfa_sfp_speed_valid(struct bfa_sfp_s *sfp, enum bfa_port_speed portspeed)3953{3954 struct sfp_mem_s *sfpmem = (struct sfp_mem_s *)sfp->dbuf_kva;3955 struct sfp_xcvr_s *xcvr = (struct sfp_xcvr_s *) sfpmem->srlid_base.xcvr;3956 union sfp_xcvr_fc3_code_u fc3 = xcvr->fc3;3957 union sfp_xcvr_e10g_code_u e10g = xcvr->e10g;3958 3959 if (portspeed == BFA_PORT_SPEED_10GBPS) {3960 if (e10g.r.e10g_sr || e10g.r.e10g_lr)3961 return BFA_STATUS_OK;3962 else {3963 bfa_trc(sfp, e10g.b);3964 return BFA_STATUS_UNSUPP_SPEED;3965 }3966 }3967 if (((portspeed & BFA_PORT_SPEED_16GBPS) && fc3.r.mb1600) ||3968 ((portspeed & BFA_PORT_SPEED_8GBPS) && fc3.r.mb800) ||3969 ((portspeed & BFA_PORT_SPEED_4GBPS) && fc3.r.mb400) ||3970 ((portspeed & BFA_PORT_SPEED_2GBPS) && fc3.r.mb200) ||3971 ((portspeed & BFA_PORT_SPEED_1GBPS) && fc3.r.mb100))3972 return BFA_STATUS_OK;3973 else {3974 bfa_trc(sfp, portspeed);3975 bfa_trc(sfp, fc3.b);3976 bfa_trc(sfp, e10g.b);3977 return BFA_STATUS_UNSUPP_SPEED;3978 }3979}3980 3981/*3982 * SFP hmbox handler3983 */3984void3985bfa_sfp_intr(void *sfparg, struct bfi_mbmsg_s *msg)3986{3987 struct bfa_sfp_s *sfp = sfparg;3988 3989 switch (msg->mh.msg_id) {3990 case BFI_SFP_I2H_SHOW:3991 bfa_sfp_show_comp(sfp, msg);3992 break;3993 3994 case BFI_SFP_I2H_SCN:3995 bfa_sfp_scn(sfp, msg);3996 break;3997 3998 default:3999 bfa_trc(sfp, msg->mh.msg_id);4000 WARN_ON(1);4001 }4002}4003 4004/*4005 * Return DMA memory needed by sfp module.4006 */4007u324008bfa_sfp_meminfo(void)4009{4010 return BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ);4011}4012 4013/*4014 * Attach virtual and physical memory for SFP.4015 */4016void4017bfa_sfp_attach(struct bfa_sfp_s *sfp, struct bfa_ioc_s *ioc, void *dev,4018 struct bfa_trc_mod_s *trcmod)4019{4020 sfp->dev = dev;4021 sfp->ioc = ioc;4022 sfp->trcmod = trcmod;4023 4024 sfp->cbfn = NULL;4025 sfp->cbarg = NULL;4026 sfp->sfpmem = NULL;4027 sfp->lock = 0;4028 sfp->data_valid = 0;4029 sfp->state = BFA_SFP_STATE_INIT;4030 sfp->state_query_lock = 0;4031 sfp->state_query_cbfn = NULL;4032 sfp->state_query_cbarg = NULL;4033 sfp->media = NULL;4034 sfp->portspeed = BFA_PORT_SPEED_UNKNOWN;4035 sfp->is_elb = BFA_FALSE;4036 4037 bfa_ioc_mbox_regisr(sfp->ioc, BFI_MC_SFP, bfa_sfp_intr, sfp);4038 bfa_q_qe_init(&sfp->ioc_notify);4039 bfa_ioc_notify_init(&sfp->ioc_notify, bfa_sfp_notify, sfp);4040 list_add_tail(&sfp->ioc_notify.qe, &sfp->ioc->notify_q);4041}4042 4043/*4044 * Claim Memory for SFP4045 */4046void4047bfa_sfp_memclaim(struct bfa_sfp_s *sfp, u8 *dm_kva, u64 dm_pa)4048{4049 sfp->dbuf_kva = dm_kva;4050 sfp->dbuf_pa = dm_pa;4051 memset(sfp->dbuf_kva, 0, sizeof(struct sfp_mem_s));4052 4053 dm_kva += BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ);4054 dm_pa += BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ);4055}4056 4057/*4058 * Show SFP eeprom content4059 *4060 * @param[in] sfp - bfa sfp module4061 *4062 * @param[out] sfpmem - sfp eeprom data4063 *4064 */4065bfa_status_t4066bfa_sfp_show(struct bfa_sfp_s *sfp, struct sfp_mem_s *sfpmem,4067 bfa_cb_sfp_t cbfn, void *cbarg)4068{4069 4070 if (!bfa_ioc_is_operational(sfp->ioc)) {4071 bfa_trc(sfp, 0);4072 return BFA_STATUS_IOC_NON_OP;4073 }4074 4075 if (sfp->lock) {4076 bfa_trc(sfp, 0);4077 return BFA_STATUS_DEVBUSY;4078 }4079 4080 sfp->cbfn = cbfn;4081 sfp->cbarg = cbarg;4082 sfp->sfpmem = sfpmem;4083 4084 bfa_sfp_getdata(sfp, BFI_SFP_MEM_DIAGEXT);4085 return BFA_STATUS_OK;4086}4087 4088/*4089 * Return SFP Media type4090 *4091 * @param[in] sfp - bfa sfp module4092 *4093 * @param[out] media - port speed from user4094 *4095 */4096bfa_status_t4097bfa_sfp_media(struct bfa_sfp_s *sfp, enum bfa_defs_sfp_media_e *media,4098 bfa_cb_sfp_t cbfn, void *cbarg)4099{4100 if (!bfa_ioc_is_operational(sfp->ioc)) {4101 bfa_trc(sfp, 0);4102 return BFA_STATUS_IOC_NON_OP;4103 }4104 4105 sfp->media = media;4106 if (sfp->state == BFA_SFP_STATE_INIT) {4107 if (sfp->state_query_lock) {4108 bfa_trc(sfp, 0);4109 return BFA_STATUS_DEVBUSY;4110 } else {4111 sfp->state_query_cbfn = cbfn;4112 sfp->state_query_cbarg = cbarg;4113 bfa_sfp_state_query(sfp);4114 return BFA_STATUS_SFP_NOT_READY;4115 }4116 }4117 4118 bfa_sfp_media_get(sfp);4119 return BFA_STATUS_OK;4120}4121 4122/*4123 * Check if user set port speed is allowed by the SFP4124 *4125 * @param[in] sfp - bfa sfp module4126 * @param[in] portspeed - port speed from user4127 *4128 */4129bfa_status_t4130bfa_sfp_speed(struct bfa_sfp_s *sfp, enum bfa_port_speed portspeed,4131 bfa_cb_sfp_t cbfn, void *cbarg)4132{4133 WARN_ON(portspeed == BFA_PORT_SPEED_UNKNOWN);4134 4135 if (!bfa_ioc_is_operational(sfp->ioc))4136 return BFA_STATUS_IOC_NON_OP;4137 4138 /* For Mezz card, all speed is allowed */4139 if (bfa_mfg_is_mezz(sfp->ioc->attr->card_type))4140 return BFA_STATUS_OK;4141 4142 /* Check SFP state */4143 sfp->portspeed = portspeed;4144 if (sfp->state == BFA_SFP_STATE_INIT) {4145 if (sfp->state_query_lock) {4146 bfa_trc(sfp, 0);4147 return BFA_STATUS_DEVBUSY;4148 } else {4149 sfp->state_query_cbfn = cbfn;4150 sfp->state_query_cbarg = cbarg;4151 bfa_sfp_state_query(sfp);4152 return BFA_STATUS_SFP_NOT_READY;4153 }4154 }4155 4156 if (sfp->state == BFA_SFP_STATE_REMOVED ||4157 sfp->state == BFA_SFP_STATE_FAILED) {4158 bfa_trc(sfp, sfp->state);4159 return BFA_STATUS_NO_SFP_DEV;4160 }4161 4162 if (sfp->state == BFA_SFP_STATE_INSERTED) {4163 bfa_trc(sfp, sfp->state);4164 return BFA_STATUS_DEVBUSY; /* sfp is reading data */4165 }4166 4167 /* For eloopback, all speed is allowed */4168 if (sfp->is_elb)4169 return BFA_STATUS_OK;4170 4171 return bfa_sfp_speed_valid(sfp, portspeed);4172}4173 4174/*4175 * Flash module specific4176 */4177 4178/*4179 * FLASH DMA buffer should be big enough to hold both MFG block and4180 * asic block(64k) at the same time and also should be 2k aligned to4181 * avoid write segement to cross sector boundary.4182 */4183#define BFA_FLASH_SEG_SZ 20484184#define BFA_FLASH_DMA_BUF_SZ \4185 BFA_ROUNDUP(0x010000 + sizeof(struct bfa_mfg_block_s), BFA_FLASH_SEG_SZ)4186 4187static void4188bfa_flash_aen_audit_post(struct bfa_ioc_s *ioc, enum bfa_audit_aen_event event,4189 int inst, int type)4190{4191 struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad;4192 struct bfa_aen_entry_s *aen_entry;4193 4194 bfad_get_aen_entry(bfad, aen_entry);4195 if (!aen_entry)4196 return;4197 4198 aen_entry->aen_data.audit.pwwn = ioc->attr->pwwn;4199 aen_entry->aen_data.audit.partition_inst = inst;4200 aen_entry->aen_data.audit.partition_type = type;4201 4202 /* Send the AEN notification */4203 bfad_im_post_vendor_event(aen_entry, bfad, ++ioc->ioc_aen_seq,4204 BFA_AEN_CAT_AUDIT, event);4205}4206 4207static void4208bfa_flash_cb(struct bfa_flash_s *flash)4209{4210 flash->op_busy = 0;4211 if (flash->cbfn)4212 flash->cbfn(flash->cbarg, flash->status);4213}4214 4215static void4216bfa_flash_notify(void *cbarg, enum bfa_ioc_event_e event)4217{4218 struct bfa_flash_s *flash = cbarg;4219 4220 bfa_trc(flash, event);4221 switch (event) {4222 case BFA_IOC_E_DISABLED:4223 case BFA_IOC_E_FAILED:4224 if (flash->op_busy) {4225 flash->status = BFA_STATUS_IOC_FAILURE;4226 flash->cbfn(flash->cbarg, flash->status);4227 flash->op_busy = 0;4228 }4229 break;4230 4231 default:4232 break;4233 }4234}4235 4236/*4237 * Send flash attribute query request.4238 *4239 * @param[in] cbarg - callback argument4240 */4241static void4242bfa_flash_query_send(void *cbarg)4243{4244 struct bfa_flash_s *flash = cbarg;4245 struct bfi_flash_query_req_s *msg =4246 (struct bfi_flash_query_req_s *) flash->mb.msg;4247 4248 bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_QUERY_REQ,4249 bfa_ioc_portid(flash->ioc));4250 bfa_alen_set(&msg->alen, sizeof(struct bfa_flash_attr_s),4251 flash->dbuf_pa);4252 bfa_ioc_mbox_queue(flash->ioc, &flash->mb);4253}4254 4255/*4256 * Send flash write request.4257 *4258 * @param[in] cbarg - callback argument4259 */4260static void4261bfa_flash_write_send(struct bfa_flash_s *flash)4262{4263 struct bfi_flash_write_req_s *msg =4264 (struct bfi_flash_write_req_s *) flash->mb.msg;4265 u32 len;4266 4267 msg->type = be32_to_cpu(flash->type);4268 msg->instance = flash->instance;4269 msg->offset = be32_to_cpu(flash->addr_off + flash->offset);4270 len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ?4271 flash->residue : BFA_FLASH_DMA_BUF_SZ;4272 msg->length = be32_to_cpu(len);4273 4274 /* indicate if it's the last msg of the whole write operation */4275 msg->last = (len == flash->residue) ? 1 : 0;4276 4277 bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_WRITE_REQ,4278 bfa_ioc_portid(flash->ioc));4279 bfa_alen_set(&msg->alen, len, flash->dbuf_pa);4280 memcpy(flash->dbuf_kva, flash->ubuf + flash->offset, len);4281 bfa_ioc_mbox_queue(flash->ioc, &flash->mb);4282 4283 flash->residue -= len;4284 flash->offset += len;4285}4286 4287/*4288 * Send flash read request.4289 *4290 * @param[in] cbarg - callback argument4291 */4292static void4293bfa_flash_read_send(void *cbarg)4294{4295 struct bfa_flash_s *flash = cbarg;4296 struct bfi_flash_read_req_s *msg =4297 (struct bfi_flash_read_req_s *) flash->mb.msg;4298 u32 len;4299 4300 msg->type = be32_to_cpu(flash->type);4301 msg->instance = flash->instance;4302 msg->offset = be32_to_cpu(flash->addr_off + flash->offset);4303 len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ?4304 flash->residue : BFA_FLASH_DMA_BUF_SZ;4305 msg->length = be32_to_cpu(len);4306 bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_READ_REQ,4307 bfa_ioc_portid(flash->ioc));4308 bfa_alen_set(&msg->alen, len, flash->dbuf_pa);4309 bfa_ioc_mbox_queue(flash->ioc, &flash->mb);4310}4311 4312/*4313 * Send flash erase request.4314 *4315 * @param[in] cbarg - callback argument4316 */4317static void4318bfa_flash_erase_send(void *cbarg)4319{4320 struct bfa_flash_s *flash = cbarg;4321 struct bfi_flash_erase_req_s *msg =4322 (struct bfi_flash_erase_req_s *) flash->mb.msg;4323 4324 msg->type = be32_to_cpu(flash->type);4325 msg->instance = flash->instance;4326 bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_ERASE_REQ,4327 bfa_ioc_portid(flash->ioc));4328 bfa_ioc_mbox_queue(flash->ioc, &flash->mb);4329}4330 4331/*4332 * Process flash response messages upon receiving interrupts.4333 *4334 * @param[in] flasharg - flash structure4335 * @param[in] msg - message structure4336 */4337static void4338bfa_flash_intr(void *flasharg, struct bfi_mbmsg_s *msg)4339{4340 struct bfa_flash_s *flash = flasharg;4341 u32 status;4342 4343 union {4344 struct bfi_flash_query_rsp_s *query;4345 struct bfi_flash_erase_rsp_s *erase;4346 struct bfi_flash_write_rsp_s *write;4347 struct bfi_flash_read_rsp_s *read;4348 struct bfi_flash_event_s *event;4349 struct bfi_mbmsg_s *msg;4350 } m;4351 4352 m.msg = msg;4353 bfa_trc(flash, msg->mh.msg_id);4354 4355 if (!flash->op_busy && msg->mh.msg_id != BFI_FLASH_I2H_EVENT) {4356 /* receiving response after ioc failure */4357 bfa_trc(flash, 0x9999);4358 return;4359 }4360 4361 switch (msg->mh.msg_id) {4362 case BFI_FLASH_I2H_QUERY_RSP:4363 status = be32_to_cpu(m.query->status);4364 bfa_trc(flash, status);4365 if (status == BFA_STATUS_OK) {4366 u32 i;4367 struct bfa_flash_attr_s *attr, *f;4368 4369 attr = (struct bfa_flash_attr_s *) flash->ubuf;4370 f = (struct bfa_flash_attr_s *) flash->dbuf_kva;4371 attr->status = be32_to_cpu(f->status);4372 attr->npart = be32_to_cpu(f->npart);4373 bfa_trc(flash, attr->status);4374 bfa_trc(flash, attr->npart);4375 for (i = 0; i < attr->npart; i++) {4376 attr->part[i].part_type =4377 be32_to_cpu(f->part[i].part_type);4378 attr->part[i].part_instance =4379 be32_to_cpu(f->part[i].part_instance);4380 attr->part[i].part_off =4381 be32_to_cpu(f->part[i].part_off);4382 attr->part[i].part_size =4383 be32_to_cpu(f->part[i].part_size);4384 attr->part[i].part_len =4385 be32_to_cpu(f->part[i].part_len);4386 attr->part[i].part_status =4387 be32_to_cpu(f->part[i].part_status);4388 }4389 }4390 flash->status = status;4391 bfa_flash_cb(flash);4392 break;4393 case BFI_FLASH_I2H_ERASE_RSP:4394 status = be32_to_cpu(m.erase->status);4395 bfa_trc(flash, status);4396 flash->status = status;4397 bfa_flash_cb(flash);4398 break;4399 case BFI_FLASH_I2H_WRITE_RSP:4400 status = be32_to_cpu(m.write->status);4401 bfa_trc(flash, status);4402 if (status != BFA_STATUS_OK || flash->residue == 0) {4403 flash->status = status;4404 bfa_flash_cb(flash);4405 } else {4406 bfa_trc(flash, flash->offset);4407 bfa_flash_write_send(flash);4408 }4409 break;4410 case BFI_FLASH_I2H_READ_RSP:4411 status = be32_to_cpu(m.read->status);4412 bfa_trc(flash, status);4413 if (status != BFA_STATUS_OK) {4414 flash->status = status;4415 bfa_flash_cb(flash);4416 } else {4417 u32 len = be32_to_cpu(m.read->length);4418 bfa_trc(flash, flash->offset);4419 bfa_trc(flash, len);4420 memcpy(flash->ubuf + flash->offset,4421 flash->dbuf_kva, len);4422 flash->residue -= len;4423 flash->offset += len;4424 if (flash->residue == 0) {4425 flash->status = status;4426 bfa_flash_cb(flash);4427 } else4428 bfa_flash_read_send(flash);4429 }4430 break;4431 case BFI_FLASH_I2H_BOOT_VER_RSP:4432 break;4433 case BFI_FLASH_I2H_EVENT:4434 status = be32_to_cpu(m.event->status);4435 bfa_trc(flash, status);4436 if (status == BFA_STATUS_BAD_FWCFG)4437 bfa_ioc_aen_post(flash->ioc, BFA_IOC_AEN_FWCFG_ERROR);4438 else if (status == BFA_STATUS_INVALID_VENDOR) {4439 u32 param;4440 param = be32_to_cpu(m.event->param);4441 bfa_trc(flash, param);4442 bfa_ioc_aen_post(flash->ioc,4443 BFA_IOC_AEN_INVALID_VENDOR);4444 }4445 break;4446 4447 default:4448 WARN_ON(1);4449 }4450}4451 4452/*4453 * Flash memory info API.4454 *4455 * @param[in] mincfg - minimal cfg variable4456 */4457u324458bfa_flash_meminfo(bfa_boolean_t mincfg)4459{4460 /* min driver doesn't need flash */4461 if (mincfg)4462 return 0;4463 return BFA_ROUNDUP(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);4464}4465 4466/*4467 * Flash attach API.4468 *4469 * @param[in] flash - flash structure4470 * @param[in] ioc - ioc structure4471 * @param[in] dev - device structure4472 * @param[in] trcmod - trace module4473 * @param[in] logmod - log module4474 */4475void4476bfa_flash_attach(struct bfa_flash_s *flash, struct bfa_ioc_s *ioc, void *dev,4477 struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg)4478{4479 flash->ioc = ioc;4480 flash->trcmod = trcmod;4481 flash->cbfn = NULL;4482 flash->cbarg = NULL;4483 flash->op_busy = 0;4484 4485 bfa_ioc_mbox_regisr(flash->ioc, BFI_MC_FLASH, bfa_flash_intr, flash);4486 bfa_q_qe_init(&flash->ioc_notify);4487 bfa_ioc_notify_init(&flash->ioc_notify, bfa_flash_notify, flash);4488 list_add_tail(&flash->ioc_notify.qe, &flash->ioc->notify_q);4489 4490 /* min driver doesn't need flash */4491 if (mincfg) {4492 flash->dbuf_kva = NULL;4493 flash->dbuf_pa = 0;4494 }4495}4496 4497/*4498 * Claim memory for flash4499 *4500 * @param[in] flash - flash structure4501 * @param[in] dm_kva - pointer to virtual memory address4502 * @param[in] dm_pa - physical memory address4503 * @param[in] mincfg - minimal cfg variable4504 */4505void4506bfa_flash_memclaim(struct bfa_flash_s *flash, u8 *dm_kva, u64 dm_pa,4507 bfa_boolean_t mincfg)4508{4509 if (mincfg)4510 return;4511 4512 flash->dbuf_kva = dm_kva;4513 flash->dbuf_pa = dm_pa;4514 memset(flash->dbuf_kva, 0, BFA_FLASH_DMA_BUF_SZ);4515 dm_kva += BFA_ROUNDUP(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);4516 dm_pa += BFA_ROUNDUP(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);4517}4518 4519/*4520 * Get flash attribute.4521 *4522 * @param[in] flash - flash structure4523 * @param[in] attr - flash attribute structure4524 * @param[in] cbfn - callback function4525 * @param[in] cbarg - callback argument4526 *4527 * Return status.4528 */4529bfa_status_t4530bfa_flash_get_attr(struct bfa_flash_s *flash, struct bfa_flash_attr_s *attr,4531 bfa_cb_flash_t cbfn, void *cbarg)4532{4533 bfa_trc(flash, BFI_FLASH_H2I_QUERY_REQ);4534 4535 if (!bfa_ioc_is_operational(flash->ioc))4536 return BFA_STATUS_IOC_NON_OP;4537 4538 if (flash->op_busy) {4539 bfa_trc(flash, flash->op_busy);4540 return BFA_STATUS_DEVBUSY;4541 }4542 4543 flash->op_busy = 1;4544 flash->cbfn = cbfn;4545 flash->cbarg = cbarg;4546 flash->ubuf = (u8 *) attr;4547 bfa_flash_query_send(flash);4548 4549 return BFA_STATUS_OK;4550}4551 4552/*4553 * Erase flash partition.4554 *4555 * @param[in] flash - flash structure4556 * @param[in] type - flash partition type4557 * @param[in] instance - flash partition instance4558 * @param[in] cbfn - callback function4559 * @param[in] cbarg - callback argument4560 *4561 * Return status.4562 */4563bfa_status_t4564bfa_flash_erase_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type,4565 u8 instance, bfa_cb_flash_t cbfn, void *cbarg)4566{4567 bfa_trc(flash, BFI_FLASH_H2I_ERASE_REQ);4568 bfa_trc(flash, type);4569 bfa_trc(flash, instance);4570 4571 if (!bfa_ioc_is_operational(flash->ioc))4572 return BFA_STATUS_IOC_NON_OP;4573 4574 if (flash->op_busy) {4575 bfa_trc(flash, flash->op_busy);4576 return BFA_STATUS_DEVBUSY;4577 }4578 4579 flash->op_busy = 1;4580 flash->cbfn = cbfn;4581 flash->cbarg = cbarg;4582 flash->type = type;4583 flash->instance = instance;4584 4585 bfa_flash_erase_send(flash);4586 bfa_flash_aen_audit_post(flash->ioc, BFA_AUDIT_AEN_FLASH_ERASE,4587 instance, type);4588 return BFA_STATUS_OK;4589}4590 4591/*4592 * Update flash partition.4593 *4594 * @param[in] flash - flash structure4595 * @param[in] type - flash partition type4596 * @param[in] instance - flash partition instance4597 * @param[in] buf - update data buffer4598 * @param[in] len - data buffer length4599 * @param[in] offset - offset relative to the partition starting address4600 * @param[in] cbfn - callback function4601 * @param[in] cbarg - callback argument4602 *4603 * Return status.4604 */4605bfa_status_t4606bfa_flash_update_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type,4607 u8 instance, void *buf, u32 len, u32 offset,4608 bfa_cb_flash_t cbfn, void *cbarg)4609{4610 bfa_trc(flash, BFI_FLASH_H2I_WRITE_REQ);4611 bfa_trc(flash, type);4612 bfa_trc(flash, instance);4613 bfa_trc(flash, len);4614 bfa_trc(flash, offset);4615 4616 if (!bfa_ioc_is_operational(flash->ioc))4617 return BFA_STATUS_IOC_NON_OP;4618 4619 /*4620 * 'len' must be in word (4-byte) boundary4621 * 'offset' must be in sector (16kb) boundary4622 */4623 if (!len || (len & 0x03) || (offset & 0x00003FFF))4624 return BFA_STATUS_FLASH_BAD_LEN;4625 4626 if (type == BFA_FLASH_PART_MFG)4627 return BFA_STATUS_EINVAL;4628 4629 if (flash->op_busy) {4630 bfa_trc(flash, flash->op_busy);4631 return BFA_STATUS_DEVBUSY;4632 }4633 4634 flash->op_busy = 1;4635 flash->cbfn = cbfn;4636 flash->cbarg = cbarg;4637 flash->type = type;4638 flash->instance = instance;4639 flash->residue = len;4640 flash->offset = 0;4641 flash->addr_off = offset;4642 flash->ubuf = buf;4643 4644 bfa_flash_write_send(flash);4645 return BFA_STATUS_OK;4646}4647 4648/*4649 * Read flash partition.4650 *4651 * @param[in] flash - flash structure4652 * @param[in] type - flash partition type4653 * @param[in] instance - flash partition instance4654 * @param[in] buf - read data buffer4655 * @param[in] len - data buffer length4656 * @param[in] offset - offset relative to the partition starting address4657 * @param[in] cbfn - callback function4658 * @param[in] cbarg - callback argument4659 *4660 * Return status.4661 */4662bfa_status_t4663bfa_flash_read_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type,4664 u8 instance, void *buf, u32 len, u32 offset,4665 bfa_cb_flash_t cbfn, void *cbarg)4666{4667 bfa_trc(flash, BFI_FLASH_H2I_READ_REQ);4668 bfa_trc(flash, type);4669 bfa_trc(flash, instance);4670 bfa_trc(flash, len);4671 bfa_trc(flash, offset);4672 4673 if (!bfa_ioc_is_operational(flash->ioc))4674 return BFA_STATUS_IOC_NON_OP;4675 4676 /*4677 * 'len' must be in word (4-byte) boundary4678 * 'offset' must be in sector (16kb) boundary4679 */4680 if (!len || (len & 0x03) || (offset & 0x00003FFF))4681 return BFA_STATUS_FLASH_BAD_LEN;4682 4683 if (flash->op_busy) {4684 bfa_trc(flash, flash->op_busy);4685 return BFA_STATUS_DEVBUSY;4686 }4687 4688 flash->op_busy = 1;4689 flash->cbfn = cbfn;4690 flash->cbarg = cbarg;4691 flash->type = type;4692 flash->instance = instance;4693 flash->residue = len;4694 flash->offset = 0;4695 flash->addr_off = offset;4696 flash->ubuf = buf;4697 bfa_flash_read_send(flash);4698 4699 return BFA_STATUS_OK;4700}4701 4702/*4703 * DIAG module specific4704 */4705 4706#define BFA_DIAG_MEMTEST_TOV 50000 /* memtest timeout in msec */4707#define CT2_BFA_DIAG_MEMTEST_TOV (9*30*1000) /* 4.5 min */4708 4709/* IOC event handler */4710static void4711bfa_diag_notify(void *diag_arg, enum bfa_ioc_event_e event)4712{4713 struct bfa_diag_s *diag = diag_arg;4714 4715 bfa_trc(diag, event);4716 bfa_trc(diag, diag->block);4717 bfa_trc(diag, diag->fwping.lock);4718 bfa_trc(diag, diag->tsensor.lock);4719 4720 switch (event) {4721 case BFA_IOC_E_DISABLED:4722 case BFA_IOC_E_FAILED:4723 if (diag->fwping.lock) {4724 diag->fwping.status = BFA_STATUS_IOC_FAILURE;4725 diag->fwping.cbfn(diag->fwping.cbarg,4726 diag->fwping.status);4727 diag->fwping.lock = 0;4728 }4729 4730 if (diag->tsensor.lock) {4731 diag->tsensor.status = BFA_STATUS_IOC_FAILURE;4732 diag->tsensor.cbfn(diag->tsensor.cbarg,4733 diag->tsensor.status);4734 diag->tsensor.lock = 0;4735 }4736 4737 if (diag->block) {4738 if (diag->timer_active) {4739 bfa_timer_stop(&diag->timer);4740 diag->timer_active = 0;4741 }4742 4743 diag->status = BFA_STATUS_IOC_FAILURE;4744 diag->cbfn(diag->cbarg, diag->status);4745 diag->block = 0;4746 }4747 break;4748 4749 default:4750 break;4751 }4752}4753 4754static void4755bfa_diag_memtest_done(void *cbarg)4756{4757 struct bfa_diag_s *diag = cbarg;4758 struct bfa_ioc_s *ioc = diag->ioc;4759 struct bfa_diag_memtest_result *res = diag->result;4760 u32 loff = BFI_BOOT_MEMTEST_RES_ADDR;4761 u32 pgnum, i;4762 4763 pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff);4764 writel(pgnum, ioc->ioc_regs.host_page_num_fn);4765 4766 for (i = 0; i < (sizeof(struct bfa_diag_memtest_result) /4767 sizeof(u32)); i++) {4768 /* read test result from smem */4769 *((u32 *) res + i) =4770 bfa_mem_read(ioc->ioc_regs.smem_page_start, loff);4771 loff += sizeof(u32);4772 }4773 4774 /* Reset IOC fwstates to BFI_IOC_UNINIT */4775 bfa_ioc_reset_fwstate(ioc);4776 4777 res->status = swab32(res->status);4778 bfa_trc(diag, res->status);4779 4780 if (res->status == BFI_BOOT_MEMTEST_RES_SIG)4781 diag->status = BFA_STATUS_OK;4782 else {4783 diag->status = BFA_STATUS_MEMTEST_FAILED;4784 res->addr = swab32(res->addr);4785 res->exp = swab32(res->exp);4786 res->act = swab32(res->act);4787 res->err_status = swab32(res->err_status);4788 res->err_status1 = swab32(res->err_status1);4789 res->err_addr = swab32(res->err_addr);4790 bfa_trc(diag, res->addr);4791 bfa_trc(diag, res->exp);4792 bfa_trc(diag, res->act);4793 bfa_trc(diag, res->err_status);4794 bfa_trc(diag, res->err_status1);4795 bfa_trc(diag, res->err_addr);4796 }4797 diag->timer_active = 0;4798 diag->cbfn(diag->cbarg, diag->status);4799 diag->block = 0;4800}4801 4802/*4803 * Firmware ping4804 */4805 4806/*4807 * Perform DMA test directly4808 */4809static void4810diag_fwping_send(struct bfa_diag_s *diag)4811{4812 struct bfi_diag_fwping_req_s *fwping_req;4813 u32 i;4814 4815 bfa_trc(diag, diag->fwping.dbuf_pa);4816 4817 /* fill DMA area with pattern */4818 for (i = 0; i < (BFI_DIAG_DMA_BUF_SZ >> 2); i++)4819 *((u32 *)diag->fwping.dbuf_kva + i) = diag->fwping.data;4820 4821 /* Fill mbox msg */4822 fwping_req = (struct bfi_diag_fwping_req_s *)diag->fwping.mbcmd.msg;4823 4824 /* Setup SG list */4825 bfa_alen_set(&fwping_req->alen, BFI_DIAG_DMA_BUF_SZ,4826 diag->fwping.dbuf_pa);4827 /* Set up dma count */4828 fwping_req->count = cpu_to_be32(diag->fwping.count);4829 /* Set up data pattern */4830 fwping_req->data = diag->fwping.data;4831 4832 /* build host command */4833 bfi_h2i_set(fwping_req->mh, BFI_MC_DIAG, BFI_DIAG_H2I_FWPING,4834 bfa_ioc_portid(diag->ioc));4835 4836 /* send mbox cmd */4837 bfa_ioc_mbox_queue(diag->ioc, &diag->fwping.mbcmd);4838}4839 4840static void4841diag_fwping_comp(struct bfa_diag_s *diag,4842 struct bfi_diag_fwping_rsp_s *diag_rsp)4843{4844 u32 rsp_data = diag_rsp->data;4845 u8 rsp_dma_status = diag_rsp->dma_status;4846 4847 bfa_trc(diag, rsp_data);4848 bfa_trc(diag, rsp_dma_status);4849 4850 if (rsp_dma_status == BFA_STATUS_OK) {4851 u32 i, pat;4852 pat = (diag->fwping.count & 0x1) ? ~(diag->fwping.data) :4853 diag->fwping.data;4854 /* Check mbox data */4855 if (diag->fwping.data != rsp_data) {4856 bfa_trc(diag, rsp_data);4857 diag->fwping.result->dmastatus =4858 BFA_STATUS_DATACORRUPTED;4859 diag->fwping.status = BFA_STATUS_DATACORRUPTED;4860 diag->fwping.cbfn(diag->fwping.cbarg,4861 diag->fwping.status);4862 diag->fwping.lock = 0;4863 return;4864 }4865 /* Check dma pattern */4866 for (i = 0; i < (BFI_DIAG_DMA_BUF_SZ >> 2); i++) {4867 if (*((u32 *)diag->fwping.dbuf_kva + i) != pat) {4868 bfa_trc(diag, i);4869 bfa_trc(diag, pat);4870 bfa_trc(diag,4871 *((u32 *)diag->fwping.dbuf_kva + i));4872 diag->fwping.result->dmastatus =4873 BFA_STATUS_DATACORRUPTED;4874 diag->fwping.status = BFA_STATUS_DATACORRUPTED;4875 diag->fwping.cbfn(diag->fwping.cbarg,4876 diag->fwping.status);4877 diag->fwping.lock = 0;4878 return;4879 }4880 }4881 diag->fwping.result->dmastatus = BFA_STATUS_OK;4882 diag->fwping.status = BFA_STATUS_OK;4883 diag->fwping.cbfn(diag->fwping.cbarg, diag->fwping.status);4884 diag->fwping.lock = 0;4885 } else {4886 diag->fwping.status = BFA_STATUS_HDMA_FAILED;4887 diag->fwping.cbfn(diag->fwping.cbarg, diag->fwping.status);4888 diag->fwping.lock = 0;4889 }4890}4891 4892/*4893 * Temperature Sensor4894 */4895 4896static void4897diag_tempsensor_send(struct bfa_diag_s *diag)4898{4899 struct bfi_diag_ts_req_s *msg;4900 4901 msg = (struct bfi_diag_ts_req_s *)diag->tsensor.mbcmd.msg;4902 bfa_trc(diag, msg->temp);4903 /* build host command */4904 bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_TEMPSENSOR,4905 bfa_ioc_portid(diag->ioc));4906 /* send mbox cmd */4907 bfa_ioc_mbox_queue(diag->ioc, &diag->tsensor.mbcmd);4908}4909 4910static void4911diag_tempsensor_comp(struct bfa_diag_s *diag, bfi_diag_ts_rsp_t *rsp)4912{4913 if (!diag->tsensor.lock) {4914 /* receiving response after ioc failure */4915 bfa_trc(diag, diag->tsensor.lock);4916 return;4917 }4918 4919 /*4920 * ASIC junction tempsensor is a reg read operation4921 * it will always return OK4922 */4923 diag->tsensor.temp->temp = be16_to_cpu(rsp->temp);4924 diag->tsensor.temp->ts_junc = rsp->ts_junc;4925 diag->tsensor.temp->ts_brd = rsp->ts_brd;4926 4927 if (rsp->ts_brd) {4928 /* tsensor.temp->status is brd_temp status */4929 diag->tsensor.temp->status = rsp->status;4930 if (rsp->status == BFA_STATUS_OK) {4931 diag->tsensor.temp->brd_temp =4932 be16_to_cpu(rsp->brd_temp);4933 } else4934 diag->tsensor.temp->brd_temp = 0;4935 }4936 4937 bfa_trc(diag, rsp->status);4938 bfa_trc(diag, rsp->ts_junc);4939 bfa_trc(diag, rsp->temp);4940 bfa_trc(diag, rsp->ts_brd);4941 bfa_trc(diag, rsp->brd_temp);4942 4943 /* tsensor status is always good bcos we always have junction temp */4944 diag->tsensor.status = BFA_STATUS_OK;4945 diag->tsensor.cbfn(diag->tsensor.cbarg, diag->tsensor.status);4946 diag->tsensor.lock = 0;4947}4948 4949/*4950 * LED Test command4951 */4952static void4953diag_ledtest_send(struct bfa_diag_s *diag, struct bfa_diag_ledtest_s *ledtest)4954{4955 struct bfi_diag_ledtest_req_s *msg;4956 4957 msg = (struct bfi_diag_ledtest_req_s *)diag->ledtest.mbcmd.msg;4958 /* build host command */4959 bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_LEDTEST,4960 bfa_ioc_portid(diag->ioc));4961 4962 /*4963 * convert the freq from N blinks per 10 sec to4964 * crossbow ontime value. We do it here because division is need4965 */4966 if (ledtest->freq)4967 ledtest->freq = 500 / ledtest->freq;4968 4969 if (ledtest->freq == 0)4970 ledtest->freq = 1;4971 4972 bfa_trc(diag, ledtest->freq);4973 /* mcpy(&ledtest_req->req, ledtest, sizeof(bfa_diag_ledtest_t)); */4974 msg->cmd = (u8) ledtest->cmd;4975 msg->color = (u8) ledtest->color;4976 msg->portid = bfa_ioc_portid(diag->ioc);4977 msg->led = ledtest->led;4978 msg->freq = cpu_to_be16(ledtest->freq);4979 4980 /* send mbox cmd */4981 bfa_ioc_mbox_queue(diag->ioc, &diag->ledtest.mbcmd);4982}4983 4984static void4985diag_ledtest_comp(struct bfa_diag_s *diag, struct bfi_diag_ledtest_rsp_s *msg)4986{4987 bfa_trc(diag, diag->ledtest.lock);4988 diag->ledtest.lock = BFA_FALSE;4989 /* no bfa_cb_queue is needed because driver is not waiting */4990}4991 4992/*4993 * Port beaconing4994 */4995static void4996diag_portbeacon_send(struct bfa_diag_s *diag, bfa_boolean_t beacon, u32 sec)4997{4998 struct bfi_diag_portbeacon_req_s *msg;4999 5000 msg = (struct bfi_diag_portbeacon_req_s *)diag->beacon.mbcmd.msg;5001 /* build host command */5002 bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_PORTBEACON,5003 bfa_ioc_portid(diag->ioc));5004 msg->beacon = beacon;5005 msg->period = cpu_to_be32(sec);5006 /* send mbox cmd */5007 bfa_ioc_mbox_queue(diag->ioc, &diag->beacon.mbcmd);5008}5009 5010static void5011diag_portbeacon_comp(struct bfa_diag_s *diag)5012{5013 bfa_trc(diag, diag->beacon.state);5014 diag->beacon.state = BFA_FALSE;5015 if (diag->cbfn_beacon)5016 diag->cbfn_beacon(diag->dev, BFA_FALSE, diag->beacon.link_e2e);5017}5018 5019/*5020 * Diag hmbox handler5021 */5022static void5023bfa_diag_intr(void *diagarg, struct bfi_mbmsg_s *msg)5024{5025 struct bfa_diag_s *diag = diagarg;5026 5027 switch (msg->mh.msg_id) {5028 case BFI_DIAG_I2H_PORTBEACON:5029 diag_portbeacon_comp(diag);5030 break;5031 case BFI_DIAG_I2H_FWPING:5032 diag_fwping_comp(diag, (struct bfi_diag_fwping_rsp_s *) msg);5033 break;5034 case BFI_DIAG_I2H_TEMPSENSOR:5035 diag_tempsensor_comp(diag, (bfi_diag_ts_rsp_t *) msg);5036 break;5037 case BFI_DIAG_I2H_LEDTEST:5038 diag_ledtest_comp(diag, (struct bfi_diag_ledtest_rsp_s *) msg);5039 break;5040 default:5041 bfa_trc(diag, msg->mh.msg_id);5042 WARN_ON(1);5043 }5044}5045 5046/*5047 * Gen RAM Test5048 *5049 * @param[in] *diag - diag data struct5050 * @param[in] *memtest - mem test params input from upper layer,5051 * @param[in] pattern - mem test pattern5052 * @param[in] *result - mem test result5053 * @param[in] cbfn - mem test callback functioin5054 * @param[in] cbarg - callback functioin arg5055 *5056 * @param[out]5057 */5058bfa_status_t5059bfa_diag_memtest(struct bfa_diag_s *diag, struct bfa_diag_memtest_s *memtest,5060 u32 pattern, struct bfa_diag_memtest_result *result,5061 bfa_cb_diag_t cbfn, void *cbarg)5062{5063 u32 memtest_tov;5064 5065 bfa_trc(diag, pattern);5066 5067 if (!bfa_ioc_adapter_is_disabled(diag->ioc))5068 return BFA_STATUS_ADAPTER_ENABLED;5069 5070 /* check to see if there is another destructive diag cmd running */5071 if (diag->block) {5072 bfa_trc(diag, diag->block);5073 return BFA_STATUS_DEVBUSY;5074 } else5075 diag->block = 1;5076 5077 diag->result = result;5078 diag->cbfn = cbfn;5079 diag->cbarg = cbarg;5080 5081 /* download memtest code and take LPU0 out of reset */5082 bfa_ioc_boot(diag->ioc, BFI_FWBOOT_TYPE_MEMTEST, BFI_FWBOOT_ENV_OS);5083 5084 memtest_tov = (bfa_ioc_asic_gen(diag->ioc) == BFI_ASIC_GEN_CT2) ?5085 CT2_BFA_DIAG_MEMTEST_TOV : BFA_DIAG_MEMTEST_TOV;5086 bfa_timer_begin(diag->ioc->timer_mod, &diag->timer,5087 bfa_diag_memtest_done, diag, memtest_tov);5088 diag->timer_active = 1;5089 return BFA_STATUS_OK;5090}5091 5092/*5093 * DIAG firmware ping command5094 *5095 * @param[in] *diag - diag data struct5096 * @param[in] cnt - dma loop count for testing PCIE5097 * @param[in] data - data pattern to pass in fw5098 * @param[in] *result - pt to bfa_diag_fwping_result_t data struct5099 * @param[in] cbfn - callback function5100 * @param[in] *cbarg - callback functioin arg5101 *5102 * @param[out]5103 */5104bfa_status_t5105bfa_diag_fwping(struct bfa_diag_s *diag, u32 cnt, u32 data,5106 struct bfa_diag_results_fwping *result, bfa_cb_diag_t cbfn,5107 void *cbarg)5108{5109 bfa_trc(diag, cnt);5110 bfa_trc(diag, data);5111 5112 if (!bfa_ioc_is_operational(diag->ioc))5113 return BFA_STATUS_IOC_NON_OP;5114 5115 if (bfa_asic_id_ct2(bfa_ioc_devid((diag->ioc))) &&5116 ((diag->ioc)->clscode == BFI_PCIFN_CLASS_ETH))5117 return BFA_STATUS_CMD_NOTSUPP;5118 5119 /* check to see if there is another destructive diag cmd running */5120 if (diag->block || diag->fwping.lock) {5121 bfa_trc(diag, diag->block);5122 bfa_trc(diag, diag->fwping.lock);5123 return BFA_STATUS_DEVBUSY;5124 }5125 5126 /* Initialization */5127 diag->fwping.lock = 1;5128 diag->fwping.cbfn = cbfn;5129 diag->fwping.cbarg = cbarg;5130 diag->fwping.result = result;5131 diag->fwping.data = data;5132 diag->fwping.count = cnt;5133 5134 /* Init test results */5135 diag->fwping.result->data = 0;5136 diag->fwping.result->status = BFA_STATUS_OK;5137 5138 /* kick off the first ping */5139 diag_fwping_send(diag);5140 return BFA_STATUS_OK;5141}5142 5143/*5144 * Read Temperature Sensor5145 *5146 * @param[in] *diag - diag data struct5147 * @param[in] *result - pt to bfa_diag_temp_t data struct5148 * @param[in] cbfn - callback function5149 * @param[in] *cbarg - callback functioin arg5150 *5151 * @param[out]5152 */5153bfa_status_t5154bfa_diag_tsensor_query(struct bfa_diag_s *diag,5155 struct bfa_diag_results_tempsensor_s *result,5156 bfa_cb_diag_t cbfn, void *cbarg)5157{5158 /* check to see if there is a destructive diag cmd running */5159 if (diag->block || diag->tsensor.lock) {5160 bfa_trc(diag, diag->block);5161 bfa_trc(diag, diag->tsensor.lock);5162 return BFA_STATUS_DEVBUSY;5163 }5164 5165 if (!bfa_ioc_is_operational(diag->ioc))5166 return BFA_STATUS_IOC_NON_OP;5167 5168 /* Init diag mod params */5169 diag->tsensor.lock = 1;5170 diag->tsensor.temp = result;5171 diag->tsensor.cbfn = cbfn;5172 diag->tsensor.cbarg = cbarg;5173 diag->tsensor.status = BFA_STATUS_OK;5174 5175 /* Send msg to fw */5176 diag_tempsensor_send(diag);5177 5178 return BFA_STATUS_OK;5179}5180 5181/*5182 * LED Test command5183 *5184 * @param[in] *diag - diag data struct5185 * @param[in] *ledtest - pt to ledtest data structure5186 *5187 * @param[out]5188 */5189bfa_status_t5190bfa_diag_ledtest(struct bfa_diag_s *diag, struct bfa_diag_ledtest_s *ledtest)5191{5192 bfa_trc(diag, ledtest->cmd);5193 5194 if (!bfa_ioc_is_operational(diag->ioc))5195 return BFA_STATUS_IOC_NON_OP;5196 5197 if (diag->beacon.state)5198 return BFA_STATUS_BEACON_ON;5199 5200 if (diag->ledtest.lock)5201 return BFA_STATUS_LEDTEST_OP;5202 5203 /* Send msg to fw */5204 diag->ledtest.lock = BFA_TRUE;5205 diag_ledtest_send(diag, ledtest);5206 5207 return BFA_STATUS_OK;5208}5209 5210/*5211 * Port beaconing command5212 *5213 * @param[in] *diag - diag data struct5214 * @param[in] beacon - port beaconing 1:ON 0:OFF5215 * @param[in] link_e2e_beacon - link beaconing 1:ON 0:OFF5216 * @param[in] sec - beaconing duration in seconds5217 *5218 * @param[out]5219 */5220bfa_status_t5221bfa_diag_beacon_port(struct bfa_diag_s *diag, bfa_boolean_t beacon,5222 bfa_boolean_t link_e2e_beacon, uint32_t sec)5223{5224 bfa_trc(diag, beacon);5225 bfa_trc(diag, link_e2e_beacon);5226 bfa_trc(diag, sec);5227 5228 if (!bfa_ioc_is_operational(diag->ioc))5229 return BFA_STATUS_IOC_NON_OP;5230 5231 if (diag->ledtest.lock)5232 return BFA_STATUS_LEDTEST_OP;5233 5234 if (diag->beacon.state && beacon) /* beacon alread on */5235 return BFA_STATUS_BEACON_ON;5236 5237 diag->beacon.state = beacon;5238 diag->beacon.link_e2e = link_e2e_beacon;5239 if (diag->cbfn_beacon)5240 diag->cbfn_beacon(diag->dev, beacon, link_e2e_beacon);5241 5242 /* Send msg to fw */5243 diag_portbeacon_send(diag, beacon, sec);5244 5245 return BFA_STATUS_OK;5246}5247 5248/*5249 * Return DMA memory needed by diag module.5250 */5251u325252bfa_diag_meminfo(void)5253{5254 return BFA_ROUNDUP(BFI_DIAG_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);5255}5256 5257/*5258 * Attach virtual and physical memory for Diag.5259 */5260void5261bfa_diag_attach(struct bfa_diag_s *diag, struct bfa_ioc_s *ioc, void *dev,5262 bfa_cb_diag_beacon_t cbfn_beacon, struct bfa_trc_mod_s *trcmod)5263{5264 diag->dev = dev;5265 diag->ioc = ioc;5266 diag->trcmod = trcmod;5267 5268 diag->block = 0;5269 diag->cbfn = NULL;5270 diag->cbarg = NULL;5271 diag->result = NULL;5272 diag->cbfn_beacon = cbfn_beacon;5273 5274 bfa_ioc_mbox_regisr(diag->ioc, BFI_MC_DIAG, bfa_diag_intr, diag);5275 bfa_q_qe_init(&diag->ioc_notify);5276 bfa_ioc_notify_init(&diag->ioc_notify, bfa_diag_notify, diag);5277 list_add_tail(&diag->ioc_notify.qe, &diag->ioc->notify_q);5278}5279 5280void5281bfa_diag_memclaim(struct bfa_diag_s *diag, u8 *dm_kva, u64 dm_pa)5282{5283 diag->fwping.dbuf_kva = dm_kva;5284 diag->fwping.dbuf_pa = dm_pa;5285 memset(diag->fwping.dbuf_kva, 0, BFI_DIAG_DMA_BUF_SZ);5286}5287 5288/*5289 * PHY module specific5290 */5291#define BFA_PHY_DMA_BUF_SZ 0x02000 /* 8k dma buffer */5292#define BFA_PHY_LOCK_STATUS 0x018878 /* phy semaphore status reg */5293 5294static void5295bfa_phy_ntoh32(u32 *obuf, u32 *ibuf, int sz)5296{5297 int i, m = sz >> 2;5298 5299 for (i = 0; i < m; i++)5300 obuf[i] = be32_to_cpu(ibuf[i]);5301}5302 5303static bfa_boolean_t5304bfa_phy_present(struct bfa_phy_s *phy)5305{5306 return (phy->ioc->attr->card_type == BFA_MFG_TYPE_LIGHTNING);5307}5308 5309static void5310bfa_phy_notify(void *cbarg, enum bfa_ioc_event_e event)5311{5312 struct bfa_phy_s *phy = cbarg;5313 5314 bfa_trc(phy, event);5315 5316 switch (event) {5317 case BFA_IOC_E_DISABLED:5318 case BFA_IOC_E_FAILED:5319 if (phy->op_busy) {5320 phy->status = BFA_STATUS_IOC_FAILURE;5321 phy->cbfn(phy->cbarg, phy->status);5322 phy->op_busy = 0;5323 }5324 break;5325 5326 default:5327 break;5328 }5329}5330 5331/*5332 * Send phy attribute query request.5333 *5334 * @param[in] cbarg - callback argument5335 */5336static void5337bfa_phy_query_send(void *cbarg)5338{5339 struct bfa_phy_s *phy = cbarg;5340 struct bfi_phy_query_req_s *msg =5341 (struct bfi_phy_query_req_s *) phy->mb.msg;5342 5343 msg->instance = phy->instance;5344 bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_QUERY_REQ,5345 bfa_ioc_portid(phy->ioc));5346 bfa_alen_set(&msg->alen, sizeof(struct bfa_phy_attr_s), phy->dbuf_pa);5347 bfa_ioc_mbox_queue(phy->ioc, &phy->mb);5348}5349 5350/*5351 * Send phy write request.5352 *5353 * @param[in] cbarg - callback argument5354 */5355static void5356bfa_phy_write_send(void *cbarg)5357{5358 struct bfa_phy_s *phy = cbarg;5359 struct bfi_phy_write_req_s *msg =5360 (struct bfi_phy_write_req_s *) phy->mb.msg;5361 u32 len;5362 u16 *buf, *dbuf;5363 int i, sz;5364 5365 msg->instance = phy->instance;5366 msg->offset = cpu_to_be32(phy->addr_off + phy->offset);5367 len = (phy->residue < BFA_PHY_DMA_BUF_SZ) ?5368 phy->residue : BFA_PHY_DMA_BUF_SZ;5369 msg->length = cpu_to_be32(len);5370 5371 /* indicate if it's the last msg of the whole write operation */5372 msg->last = (len == phy->residue) ? 1 : 0;5373 5374 bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_WRITE_REQ,5375 bfa_ioc_portid(phy->ioc));5376 bfa_alen_set(&msg->alen, len, phy->dbuf_pa);5377 5378 buf = (u16 *) (phy->ubuf + phy->offset);5379 dbuf = (u16 *)phy->dbuf_kva;5380 sz = len >> 1;5381 for (i = 0; i < sz; i++)5382 buf[i] = cpu_to_be16(dbuf[i]);5383 5384 bfa_ioc_mbox_queue(phy->ioc, &phy->mb);5385 5386 phy->residue -= len;5387 phy->offset += len;5388}5389 5390/*5391 * Send phy read request.5392 *5393 * @param[in] cbarg - callback argument5394 */5395static void5396bfa_phy_read_send(void *cbarg)5397{5398 struct bfa_phy_s *phy = cbarg;5399 struct bfi_phy_read_req_s *msg =5400 (struct bfi_phy_read_req_s *) phy->mb.msg;5401 u32 len;5402 5403 msg->instance = phy->instance;5404 msg->offset = cpu_to_be32(phy->addr_off + phy->offset);5405 len = (phy->residue < BFA_PHY_DMA_BUF_SZ) ?5406 phy->residue : BFA_PHY_DMA_BUF_SZ;5407 msg->length = cpu_to_be32(len);5408 bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_READ_REQ,5409 bfa_ioc_portid(phy->ioc));5410 bfa_alen_set(&msg->alen, len, phy->dbuf_pa);5411 bfa_ioc_mbox_queue(phy->ioc, &phy->mb);5412}5413 5414/*5415 * Send phy stats request.5416 *5417 * @param[in] cbarg - callback argument5418 */5419static void5420bfa_phy_stats_send(void *cbarg)5421{5422 struct bfa_phy_s *phy = cbarg;5423 struct bfi_phy_stats_req_s *msg =5424 (struct bfi_phy_stats_req_s *) phy->mb.msg;5425 5426 msg->instance = phy->instance;5427 bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_STATS_REQ,5428 bfa_ioc_portid(phy->ioc));5429 bfa_alen_set(&msg->alen, sizeof(struct bfa_phy_stats_s), phy->dbuf_pa);5430 bfa_ioc_mbox_queue(phy->ioc, &phy->mb);5431}5432 5433/*5434 * Flash memory info API.5435 *5436 * @param[in] mincfg - minimal cfg variable5437 */5438u325439bfa_phy_meminfo(bfa_boolean_t mincfg)5440{5441 /* min driver doesn't need phy */5442 if (mincfg)5443 return 0;5444 5445 return BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);5446}5447 5448/*5449 * Flash attach API.5450 *5451 * @param[in] phy - phy structure5452 * @param[in] ioc - ioc structure5453 * @param[in] dev - device structure5454 * @param[in] trcmod - trace module5455 * @param[in] logmod - log module5456 */5457void5458bfa_phy_attach(struct bfa_phy_s *phy, struct bfa_ioc_s *ioc, void *dev,5459 struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg)5460{5461 phy->ioc = ioc;5462 phy->trcmod = trcmod;5463 phy->cbfn = NULL;5464 phy->cbarg = NULL;5465 phy->op_busy = 0;5466 5467 bfa_ioc_mbox_regisr(phy->ioc, BFI_MC_PHY, bfa_phy_intr, phy);5468 bfa_q_qe_init(&phy->ioc_notify);5469 bfa_ioc_notify_init(&phy->ioc_notify, bfa_phy_notify, phy);5470 list_add_tail(&phy->ioc_notify.qe, &phy->ioc->notify_q);5471 5472 /* min driver doesn't need phy */5473 if (mincfg) {5474 phy->dbuf_kva = NULL;5475 phy->dbuf_pa = 0;5476 }5477}5478 5479/*5480 * Claim memory for phy5481 *5482 * @param[in] phy - phy structure5483 * @param[in] dm_kva - pointer to virtual memory address5484 * @param[in] dm_pa - physical memory address5485 * @param[in] mincfg - minimal cfg variable5486 */5487void5488bfa_phy_memclaim(struct bfa_phy_s *phy, u8 *dm_kva, u64 dm_pa,5489 bfa_boolean_t mincfg)5490{5491 if (mincfg)5492 return;5493 5494 phy->dbuf_kva = dm_kva;5495 phy->dbuf_pa = dm_pa;5496 memset(phy->dbuf_kva, 0, BFA_PHY_DMA_BUF_SZ);5497 dm_kva += BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);5498 dm_pa += BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);5499}5500 5501bfa_boolean_t5502bfa_phy_busy(struct bfa_ioc_s *ioc)5503{5504 void __iomem *rb;5505 5506 rb = bfa_ioc_bar0(ioc);5507 return readl(rb + BFA_PHY_LOCK_STATUS);5508}5509 5510/*5511 * Get phy attribute.5512 *5513 * @param[in] phy - phy structure5514 * @param[in] attr - phy attribute structure5515 * @param[in] cbfn - callback function5516 * @param[in] cbarg - callback argument5517 *5518 * Return status.5519 */5520bfa_status_t5521bfa_phy_get_attr(struct bfa_phy_s *phy, u8 instance,5522 struct bfa_phy_attr_s *attr, bfa_cb_phy_t cbfn, void *cbarg)5523{5524 bfa_trc(phy, BFI_PHY_H2I_QUERY_REQ);5525 bfa_trc(phy, instance);5526 5527 if (!bfa_phy_present(phy))5528 return BFA_STATUS_PHY_NOT_PRESENT;5529 5530 if (!bfa_ioc_is_operational(phy->ioc))5531 return BFA_STATUS_IOC_NON_OP;5532 5533 if (phy->op_busy || bfa_phy_busy(phy->ioc)) {5534 bfa_trc(phy, phy->op_busy);5535 return BFA_STATUS_DEVBUSY;5536 }5537 5538 phy->op_busy = 1;5539 phy->cbfn = cbfn;5540 phy->cbarg = cbarg;5541 phy->instance = instance;5542 phy->ubuf = (uint8_t *) attr;5543 bfa_phy_query_send(phy);5544 5545 return BFA_STATUS_OK;5546}5547 5548/*5549 * Get phy stats.5550 *5551 * @param[in] phy - phy structure5552 * @param[in] instance - phy image instance5553 * @param[in] stats - pointer to phy stats5554 * @param[in] cbfn - callback function5555 * @param[in] cbarg - callback argument5556 *5557 * Return status.5558 */5559bfa_status_t5560bfa_phy_get_stats(struct bfa_phy_s *phy, u8 instance,5561 struct bfa_phy_stats_s *stats,5562 bfa_cb_phy_t cbfn, void *cbarg)5563{5564 bfa_trc(phy, BFI_PHY_H2I_STATS_REQ);5565 bfa_trc(phy, instance);5566 5567 if (!bfa_phy_present(phy))5568 return BFA_STATUS_PHY_NOT_PRESENT;5569 5570 if (!bfa_ioc_is_operational(phy->ioc))5571 return BFA_STATUS_IOC_NON_OP;5572 5573 if (phy->op_busy || bfa_phy_busy(phy->ioc)) {5574 bfa_trc(phy, phy->op_busy);5575 return BFA_STATUS_DEVBUSY;5576 }5577 5578 phy->op_busy = 1;5579 phy->cbfn = cbfn;5580 phy->cbarg = cbarg;5581 phy->instance = instance;5582 phy->ubuf = (u8 *) stats;5583 bfa_phy_stats_send(phy);5584 5585 return BFA_STATUS_OK;5586}5587 5588/*5589 * Update phy image.5590 *5591 * @param[in] phy - phy structure5592 * @param[in] instance - phy image instance5593 * @param[in] buf - update data buffer5594 * @param[in] len - data buffer length5595 * @param[in] offset - offset relative to starting address5596 * @param[in] cbfn - callback function5597 * @param[in] cbarg - callback argument5598 *5599 * Return status.5600 */5601bfa_status_t5602bfa_phy_update(struct bfa_phy_s *phy, u8 instance,5603 void *buf, u32 len, u32 offset,5604 bfa_cb_phy_t cbfn, void *cbarg)5605{5606 bfa_trc(phy, BFI_PHY_H2I_WRITE_REQ);5607 bfa_trc(phy, instance);5608 bfa_trc(phy, len);5609 bfa_trc(phy, offset);5610 5611 if (!bfa_phy_present(phy))5612 return BFA_STATUS_PHY_NOT_PRESENT;5613 5614 if (!bfa_ioc_is_operational(phy->ioc))5615 return BFA_STATUS_IOC_NON_OP;5616 5617 /* 'len' must be in word (4-byte) boundary */5618 if (!len || (len & 0x03))5619 return BFA_STATUS_FAILED;5620 5621 if (phy->op_busy || bfa_phy_busy(phy->ioc)) {5622 bfa_trc(phy, phy->op_busy);5623 return BFA_STATUS_DEVBUSY;5624 }5625 5626 phy->op_busy = 1;5627 phy->cbfn = cbfn;5628 phy->cbarg = cbarg;5629 phy->instance = instance;5630 phy->residue = len;5631 phy->offset = 0;5632 phy->addr_off = offset;5633 phy->ubuf = buf;5634 5635 bfa_phy_write_send(phy);5636 return BFA_STATUS_OK;5637}5638 5639/*5640 * Read phy image.5641 *5642 * @param[in] phy - phy structure5643 * @param[in] instance - phy image instance5644 * @param[in] buf - read data buffer5645 * @param[in] len - data buffer length5646 * @param[in] offset - offset relative to starting address5647 * @param[in] cbfn - callback function5648 * @param[in] cbarg - callback argument5649 *5650 * Return status.5651 */5652bfa_status_t5653bfa_phy_read(struct bfa_phy_s *phy, u8 instance,5654 void *buf, u32 len, u32 offset,5655 bfa_cb_phy_t cbfn, void *cbarg)5656{5657 bfa_trc(phy, BFI_PHY_H2I_READ_REQ);5658 bfa_trc(phy, instance);5659 bfa_trc(phy, len);5660 bfa_trc(phy, offset);5661 5662 if (!bfa_phy_present(phy))5663 return BFA_STATUS_PHY_NOT_PRESENT;5664 5665 if (!bfa_ioc_is_operational(phy->ioc))5666 return BFA_STATUS_IOC_NON_OP;5667 5668 /* 'len' must be in word (4-byte) boundary */5669 if (!len || (len & 0x03))5670 return BFA_STATUS_FAILED;5671 5672 if (phy->op_busy || bfa_phy_busy(phy->ioc)) {5673 bfa_trc(phy, phy->op_busy);5674 return BFA_STATUS_DEVBUSY;5675 }5676 5677 phy->op_busy = 1;5678 phy->cbfn = cbfn;5679 phy->cbarg = cbarg;5680 phy->instance = instance;5681 phy->residue = len;5682 phy->offset = 0;5683 phy->addr_off = offset;5684 phy->ubuf = buf;5685 bfa_phy_read_send(phy);5686 5687 return BFA_STATUS_OK;5688}5689 5690/*5691 * Process phy response messages upon receiving interrupts.5692 *5693 * @param[in] phyarg - phy structure5694 * @param[in] msg - message structure5695 */5696void5697bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg)5698{5699 struct bfa_phy_s *phy = phyarg;5700 u32 status;5701 5702 union {5703 struct bfi_phy_query_rsp_s *query;5704 struct bfi_phy_stats_rsp_s *stats;5705 struct bfi_phy_write_rsp_s *write;5706 struct bfi_phy_read_rsp_s *read;5707 struct bfi_mbmsg_s *msg;5708 } m;5709 5710 m.msg = msg;5711 bfa_trc(phy, msg->mh.msg_id);5712 5713 if (!phy->op_busy) {5714 /* receiving response after ioc failure */5715 bfa_trc(phy, 0x9999);5716 return;5717 }5718 5719 switch (msg->mh.msg_id) {5720 case BFI_PHY_I2H_QUERY_RSP:5721 status = be32_to_cpu(m.query->status);5722 bfa_trc(phy, status);5723 5724 if (status == BFA_STATUS_OK) {5725 struct bfa_phy_attr_s *attr =5726 (struct bfa_phy_attr_s *) phy->ubuf;5727 bfa_phy_ntoh32((u32 *)attr, (u32 *)phy->dbuf_kva,5728 sizeof(struct bfa_phy_attr_s));5729 bfa_trc(phy, attr->status);5730 bfa_trc(phy, attr->length);5731 }5732 5733 phy->status = status;5734 phy->op_busy = 0;5735 if (phy->cbfn)5736 phy->cbfn(phy->cbarg, phy->status);5737 break;5738 case BFI_PHY_I2H_STATS_RSP:5739 status = be32_to_cpu(m.stats->status);5740 bfa_trc(phy, status);5741 5742 if (status == BFA_STATUS_OK) {5743 struct bfa_phy_stats_s *stats =5744 (struct bfa_phy_stats_s *) phy->ubuf;5745 bfa_phy_ntoh32((u32 *)stats, (u32 *)phy->dbuf_kva,5746 sizeof(struct bfa_phy_stats_s));5747 bfa_trc(phy, stats->status);5748 }5749 5750 phy->status = status;5751 phy->op_busy = 0;5752 if (phy->cbfn)5753 phy->cbfn(phy->cbarg, phy->status);5754 break;5755 case BFI_PHY_I2H_WRITE_RSP:5756 status = be32_to_cpu(m.write->status);5757 bfa_trc(phy, status);5758 5759 if (status != BFA_STATUS_OK || phy->residue == 0) {5760 phy->status = status;5761 phy->op_busy = 0;5762 if (phy->cbfn)5763 phy->cbfn(phy->cbarg, phy->status);5764 } else {5765 bfa_trc(phy, phy->offset);5766 bfa_phy_write_send(phy);5767 }5768 break;5769 case BFI_PHY_I2H_READ_RSP:5770 status = be32_to_cpu(m.read->status);5771 bfa_trc(phy, status);5772 5773 if (status != BFA_STATUS_OK) {5774 phy->status = status;5775 phy->op_busy = 0;5776 if (phy->cbfn)5777 phy->cbfn(phy->cbarg, phy->status);5778 } else {5779 u32 len = be32_to_cpu(m.read->length);5780 u16 *buf = (u16 *)(phy->ubuf + phy->offset);5781 u16 *dbuf = (u16 *)phy->dbuf_kva;5782 int i, sz = len >> 1;5783 5784 bfa_trc(phy, phy->offset);5785 bfa_trc(phy, len);5786 5787 for (i = 0; i < sz; i++)5788 buf[i] = be16_to_cpu(dbuf[i]);5789 5790 phy->residue -= len;5791 phy->offset += len;5792 5793 if (phy->residue == 0) {5794 phy->status = status;5795 phy->op_busy = 0;5796 if (phy->cbfn)5797 phy->cbfn(phy->cbarg, phy->status);5798 } else5799 bfa_phy_read_send(phy);5800 }5801 break;5802 default:5803 WARN_ON(1);5804 }5805}5806 5807/* forward declaration of DCONF state machine */5808static void bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf,5809 enum bfa_dconf_event event);5810static void bfa_dconf_sm_flash_read(struct bfa_dconf_mod_s *dconf,5811 enum bfa_dconf_event event);5812static void bfa_dconf_sm_ready(struct bfa_dconf_mod_s *dconf,5813 enum bfa_dconf_event event);5814static void bfa_dconf_sm_dirty(struct bfa_dconf_mod_s *dconf,5815 enum bfa_dconf_event event);5816static void bfa_dconf_sm_sync(struct bfa_dconf_mod_s *dconf,5817 enum bfa_dconf_event event);5818static void bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf,5819 enum bfa_dconf_event event);5820static void bfa_dconf_sm_iocdown_dirty(struct bfa_dconf_mod_s *dconf,5821 enum bfa_dconf_event event);5822 5823static void bfa_dconf_cbfn(void *dconf, bfa_status_t status);5824static void bfa_dconf_timer(void *cbarg);5825static bfa_status_t bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf);5826static void bfa_dconf_init_cb(void *arg, bfa_status_t status);5827 5828/*5829 * Beginning state of dconf module. Waiting for an event to start.5830 */5831static void5832bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)5833{5834 bfa_status_t bfa_status;5835 bfa_trc(dconf->bfa, event);5836 5837 switch (event) {5838 case BFA_DCONF_SM_INIT:5839 if (dconf->min_cfg) {5840 bfa_trc(dconf->bfa, dconf->min_cfg);5841 bfa_fsm_send_event(&dconf->bfa->iocfc,5842 IOCFC_E_DCONF_DONE);5843 return;5844 }5845 bfa_sm_set_state(dconf, bfa_dconf_sm_flash_read);5846 bfa_timer_start(dconf->bfa, &dconf->timer,5847 bfa_dconf_timer, dconf, 2 * BFA_DCONF_UPDATE_TOV);5848 bfa_status = bfa_flash_read_part(BFA_FLASH(dconf->bfa),5849 BFA_FLASH_PART_DRV, dconf->instance,5850 dconf->dconf,5851 sizeof(struct bfa_dconf_s), 0,5852 bfa_dconf_init_cb, dconf->bfa);5853 if (bfa_status != BFA_STATUS_OK) {5854 bfa_timer_stop(&dconf->timer);5855 bfa_dconf_init_cb(dconf->bfa, BFA_STATUS_FAILED);5856 bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);5857 return;5858 }5859 break;5860 case BFA_DCONF_SM_EXIT:5861 bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE);5862 break;5863 case BFA_DCONF_SM_IOCDISABLE:5864 case BFA_DCONF_SM_WR:5865 case BFA_DCONF_SM_FLASH_COMP:5866 break;5867 default:5868 bfa_sm_fault(dconf->bfa, event);5869 }5870}5871 5872/*5873 * Read flash for dconf entries and make a call back to the driver once done.5874 */5875static void5876bfa_dconf_sm_flash_read(struct bfa_dconf_mod_s *dconf,5877 enum bfa_dconf_event event)5878{5879 bfa_trc(dconf->bfa, event);5880 5881 switch (event) {5882 case BFA_DCONF_SM_FLASH_COMP:5883 bfa_timer_stop(&dconf->timer);5884 bfa_sm_set_state(dconf, bfa_dconf_sm_ready);5885 break;5886 case BFA_DCONF_SM_TIMEOUT:5887 bfa_sm_set_state(dconf, bfa_dconf_sm_ready);5888 bfa_ioc_suspend(&dconf->bfa->ioc);5889 break;5890 case BFA_DCONF_SM_EXIT:5891 bfa_timer_stop(&dconf->timer);5892 bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);5893 bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE);5894 break;5895 case BFA_DCONF_SM_IOCDISABLE:5896 bfa_timer_stop(&dconf->timer);5897 bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);5898 break;5899 default:5900 bfa_sm_fault(dconf->bfa, event);5901 }5902}5903 5904/*5905 * DCONF Module is in ready state. Has completed the initialization.5906 */5907static void5908bfa_dconf_sm_ready(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)5909{5910 bfa_trc(dconf->bfa, event);5911 5912 switch (event) {5913 case BFA_DCONF_SM_WR:5914 bfa_timer_start(dconf->bfa, &dconf->timer,5915 bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);5916 bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);5917 break;5918 case BFA_DCONF_SM_EXIT:5919 bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);5920 bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE);5921 break;5922 case BFA_DCONF_SM_INIT:5923 case BFA_DCONF_SM_IOCDISABLE:5924 break;5925 default:5926 bfa_sm_fault(dconf->bfa, event);5927 }5928}5929 5930/*5931 * entries are dirty, write back to the flash.5932 */5933 5934static void5935bfa_dconf_sm_dirty(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)5936{5937 bfa_trc(dconf->bfa, event);5938 5939 switch (event) {5940 case BFA_DCONF_SM_TIMEOUT:5941 bfa_sm_set_state(dconf, bfa_dconf_sm_sync);5942 bfa_dconf_flash_write(dconf);5943 break;5944 case BFA_DCONF_SM_WR:5945 bfa_timer_stop(&dconf->timer);5946 bfa_timer_start(dconf->bfa, &dconf->timer,5947 bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);5948 break;5949 case BFA_DCONF_SM_EXIT:5950 bfa_timer_stop(&dconf->timer);5951 bfa_timer_start(dconf->bfa, &dconf->timer,5952 bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);5953 bfa_sm_set_state(dconf, bfa_dconf_sm_final_sync);5954 bfa_dconf_flash_write(dconf);5955 break;5956 case BFA_DCONF_SM_FLASH_COMP:5957 break;5958 case BFA_DCONF_SM_IOCDISABLE:5959 bfa_timer_stop(&dconf->timer);5960 bfa_sm_set_state(dconf, bfa_dconf_sm_iocdown_dirty);5961 break;5962 default:5963 bfa_sm_fault(dconf->bfa, event);5964 }5965}5966 5967/*5968 * Sync the dconf entries to the flash.5969 */5970static void5971bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf,5972 enum bfa_dconf_event event)5973{5974 bfa_trc(dconf->bfa, event);5975 5976 switch (event) {5977 case BFA_DCONF_SM_IOCDISABLE:5978 case BFA_DCONF_SM_FLASH_COMP:5979 bfa_timer_stop(&dconf->timer);5980 fallthrough;5981 case BFA_DCONF_SM_TIMEOUT:5982 bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);5983 bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE);5984 break;5985 default:5986 bfa_sm_fault(dconf->bfa, event);5987 }5988}5989 5990static void5991bfa_dconf_sm_sync(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event)5992{5993 bfa_trc(dconf->bfa, event);5994 5995 switch (event) {5996 case BFA_DCONF_SM_FLASH_COMP:5997 bfa_sm_set_state(dconf, bfa_dconf_sm_ready);5998 break;5999 case BFA_DCONF_SM_WR:6000 bfa_timer_start(dconf->bfa, &dconf->timer,6001 bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);6002 bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);6003 break;6004 case BFA_DCONF_SM_EXIT:6005 bfa_timer_start(dconf->bfa, &dconf->timer,6006 bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);6007 bfa_sm_set_state(dconf, bfa_dconf_sm_final_sync);6008 break;6009 case BFA_DCONF_SM_IOCDISABLE:6010 bfa_sm_set_state(dconf, bfa_dconf_sm_iocdown_dirty);6011 break;6012 default:6013 bfa_sm_fault(dconf->bfa, event);6014 }6015}6016 6017static void6018bfa_dconf_sm_iocdown_dirty(struct bfa_dconf_mod_s *dconf,6019 enum bfa_dconf_event event)6020{6021 bfa_trc(dconf->bfa, event);6022 6023 switch (event) {6024 case BFA_DCONF_SM_INIT:6025 bfa_timer_start(dconf->bfa, &dconf->timer,6026 bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV);6027 bfa_sm_set_state(dconf, bfa_dconf_sm_dirty);6028 break;6029 case BFA_DCONF_SM_EXIT:6030 bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);6031 bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE);6032 break;6033 case BFA_DCONF_SM_IOCDISABLE:6034 break;6035 default:6036 bfa_sm_fault(dconf->bfa, event);6037 }6038}6039 6040/*6041 * Compute and return memory needed by DRV_CFG module.6042 */6043void6044bfa_dconf_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,6045 struct bfa_s *bfa)6046{6047 struct bfa_mem_kva_s *dconf_kva = BFA_MEM_DCONF_KVA(bfa);6048 6049 if (cfg->drvcfg.min_cfg)6050 bfa_mem_kva_setup(meminfo, dconf_kva,6051 sizeof(struct bfa_dconf_hdr_s));6052 else6053 bfa_mem_kva_setup(meminfo, dconf_kva,6054 sizeof(struct bfa_dconf_s));6055}6056 6057void6058bfa_dconf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg)6059{6060 struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);6061 6062 dconf->bfad = bfad;6063 dconf->bfa = bfa;6064 dconf->instance = bfa->ioc.port_id;6065 bfa_trc(bfa, dconf->instance);6066 6067 dconf->dconf = (struct bfa_dconf_s *) bfa_mem_kva_curp(dconf);6068 if (cfg->drvcfg.min_cfg) {6069 bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_hdr_s);6070 dconf->min_cfg = BFA_TRUE;6071 } else {6072 dconf->min_cfg = BFA_FALSE;6073 bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_s);6074 }6075 6076 bfa_dconf_read_data_valid(bfa) = BFA_FALSE;6077 bfa_sm_set_state(dconf, bfa_dconf_sm_uninit);6078}6079 6080static void6081bfa_dconf_init_cb(void *arg, bfa_status_t status)6082{6083 struct bfa_s *bfa = arg;6084 struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);6085 6086 if (status == BFA_STATUS_OK) {6087 bfa_dconf_read_data_valid(bfa) = BFA_TRUE;6088 if (dconf->dconf->hdr.signature != BFI_DCONF_SIGNATURE)6089 dconf->dconf->hdr.signature = BFI_DCONF_SIGNATURE;6090 if (dconf->dconf->hdr.version != BFI_DCONF_VERSION)6091 dconf->dconf->hdr.version = BFI_DCONF_VERSION;6092 }6093 bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP);6094 bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_DCONF_DONE);6095}6096 6097void6098bfa_dconf_modinit(struct bfa_s *bfa)6099{6100 struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);6101 bfa_sm_send_event(dconf, BFA_DCONF_SM_INIT);6102}6103 6104static void bfa_dconf_timer(void *cbarg)6105{6106 struct bfa_dconf_mod_s *dconf = cbarg;6107 bfa_sm_send_event(dconf, BFA_DCONF_SM_TIMEOUT);6108}6109 6110void6111bfa_dconf_iocdisable(struct bfa_s *bfa)6112{6113 struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);6114 bfa_sm_send_event(dconf, BFA_DCONF_SM_IOCDISABLE);6115}6116 6117static bfa_status_t6118bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf)6119{6120 bfa_status_t bfa_status;6121 bfa_trc(dconf->bfa, 0);6122 6123 bfa_status = bfa_flash_update_part(BFA_FLASH(dconf->bfa),6124 BFA_FLASH_PART_DRV, dconf->instance,6125 dconf->dconf, sizeof(struct bfa_dconf_s), 0,6126 bfa_dconf_cbfn, dconf);6127 if (bfa_status != BFA_STATUS_OK)6128 WARN_ON(bfa_status);6129 bfa_trc(dconf->bfa, bfa_status);6130 6131 return bfa_status;6132}6133 6134bfa_status_t6135bfa_dconf_update(struct bfa_s *bfa)6136{6137 struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);6138 bfa_trc(dconf->bfa, 0);6139 if (bfa_sm_cmp_state(dconf, bfa_dconf_sm_iocdown_dirty))6140 return BFA_STATUS_FAILED;6141 6142 if (dconf->min_cfg) {6143 bfa_trc(dconf->bfa, dconf->min_cfg);6144 return BFA_STATUS_FAILED;6145 }6146 6147 bfa_sm_send_event(dconf, BFA_DCONF_SM_WR);6148 return BFA_STATUS_OK;6149}6150 6151static void6152bfa_dconf_cbfn(void *arg, bfa_status_t status)6153{6154 struct bfa_dconf_mod_s *dconf = arg;6155 WARN_ON(status);6156 bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP);6157}6158 6159void6160bfa_dconf_modexit(struct bfa_s *bfa)6161{6162 struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa);6163 bfa_sm_send_event(dconf, BFA_DCONF_SM_EXIT);6164}6165 6166/*6167 * FRU specific functions6168 */6169 6170#define BFA_FRU_DMA_BUF_SZ 0x02000 /* 8k dma buffer */6171#define BFA_FRU_CHINOOK_MAX_SIZE 0x100006172#define BFA_FRU_LIGHTNING_MAX_SIZE 0x2006173 6174static void6175bfa_fru_notify(void *cbarg, enum bfa_ioc_event_e event)6176{6177 struct bfa_fru_s *fru = cbarg;6178 6179 bfa_trc(fru, event);6180 6181 switch (event) {6182 case BFA_IOC_E_DISABLED:6183 case BFA_IOC_E_FAILED:6184 if (fru->op_busy) {6185 fru->status = BFA_STATUS_IOC_FAILURE;6186 fru->cbfn(fru->cbarg, fru->status);6187 fru->op_busy = 0;6188 }6189 break;6190 6191 default:6192 break;6193 }6194}6195 6196/*6197 * Send fru write request.6198 *6199 * @param[in] cbarg - callback argument6200 */6201static void6202bfa_fru_write_send(void *cbarg, enum bfi_fru_h2i_msgs msg_type)6203{6204 struct bfa_fru_s *fru = cbarg;6205 struct bfi_fru_write_req_s *msg =6206 (struct bfi_fru_write_req_s *) fru->mb.msg;6207 u32 len;6208 6209 msg->offset = cpu_to_be32(fru->addr_off + fru->offset);6210 len = (fru->residue < BFA_FRU_DMA_BUF_SZ) ?6211 fru->residue : BFA_FRU_DMA_BUF_SZ;6212 msg->length = cpu_to_be32(len);6213 6214 /*6215 * indicate if it's the last msg of the whole write operation6216 */6217 msg->last = (len == fru->residue) ? 1 : 0;6218 6219 msg->trfr_cmpl = (len == fru->residue) ? fru->trfr_cmpl : 0;6220 bfi_h2i_set(msg->mh, BFI_MC_FRU, msg_type, bfa_ioc_portid(fru->ioc));6221 bfa_alen_set(&msg->alen, len, fru->dbuf_pa);6222 6223 memcpy(fru->dbuf_kva, fru->ubuf + fru->offset, len);6224 bfa_ioc_mbox_queue(fru->ioc, &fru->mb);6225 6226 fru->residue -= len;6227 fru->offset += len;6228}6229 6230/*6231 * Send fru read request.6232 *6233 * @param[in] cbarg - callback argument6234 */6235static void6236bfa_fru_read_send(void *cbarg, enum bfi_fru_h2i_msgs msg_type)6237{6238 struct bfa_fru_s *fru = cbarg;6239 struct bfi_fru_read_req_s *msg =6240 (struct bfi_fru_read_req_s *) fru->mb.msg;6241 u32 len;6242 6243 msg->offset = cpu_to_be32(fru->addr_off + fru->offset);6244 len = (fru->residue < BFA_FRU_DMA_BUF_SZ) ?6245 fru->residue : BFA_FRU_DMA_BUF_SZ;6246 msg->length = cpu_to_be32(len);6247 bfi_h2i_set(msg->mh, BFI_MC_FRU, msg_type, bfa_ioc_portid(fru->ioc));6248 bfa_alen_set(&msg->alen, len, fru->dbuf_pa);6249 bfa_ioc_mbox_queue(fru->ioc, &fru->mb);6250}6251 6252/*6253 * Flash memory info API.6254 *6255 * @param[in] mincfg - minimal cfg variable6256 */6257u326258bfa_fru_meminfo(bfa_boolean_t mincfg)6259{6260 /* min driver doesn't need fru */6261 if (mincfg)6262 return 0;6263 6264 return BFA_ROUNDUP(BFA_FRU_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);6265}6266 6267/*6268 * Flash attach API.6269 *6270 * @param[in] fru - fru structure6271 * @param[in] ioc - ioc structure6272 * @param[in] dev - device structure6273 * @param[in] trcmod - trace module6274 * @param[in] logmod - log module6275 */6276void6277bfa_fru_attach(struct bfa_fru_s *fru, struct bfa_ioc_s *ioc, void *dev,6278 struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg)6279{6280 fru->ioc = ioc;6281 fru->trcmod = trcmod;6282 fru->cbfn = NULL;6283 fru->cbarg = NULL;6284 fru->op_busy = 0;6285 6286 bfa_ioc_mbox_regisr(fru->ioc, BFI_MC_FRU, bfa_fru_intr, fru);6287 bfa_q_qe_init(&fru->ioc_notify);6288 bfa_ioc_notify_init(&fru->ioc_notify, bfa_fru_notify, fru);6289 list_add_tail(&fru->ioc_notify.qe, &fru->ioc->notify_q);6290 6291 /* min driver doesn't need fru */6292 if (mincfg) {6293 fru->dbuf_kva = NULL;6294 fru->dbuf_pa = 0;6295 }6296}6297 6298/*6299 * Claim memory for fru6300 *6301 * @param[in] fru - fru structure6302 * @param[in] dm_kva - pointer to virtual memory address6303 * @param[in] dm_pa - frusical memory address6304 * @param[in] mincfg - minimal cfg variable6305 */6306void6307bfa_fru_memclaim(struct bfa_fru_s *fru, u8 *dm_kva, u64 dm_pa,6308 bfa_boolean_t mincfg)6309{6310 if (mincfg)6311 return;6312 6313 fru->dbuf_kva = dm_kva;6314 fru->dbuf_pa = dm_pa;6315 memset(fru->dbuf_kva, 0, BFA_FRU_DMA_BUF_SZ);6316 dm_kva += BFA_ROUNDUP(BFA_FRU_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);6317 dm_pa += BFA_ROUNDUP(BFA_FRU_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);6318}6319 6320/*6321 * Update fru vpd image.6322 *6323 * @param[in] fru - fru structure6324 * @param[in] buf - update data buffer6325 * @param[in] len - data buffer length6326 * @param[in] offset - offset relative to starting address6327 * @param[in] cbfn - callback function6328 * @param[in] cbarg - callback argument6329 *6330 * Return status.6331 */6332bfa_status_t6333bfa_fruvpd_update(struct bfa_fru_s *fru, void *buf, u32 len, u32 offset,6334 bfa_cb_fru_t cbfn, void *cbarg, u8 trfr_cmpl)6335{6336 bfa_trc(fru, BFI_FRUVPD_H2I_WRITE_REQ);6337 bfa_trc(fru, len);6338 bfa_trc(fru, offset);6339 6340 if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2 &&6341 fru->ioc->attr->card_type != BFA_MFG_TYPE_CHINOOK2)6342 return BFA_STATUS_FRU_NOT_PRESENT;6343 6344 if (fru->ioc->attr->card_type != BFA_MFG_TYPE_CHINOOK)6345 return BFA_STATUS_CMD_NOTSUPP;6346 6347 if (!bfa_ioc_is_operational(fru->ioc))6348 return BFA_STATUS_IOC_NON_OP;6349 6350 if (fru->op_busy) {6351 bfa_trc(fru, fru->op_busy);6352 return BFA_STATUS_DEVBUSY;6353 }6354 6355 fru->op_busy = 1;6356 6357 fru->cbfn = cbfn;6358 fru->cbarg = cbarg;6359 fru->residue = len;6360 fru->offset = 0;6361 fru->addr_off = offset;6362 fru->ubuf = buf;6363 fru->trfr_cmpl = trfr_cmpl;6364 6365 bfa_fru_write_send(fru, BFI_FRUVPD_H2I_WRITE_REQ);6366 6367 return BFA_STATUS_OK;6368}6369 6370/*6371 * Read fru vpd image.6372 *6373 * @param[in] fru - fru structure6374 * @param[in] buf - read data buffer6375 * @param[in] len - data buffer length6376 * @param[in] offset - offset relative to starting address6377 * @param[in] cbfn - callback function6378 * @param[in] cbarg - callback argument6379 *6380 * Return status.6381 */6382bfa_status_t6383bfa_fruvpd_read(struct bfa_fru_s *fru, void *buf, u32 len, u32 offset,6384 bfa_cb_fru_t cbfn, void *cbarg)6385{6386 bfa_trc(fru, BFI_FRUVPD_H2I_READ_REQ);6387 bfa_trc(fru, len);6388 bfa_trc(fru, offset);6389 6390 if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2)6391 return BFA_STATUS_FRU_NOT_PRESENT;6392 6393 if (fru->ioc->attr->card_type != BFA_MFG_TYPE_CHINOOK &&6394 fru->ioc->attr->card_type != BFA_MFG_TYPE_CHINOOK2)6395 return BFA_STATUS_CMD_NOTSUPP;6396 6397 if (!bfa_ioc_is_operational(fru->ioc))6398 return BFA_STATUS_IOC_NON_OP;6399 6400 if (fru->op_busy) {6401 bfa_trc(fru, fru->op_busy);6402 return BFA_STATUS_DEVBUSY;6403 }6404 6405 fru->op_busy = 1;6406 6407 fru->cbfn = cbfn;6408 fru->cbarg = cbarg;6409 fru->residue = len;6410 fru->offset = 0;6411 fru->addr_off = offset;6412 fru->ubuf = buf;6413 bfa_fru_read_send(fru, BFI_FRUVPD_H2I_READ_REQ);6414 6415 return BFA_STATUS_OK;6416}6417 6418/*6419 * Get maximum size fru vpd image.6420 *6421 * @param[in] fru - fru structure6422 * @param[out] size - maximum size of fru vpd data6423 *6424 * Return status.6425 */6426bfa_status_t6427bfa_fruvpd_get_max_size(struct bfa_fru_s *fru, u32 *max_size)6428{6429 if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2)6430 return BFA_STATUS_FRU_NOT_PRESENT;6431 6432 if (!bfa_ioc_is_operational(fru->ioc))6433 return BFA_STATUS_IOC_NON_OP;6434 6435 if (fru->ioc->attr->card_type == BFA_MFG_TYPE_CHINOOK ||6436 fru->ioc->attr->card_type == BFA_MFG_TYPE_CHINOOK2)6437 *max_size = BFA_FRU_CHINOOK_MAX_SIZE;6438 else6439 return BFA_STATUS_CMD_NOTSUPP;6440 return BFA_STATUS_OK;6441}6442/*6443 * tfru write.6444 *6445 * @param[in] fru - fru structure6446 * @param[in] buf - update data buffer6447 * @param[in] len - data buffer length6448 * @param[in] offset - offset relative to starting address6449 * @param[in] cbfn - callback function6450 * @param[in] cbarg - callback argument6451 *6452 * Return status.6453 */6454bfa_status_t6455bfa_tfru_write(struct bfa_fru_s *fru, void *buf, u32 len, u32 offset,6456 bfa_cb_fru_t cbfn, void *cbarg)6457{6458 bfa_trc(fru, BFI_TFRU_H2I_WRITE_REQ);6459 bfa_trc(fru, len);6460 bfa_trc(fru, offset);6461 bfa_trc(fru, *((u8 *) buf));6462 6463 if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2)6464 return BFA_STATUS_FRU_NOT_PRESENT;6465 6466 if (!bfa_ioc_is_operational(fru->ioc))6467 return BFA_STATUS_IOC_NON_OP;6468 6469 if (fru->op_busy) {6470 bfa_trc(fru, fru->op_busy);6471 return BFA_STATUS_DEVBUSY;6472 }6473 6474 fru->op_busy = 1;6475 6476 fru->cbfn = cbfn;6477 fru->cbarg = cbarg;6478 fru->residue = len;6479 fru->offset = 0;6480 fru->addr_off = offset;6481 fru->ubuf = buf;6482 6483 bfa_fru_write_send(fru, BFI_TFRU_H2I_WRITE_REQ);6484 6485 return BFA_STATUS_OK;6486}6487 6488/*6489 * tfru read.6490 *6491 * @param[in] fru - fru structure6492 * @param[in] buf - read data buffer6493 * @param[in] len - data buffer length6494 * @param[in] offset - offset relative to starting address6495 * @param[in] cbfn - callback function6496 * @param[in] cbarg - callback argument6497 *6498 * Return status.6499 */6500bfa_status_t6501bfa_tfru_read(struct bfa_fru_s *fru, void *buf, u32 len, u32 offset,6502 bfa_cb_fru_t cbfn, void *cbarg)6503{6504 bfa_trc(fru, BFI_TFRU_H2I_READ_REQ);6505 bfa_trc(fru, len);6506 bfa_trc(fru, offset);6507 6508 if (fru->ioc->asic_gen != BFI_ASIC_GEN_CT2)6509 return BFA_STATUS_FRU_NOT_PRESENT;6510 6511 if (!bfa_ioc_is_operational(fru->ioc))6512 return BFA_STATUS_IOC_NON_OP;6513 6514 if (fru->op_busy) {6515 bfa_trc(fru, fru->op_busy);6516 return BFA_STATUS_DEVBUSY;6517 }6518 6519 fru->op_busy = 1;6520 6521 fru->cbfn = cbfn;6522 fru->cbarg = cbarg;6523 fru->residue = len;6524 fru->offset = 0;6525 fru->addr_off = offset;6526 fru->ubuf = buf;6527 bfa_fru_read_send(fru, BFI_TFRU_H2I_READ_REQ);6528 6529 return BFA_STATUS_OK;6530}6531 6532/*6533 * Process fru response messages upon receiving interrupts.6534 *6535 * @param[in] fruarg - fru structure6536 * @param[in] msg - message structure6537 */6538void6539bfa_fru_intr(void *fruarg, struct bfi_mbmsg_s *msg)6540{6541 struct bfa_fru_s *fru = fruarg;6542 struct bfi_fru_rsp_s *rsp = (struct bfi_fru_rsp_s *)msg;6543 u32 status;6544 6545 bfa_trc(fru, msg->mh.msg_id);6546 6547 if (!fru->op_busy) {6548 /*6549 * receiving response after ioc failure6550 */6551 bfa_trc(fru, 0x9999);6552 return;6553 }6554 6555 switch (msg->mh.msg_id) {6556 case BFI_FRUVPD_I2H_WRITE_RSP:6557 case BFI_TFRU_I2H_WRITE_RSP:6558 status = be32_to_cpu(rsp->status);6559 bfa_trc(fru, status);6560 6561 if (status != BFA_STATUS_OK || fru->residue == 0) {6562 fru->status = status;6563 fru->op_busy = 0;6564 if (fru->cbfn)6565 fru->cbfn(fru->cbarg, fru->status);6566 } else {6567 bfa_trc(fru, fru->offset);6568 if (msg->mh.msg_id == BFI_FRUVPD_I2H_WRITE_RSP)6569 bfa_fru_write_send(fru,6570 BFI_FRUVPD_H2I_WRITE_REQ);6571 else6572 bfa_fru_write_send(fru,6573 BFI_TFRU_H2I_WRITE_REQ);6574 }6575 break;6576 case BFI_FRUVPD_I2H_READ_RSP:6577 case BFI_TFRU_I2H_READ_RSP:6578 status = be32_to_cpu(rsp->status);6579 bfa_trc(fru, status);6580 6581 if (status != BFA_STATUS_OK) {6582 fru->status = status;6583 fru->op_busy = 0;6584 if (fru->cbfn)6585 fru->cbfn(fru->cbarg, fru->status);6586 } else {6587 u32 len = be32_to_cpu(rsp->length);6588 6589 bfa_trc(fru, fru->offset);6590 bfa_trc(fru, len);6591 6592 memcpy(fru->ubuf + fru->offset, fru->dbuf_kva, len);6593 fru->residue -= len;6594 fru->offset += len;6595 6596 if (fru->residue == 0) {6597 fru->status = status;6598 fru->op_busy = 0;6599 if (fru->cbfn)6600 fru->cbfn(fru->cbarg, fru->status);6601 } else {6602 if (msg->mh.msg_id == BFI_FRUVPD_I2H_READ_RSP)6603 bfa_fru_read_send(fru,6604 BFI_FRUVPD_H2I_READ_REQ);6605 else6606 bfa_fru_read_send(fru,6607 BFI_TFRU_H2I_READ_REQ);6608 }6609 }6610 break;6611 default:6612 WARN_ON(1);6613 }6614}6615 6616/*6617 * register definitions6618 */6619#define FLI_CMD_REG 0x0001d0006620#define FLI_RDDATA_REG 0x0001d0106621#define FLI_ADDR_REG 0x0001d0046622#define FLI_DEV_STATUS_REG 0x0001d0146623 6624#define BFA_FLASH_FIFO_SIZE 128 /* fifo size */6625#define BFA_FLASH_CHECK_MAX 10000 /* max # of status check */6626#define BFA_FLASH_BLOCKING_OP_MAX 1000000 /* max # of blocking op check */6627#define BFA_FLASH_WIP_MASK 0x01 /* write in progress bit mask */6628 6629enum bfa_flash_cmd {6630 BFA_FLASH_FAST_READ = 0x0b, /* fast read */6631 BFA_FLASH_READ_STATUS = 0x05, /* read status */6632};6633 6634/*6635 * Hardware error definition6636 */6637enum bfa_flash_err {6638 BFA_FLASH_NOT_PRESENT = -1, /*!< flash not present */6639 BFA_FLASH_UNINIT = -2, /*!< flash not initialized */6640 BFA_FLASH_BAD = -3, /*!< flash bad */6641 BFA_FLASH_BUSY = -4, /*!< flash busy */6642 BFA_FLASH_ERR_CMD_ACT = -5, /*!< command active never cleared */6643 BFA_FLASH_ERR_FIFO_CNT = -6, /*!< fifo count never cleared */6644 BFA_FLASH_ERR_WIP = -7, /*!< write-in-progress never cleared */6645 BFA_FLASH_ERR_TIMEOUT = -8, /*!< fli timeout */6646 BFA_FLASH_ERR_LEN = -9, /*!< invalid length */6647};6648 6649/*6650 * Flash command register data structure6651 */6652union bfa_flash_cmd_reg_u {6653 struct {6654#ifdef __BIG_ENDIAN6655 u32 act:1;6656 u32 rsv:1;6657 u32 write_cnt:9;6658 u32 read_cnt:9;6659 u32 addr_cnt:4;6660 u32 cmd:8;6661#else6662 u32 cmd:8;6663 u32 addr_cnt:4;6664 u32 read_cnt:9;6665 u32 write_cnt:9;6666 u32 rsv:1;6667 u32 act:1;6668#endif6669 } r;6670 u32 i;6671};6672 6673/*6674 * Flash device status register data structure6675 */6676union bfa_flash_dev_status_reg_u {6677 struct {6678#ifdef __BIG_ENDIAN6679 u32 rsv:21;6680 u32 fifo_cnt:6;6681 u32 busy:1;6682 u32 init_status:1;6683 u32 present:1;6684 u32 bad:1;6685 u32 good:1;6686#else6687 u32 good:1;6688 u32 bad:1;6689 u32 present:1;6690 u32 init_status:1;6691 u32 busy:1;6692 u32 fifo_cnt:6;6693 u32 rsv:21;6694#endif6695 } r;6696 u32 i;6697};6698 6699/*6700 * Flash address register data structure6701 */6702union bfa_flash_addr_reg_u {6703 struct {6704#ifdef __BIG_ENDIAN6705 u32 addr:24;6706 u32 dummy:8;6707#else6708 u32 dummy:8;6709 u32 addr:24;6710#endif6711 } r;6712 u32 i;6713};6714 6715/*6716 * dg flash_raw_private Flash raw private functions6717 */6718static void6719bfa_flash_set_cmd(void __iomem *pci_bar, u8 wr_cnt,6720 u8 rd_cnt, u8 ad_cnt, u8 op)6721{6722 union bfa_flash_cmd_reg_u cmd;6723 6724 cmd.i = 0;6725 cmd.r.act = 1;6726 cmd.r.write_cnt = wr_cnt;6727 cmd.r.read_cnt = rd_cnt;6728 cmd.r.addr_cnt = ad_cnt;6729 cmd.r.cmd = op;6730 writel(cmd.i, (pci_bar + FLI_CMD_REG));6731}6732 6733static void6734bfa_flash_set_addr(void __iomem *pci_bar, u32 address)6735{6736 union bfa_flash_addr_reg_u addr;6737 6738 addr.r.addr = address & 0x00ffffff;6739 addr.r.dummy = 0;6740 writel(addr.i, (pci_bar + FLI_ADDR_REG));6741}6742 6743static int6744bfa_flash_cmd_act_check(void __iomem *pci_bar)6745{6746 union bfa_flash_cmd_reg_u cmd;6747 6748 cmd.i = readl(pci_bar + FLI_CMD_REG);6749 6750 if (cmd.r.act)6751 return BFA_FLASH_ERR_CMD_ACT;6752 6753 return 0;6754}6755 6756/*6757 * @brief6758 * Flush FLI data fifo.6759 *6760 * @param[in] pci_bar - pci bar address6761 * @param[in] dev_status - device status6762 *6763 * Return 0 on success, negative error number on error.6764 */6765static u326766bfa_flash_fifo_flush(void __iomem *pci_bar)6767{6768 u32 i;6769 union bfa_flash_dev_status_reg_u dev_status;6770 6771 dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG);6772 6773 if (!dev_status.r.fifo_cnt)6774 return 0;6775 6776 /* fifo counter in terms of words */6777 for (i = 0; i < dev_status.r.fifo_cnt; i++)6778 readl(pci_bar + FLI_RDDATA_REG);6779 6780 /*6781 * Check the device status. It may take some time.6782 */6783 for (i = 0; i < BFA_FLASH_CHECK_MAX; i++) {6784 dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG);6785 if (!dev_status.r.fifo_cnt)6786 break;6787 }6788 6789 if (dev_status.r.fifo_cnt)6790 return BFA_FLASH_ERR_FIFO_CNT;6791 6792 return 0;6793}6794 6795/*6796 * @brief6797 * Read flash status.6798 *6799 * @param[in] pci_bar - pci bar address6800 *6801 * Return 0 on success, negative error number on error.6802*/6803static u326804bfa_flash_status_read(void __iomem *pci_bar)6805{6806 union bfa_flash_dev_status_reg_u dev_status;6807 int status;6808 u32 ret_status;6809 int i;6810 6811 status = bfa_flash_fifo_flush(pci_bar);6812 if (status < 0)6813 return status;6814 6815 bfa_flash_set_cmd(pci_bar, 0, 4, 0, BFA_FLASH_READ_STATUS);6816 6817 for (i = 0; i < BFA_FLASH_CHECK_MAX; i++) {6818 status = bfa_flash_cmd_act_check(pci_bar);6819 if (!status)6820 break;6821 }6822 6823 if (status)6824 return status;6825 6826 dev_status.i = readl(pci_bar + FLI_DEV_STATUS_REG);6827 if (!dev_status.r.fifo_cnt)6828 return BFA_FLASH_BUSY;6829 6830 ret_status = readl(pci_bar + FLI_RDDATA_REG);6831 ret_status >>= 24;6832 6833 status = bfa_flash_fifo_flush(pci_bar);6834 if (status < 0)6835 return status;6836 6837 return ret_status;6838}6839 6840/*6841 * @brief6842 * Start flash read operation.6843 *6844 * @param[in] pci_bar - pci bar address6845 * @param[in] offset - flash address offset6846 * @param[in] len - read data length6847 * @param[in] buf - read data buffer6848 *6849 * Return 0 on success, negative error number on error.6850 */6851static u326852bfa_flash_read_start(void __iomem *pci_bar, u32 offset, u32 len,6853 char *buf)6854{6855 int status;6856 6857 /*6858 * len must be mutiple of 4 and not exceeding fifo size6859 */6860 if (len == 0 || len > BFA_FLASH_FIFO_SIZE || (len & 0x03) != 0)6861 return BFA_FLASH_ERR_LEN;6862 6863 /*6864 * check status6865 */6866 status = bfa_flash_status_read(pci_bar);6867 if (status == BFA_FLASH_BUSY)6868 status = bfa_flash_status_read(pci_bar);6869 6870 if (status < 0)6871 return status;6872 6873 /*6874 * check if write-in-progress bit is cleared6875 */6876 if (status & BFA_FLASH_WIP_MASK)6877 return BFA_FLASH_ERR_WIP;6878 6879 bfa_flash_set_addr(pci_bar, offset);6880 6881 bfa_flash_set_cmd(pci_bar, 0, (u8)len, 4, BFA_FLASH_FAST_READ);6882 6883 return 0;6884}6885 6886/*6887 * @brief6888 * Check flash read operation.6889 *6890 * @param[in] pci_bar - pci bar address6891 *6892 * Return flash device status, 1 if busy, 0 if not.6893 */6894static u326895bfa_flash_read_check(void __iomem *pci_bar)6896{6897 if (bfa_flash_cmd_act_check(pci_bar))6898 return 1;6899 6900 return 0;6901}6902 6903/*6904 * @brief6905 * End flash read operation.6906 *6907 * @param[in] pci_bar - pci bar address6908 * @param[in] len - read data length6909 * @param[in] buf - read data buffer6910 *6911 */6912static void6913bfa_flash_read_end(void __iomem *pci_bar, u32 len, char *buf)6914{6915 6916 u32 i;6917 6918 /*6919 * read data fifo up to 32 words6920 */6921 for (i = 0; i < len; i += 4) {6922 u32 w = readl(pci_bar + FLI_RDDATA_REG);6923 *((u32 *) (buf + i)) = swab32(w);6924 }6925 6926 bfa_flash_fifo_flush(pci_bar);6927}6928 6929/*6930 * @brief6931 * Perform flash raw read.6932 *6933 * @param[in] pci_bar - pci bar address6934 * @param[in] offset - flash partition address offset6935 * @param[in] buf - read data buffer6936 * @param[in] len - read data length6937 *6938 * Return status.6939 */6940 6941 6942#define FLASH_BLOCKING_OP_MAX 5006943#define FLASH_SEM_LOCK_REG 0x188206944 6945static int6946bfa_raw_sem_get(void __iomem *bar)6947{6948 int locked;6949 6950 locked = readl((bar + FLASH_SEM_LOCK_REG));6951 return !locked;6952 6953}6954 6955static bfa_status_t6956bfa_flash_sem_get(void __iomem *bar)6957{6958 u32 n = FLASH_BLOCKING_OP_MAX;6959 6960 while (!bfa_raw_sem_get(bar)) {6961 if (--n <= 0)6962 return BFA_STATUS_BADFLASH;6963 mdelay(10);6964 }6965 return BFA_STATUS_OK;6966}6967 6968static void6969bfa_flash_sem_put(void __iomem *bar)6970{6971 writel(0, (bar + FLASH_SEM_LOCK_REG));6972}6973 6974bfa_status_t6975bfa_flash_raw_read(void __iomem *pci_bar, u32 offset, char *buf,6976 u32 len)6977{6978 u32 n;6979 int status;6980 u32 off, l, s, residue, fifo_sz;6981 6982 residue = len;6983 off = 0;6984 fifo_sz = BFA_FLASH_FIFO_SIZE;6985 status = bfa_flash_sem_get(pci_bar);6986 if (status != BFA_STATUS_OK)6987 return status;6988 6989 while (residue) {6990 s = offset + off;6991 n = s / fifo_sz;6992 l = (n + 1) * fifo_sz - s;6993 if (l > residue)6994 l = residue;6995 6996 status = bfa_flash_read_start(pci_bar, offset + off, l,6997 &buf[off]);6998 if (status < 0) {6999 bfa_flash_sem_put(pci_bar);7000 return BFA_STATUS_FAILED;7001 }7002 7003 n = BFA_FLASH_BLOCKING_OP_MAX;7004 while (bfa_flash_read_check(pci_bar)) {7005 if (--n <= 0) {7006 bfa_flash_sem_put(pci_bar);7007 return BFA_STATUS_FAILED;7008 }7009 }7010 7011 bfa_flash_read_end(pci_bar, l, &buf[off]);7012 7013 residue -= l;7014 off += l;7015 }7016 bfa_flash_sem_put(pci_bar);7017 7018 return BFA_STATUS_OK;7019}7020