1 /******************************************************************************* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * Copyright 2014 QLogic Corporation 22 * The contents of this file are subject to the terms of the 23 * QLogic End User License (the "License"). 24 * You may not use this file except in compliance with the License. 25 * 26 * You can obtain a copy of the License at 27 * http://www.qlogic.com/Resources/Documents/DriverDownloadHelp/ 28 * QLogic_End_User_Software_License.txt 29 * See the License for the specific language governing permissions 30 * and limitations under the License. 31 * 32 * 33 * Module Description: 34 * 35 * 36 * History: 37 * 11/26/07 Alon Elhanani Inception. 38 ******************************************************************************/ 39 40 #include "lm5710.h" 41 #include "license.h" 42 #include "mcp_shmem.h" 43 #include "debug.h" 44 45 #define MCP_EMUL_TIMEOUT 200000 /* 200 ms (in us) */ 46 #define MCP_TIMEOUT 5000000 /* 5 seconds (in us) */ 47 #define MCP_ONE_TIMEOUT 100000 /* 100 ms (in us) */ 48 49 /** 50 * Waits for MCP_ONE_TIMEOUT or MCP_ONE_TIMEOUT*10, 51 * depending on the HW type. 52 * 53 * @param pdev 54 */ 55 static __inline void lm_mcp_wait_one ( 56 IN struct _lm_device_t * pdev 57 ) 58 { 59 /* special handling for emulation and FPGA, 60 wait 10 times longer */ 61 if (CHIP_REV_IS_SLOW(pdev)) { 62 mm_wait(pdev, MCP_ONE_TIMEOUT*10); 63 } else { 64 mm_wait(pdev, MCP_ONE_TIMEOUT); 65 } 66 } 67 68 69 #if !defined(b710) 70 71 /** 72 * Prepare CLP to MCP reset. 73 * 74 * @param pdev Device handle 75 * @param magic_val Old value of `magic' bit. 76 */ 77 void lm_clp_reset_prep( 78 IN struct _lm_device_t * pdev, 79 OUT u32_t * magic_val 80 ) 81 { 82 u32_t val = 0; 83 u32_t offset; 84 85 #define SHARED_MF_CLP_MAGIC 0x80000000 /* `magic' bit */ 86 87 ASSERT_STATIC(sizeof(struct mf_cfg) % sizeof(u32_t) == 0); 88 89 /* Do some magic... */ 90 offset = OFFSETOF(mf_cfg_t, shared_mf_config.clp_mb); 91 LM_MFCFG_READ(pdev, offset, &val); 92 *magic_val = val & SHARED_MF_CLP_MAGIC; 93 LM_MFCFG_WRITE(pdev, offset, val | SHARED_MF_CLP_MAGIC); 94 } 95 96 /** 97 * Restore the value of the `magic' bit. 98 * 99 * @param pdev Device handle. 100 * @param magic_val Old value of the `magic' bit. 101 */ 102 void lm_clp_reset_done( 103 IN struct _lm_device_t * pdev, 104 IN u32_t magic_val 105 ) 106 { 107 u32_t val = 0; 108 u32_t offset; 109 110 /* Restore the `magic' bit value... */ 111 offset = OFFSETOF(mf_cfg_t, shared_mf_config.clp_mb); 112 LM_MFCFG_READ(pdev, offset, &val); 113 LM_MFCFG_WRITE(pdev, offset, (val & (~SHARED_MF_CLP_MAGIC)) | magic_val); 114 } 115 116 #endif // !b710 117 118 u8_t lm_is_mcp_detected( 119 IN struct _lm_device_t *pdev 120 ) 121 { 122 return pdev->hw_info.mcp_detected; 123 } 124 125 /** 126 * @Description 127 * Prepares for MCP reset: takes care of CLP configurations 128 * (saves it aside to resotre later) . 129 * 130 * @param pdev 131 * @param magic_val Old value of 'magic' bit. 132 */ 133 lm_status_t lm_reset_mcp_prep(lm_device_t *pdev, u32_t * magic_val) 134 { 135 u32_t shmem; 136 u32_t validity_offset; 137 138 /* Set `magic' bit in order to save MF config */ 139 if (!CHIP_IS_E1(pdev)) 140 { 141 lm_clp_reset_prep(pdev, magic_val); 142 } 143 144 /* Get shmem offset */ 145 shmem = REG_RD(pdev, MISC_REG_SHARED_MEM_ADDR); 146 validity_offset = OFFSETOF(shmem_region_t, validity_map[0]); 147 148 /* Clear validity map flags */ 149 if( shmem > 0 ) 150 { 151 REG_WR(pdev, shmem + validity_offset, 0); 152 } 153 154 return LM_STATUS_SUCCESS; 155 } 156 157 lm_status_t lm_reset_mcp_comp(lm_device_t *pdev, u32_t magic_val) 158 { 159 lm_status_t lm_status = LM_STATUS_SUCCESS; 160 u32_t shmem_sig_timeout = 0; 161 u32_t validity_offset = 0; 162 u32_t shmem = 0; 163 u32_t val = 0; 164 u32_t cnt = 0; 165 166 #ifdef _VBD_CMD_ 167 return LM_STATUS_SUCCESS; 168 #endif 169 170 /* Get shmem offset */ 171 shmem = REG_RD(pdev, MISC_REG_SHARED_MEM_ADDR); 172 if( shmem == 0 ) { 173 DbgMessage(pdev, FATAL, "Shmem 0 return failure\n"); 174 lm_status = LM_STATUS_FAILURE; 175 goto exit_lbl; 176 } 177 178 ASSERT_STATIC(0 != MCP_ONE_TIMEOUT); 179 180 if (CHIP_REV_IS_EMUL(pdev)) 181 shmem_sig_timeout = MCP_EMUL_TIMEOUT / MCP_ONE_TIMEOUT; // 200ms 182 else 183 shmem_sig_timeout = MCP_TIMEOUT / MCP_ONE_TIMEOUT; // 5sec 184 185 validity_offset = OFFSETOF(shmem_region_t, validity_map[0]); 186 187 /* Wait for MCP to come up */ 188 for(cnt = 0; cnt < shmem_sig_timeout; cnt++) 189 { 190 /* TBD: its best to check validity map of last port. currently checks on port 0. */ 191 val = REG_RD(pdev, shmem + validity_offset); 192 DbgMessage(pdev, INFORM, "shmem 0x%x validity map(0x%x)=0x%x\n", shmem, shmem + validity_offset, val); 193 194 /* check that shared memory is valid. */ 195 if((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) == 196 (SHR_MEM_VALIDITY_DEV_INFO|SHR_MEM_VALIDITY_MB)) { 197 break; 198 } 199 200 lm_mcp_wait_one(pdev); 201 } 202 203 DbgMessage(pdev, INFORM , "Cnt=%d Shmem validity map 0x%x\n",cnt, val); 204 205 /* Check that shared memory is valid. This indicates that MCP is up. */ 206 if((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) != 207 (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) 208 { 209 DbgMessage(pdev, FATAL, "Shmem signature not present. MCP is not up !!\n"); 210 lm_status = LM_STATUS_FAILURE; 211 goto exit_lbl; 212 } 213 214 exit_lbl: 215 216 if (!CHIP_IS_E1(pdev)) 217 { 218 /* Restore `magic' bit value */ 219 lm_clp_reset_done(pdev, magic_val); 220 } 221 222 return lm_status; 223 } 224 225 lm_status_t lm_reset_mcp( 226 IN struct _lm_device_t *pdev 227 ) 228 { 229 230 u32_t magic_val = 0; 231 u32_t val, retries=0; 232 lm_status_t lm_status = LM_STATUS_SUCCESS; 233 234 DbgMessage(pdev, VERBOSE, "Entered lm_reset_mcp\n"); 235 236 lm_reset_mcp_prep(pdev, &magic_val); 237 238 /* wait up to 3 seconds to get all locks. Whatsoever, reset mcp afterwards */ 239 do { 240 REG_WR(pdev, MISC_REG_DRIVER_CONTROL_15 + 4, 0xffffffff); 241 val = REG_RD(pdev, MISC_REG_DRIVER_CONTROL_15); 242 mm_wait(pdev, 1); 243 } while ((val != 0xffffffff) && (++retries < 3000000)); 244 245 /* Reset the MCP */ 246 REG_WR(pdev, GRCBASE_MISC+ MISC_REGISTERS_RESET_REG_2_CLEAR, 247 MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_REG_HARD_CORE | 248 MISC_REGISTERS_RESET_REG_2_RST_MCP_N_HARD_CORE_RST_B | 249 MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_CMN_CPU | 250 MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_CMN_CORE); 251 252 /* release the locks taken */ 253 REG_WR(pdev, MISC_REG_DRIVER_CONTROL_15, 0xffffffff); 254 255 mm_wait(pdev, 100000); 256 257 // No need to wait here a minimum time, since the mcp_comp will 258 // returns only when mcp is ready. 259 lm_status = lm_reset_mcp_comp(pdev, magic_val); 260 261 return lm_status; 262 } 263 264 //acquire split MCP access lock register 265 lm_status_t 266 acquire_split_alr( 267 lm_device_t *pdev) 268 { 269 lm_status_t lm_status; 270 u32_t j, cnt; 271 u32_t val_wr, val_rd; 272 273 DbgMessage(pdev, INFORM, "acquire_split_alr() - %d START!\n", FUNC_ID(pdev) ); 274 275 //Adjust timeout for our emulation needs 276 cnt = 30000 * 100; 277 val_wr = 1UL << 31; 278 val_rd = 0; 279 280 //acquire lock using mcpr_access_lock SPLIT register 281 282 for(j = 0; j < cnt*10; j++) 283 { 284 REG_WR(pdev, GRCBASE_MCP + 0x9c, val_wr); 285 val_rd = REG_RD(pdev, GRCBASE_MCP + 0x9c); 286 if (val_rd & (1UL << 31)) 287 { 288 break; 289 } 290 291 mm_wait(pdev, 5); 292 } 293 294 if(val_rd & (1UL << 31)) 295 { 296 lm_status = LM_STATUS_SUCCESS; 297 } 298 else 299 { 300 DbgBreakMsg("Cannot get access to nvram interface.\n"); 301 302 lm_status = LM_STATUS_BUSY; 303 } 304 305 DbgMessage(pdev, INFORM, "acquire_split_alr() - %d END!\n", FUNC_ID(pdev) ); 306 307 return lm_status; 308 } 309 310 //Release split MCP access lock register 311 void 312 release_split_alr( 313 lm_device_t *pdev) 314 { 315 u32_t val = 0; 316 317 DbgMessage(pdev, INFORM, "release_split_alr() - %d START!\n", FUNC_ID(pdev) ); 318 319 //This is only a sanity check, can remove later in free build. 320 val= REG_RD(pdev, GRCBASE_MCP + 0x9c); 321 DbgBreakIf(!(val & (1L << 31))); 322 323 val = 0; 324 325 //release mcpr_access_lock SPLIT register 326 REG_WR(pdev, GRCBASE_MCP + 0x9c, val); 327 DbgMessage(pdev, INFORM, "release_split_alr() - %d END!\n", FUNC_ID(pdev) ); 328 } /* release_nvram_lock */ 329 330 /******************************************************************************* 331 * Description: 332 * sends the mcp a keepalive to known registers 333 * Return: 334 ******************************************************************************/ 335 lm_status_t lm_send_driver_pulse( lm_device_t* pdev ) 336 { 337 u32_t msg_code = 0; 338 u32_t drv_pulse = 0; 339 u32_t mcp_pulse = 0; 340 341 if CHK_NULL(pdev) 342 { 343 return LM_STATUS_INVALID_PARAMETER ; 344 } 345 346 if GET_FLAGS(pdev->params.test_mode, TEST_MODE_NO_MCP) 347 { 348 return LM_STATUS_SUCCESS ; 349 } 350 351 ++pdev->vars.drv_pulse_wr_seq; 352 msg_code = pdev->vars.drv_pulse_wr_seq & DRV_PULSE_SEQ_MASK; 353 if (GET_FLAGS(pdev->params.test_mode, TEST_MODE_DRIVER_PULSE_ALWAYS_ALIVE) 354 || IS_DRIVER_PULSE_ALWAYS_ALIVE(pdev)) 355 { 356 SET_FLAGS( msg_code, DRV_PULSE_ALWAYS_ALIVE ) ; 357 } 358 359 drv_pulse = msg_code; 360 361 LM_SHMEM_WRITE(pdev, 362 OFFSETOF(shmem_region_t, 363 func_mb[FUNC_MAILBOX_ID(pdev)].drv_pulse_mb),msg_code); 364 LM_SHMEM_READ(pdev, 365 OFFSETOF(shmem_region_t, 366 func_mb[FUNC_MAILBOX_ID(pdev)].mcp_pulse_mb), 367 &mcp_pulse); 368 369 mcp_pulse&= MCP_PULSE_SEQ_MASK ; 370 /* The delta between driver pulse and mcp response 371 * should be 1 (before mcp response) or 0 (after mcp response) 372 */ 373 if ((drv_pulse != mcp_pulse) && 374 (drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK))) 375 { 376 DbgMessage(pdev, FATAL, "drv_pulse (0x%x) != mcp_pulse (0x%x)\n", drv_pulse, mcp_pulse ); 377 return LM_STATUS_FAILURE ; 378 } 379 DbgMessage(pdev, INFORMi , "Sent driver pulse cmd to MCP\n"); 380 return LM_STATUS_SUCCESS ; 381 } 382 /******************************************************************************* 383 * Description: 384 * Set driver pulse to MCP to always alive 385 * Return: 386 ******************************************************************************/ 387 void lm_driver_pulse_always_alive(struct _lm_device_t* pdev) 388 { 389 if CHK_NULL(pdev) 390 { 391 return; 392 } 393 if GET_FLAGS(pdev->params.test_mode, TEST_MODE_NO_MCP) 394 { 395 return ; 396 } 397 // Reset the MCP pulse to always alive 398 LM_SHMEM_WRITE( pdev, 399 OFFSETOF(shmem_region_t, 400 func_mb[FUNC_MAILBOX_ID(pdev)].drv_pulse_mb), 401 DRV_PULSE_ALWAYS_ALIVE ); 402 } 403 // entry that represents a function in the loader objcet 404 typedef struct _lm_loader_func_entry_t 405 { 406 u8_t b_loaded ; // does this function was loaded 407 } lm_loader_func_entry_t ; 408 // global object represents MCP - should be one per CHIP (boards) 409 typedef struct _lm_loader_path_obj_t 410 { 411 u32_t* lock_ctx ; // reserved - lock object context (currently not in use) 412 lm_loader_func_entry_t func_arr[E1H_FUNC_MAX] ; // array of function entries 413 } lm_loader_path_obj_t ; 414 415 typedef struct _lm_loader_obj_t 416 { 417 u8_t lock_owner ; // is a function acquire the lock? (1 based) 418 lm_loader_path_obj_t path_arr[MAX_PATH_NUM] ; 419 } lm_loader_obj_t ; 420 421 lm_loader_obj_t g_lm_loader = {0}; 422 423 // TRUE if the function is first on the port 424 #define LM_LOADER_IS_FIRST_ON_PORT(_pdev,_path_idx,_port_idx) \ 425 ( (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[_port_idx+0].b_loaded) && \ 426 (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[_port_idx+2].b_loaded) && \ 427 (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[_port_idx+4].b_loaded) && \ 428 (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[_port_idx+6].b_loaded) ) 429 430 // TRUE if the function is last on the port 431 #define LM_LOADER_IS_LAST_ON_PORT(_pdev,_path_idx,_port_idx) \ 432 ( ( ( FUNC_ID(_pdev) == (_port_idx+0) ) ? TRUE : (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[(_port_idx+0)].b_loaded) ) && \ 433 ( ( FUNC_ID(_pdev) == (_port_idx+2) ) ? TRUE : (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[(_port_idx+2)].b_loaded) ) && \ 434 ( ( FUNC_ID(_pdev) == (_port_idx+4) ) ? TRUE : (FALSE == g_lm_loader.path_arr[_path_idx].func_arr[(_port_idx+4)].b_loaded) ) && \ 435 ( ( FUNC_ID(_pdev) == (_port_idx+6) ) ? TRUE : (_port_idx == 0)?(FALSE == g_lm_loader.path_arr[_path_idx].func_arr[6].b_loaded):(FALSE == g_lm_loader.path_arr[_path_idx].func_arr[7].b_loaded) ) ) 436 437 438 #define LM_LOADER_IS_FIRST_ON_COMMON(_pdev,_path_idx) (LM_LOADER_IS_FIRST_ON_PORT(_pdev,_path_idx,0) && LM_LOADER_IS_FIRST_ON_PORT(_pdev,_path_idx,1)) 439 #define LM_LOADER_IS_LAST_ON_COMMON(_pdev,_path_idx) (LM_LOADER_IS_LAST_ON_PORT(_pdev,_path_idx,0) && LM_LOADER_IS_LAST_ON_PORT(_pdev,_path_idx,1)) 440 441 #define LM_LOADER_IS_FIRST_ON_CHIP(_pdev) (LM_LOADER_IS_FIRST_ON_COMMON(_pdev,0) && LM_LOADER_IS_FIRST_ON_COMMON(_pdev,1)) 442 #define LM_LOADER_IS_LAST_ON_CHIP(_pdev) (LM_LOADER_IS_LAST_ON_COMMON(_pdev,0) && LM_LOADER_IS_LAST_ON_COMMON(_pdev,1)) 443 444 // Accessed only with lock! 445 // TRUE if any device is currently locked 446 #define LM_LOADER_IS_LOCKED(_chip_idx) ( (FALSE != g_lm_loader.lock_owner) ) 447 448 /* 449 *Function Name:lm_loader_opcode_to_mcp_msg 450 * 451 *Parameters: 452 * b_lock - true if it is lock false if unlock 453 *Description: 454 * LM_LOADER_OPCODE_XXX-->DRV_MSG_CODE_XXX 455 *Returns: 456 * 457 */ 458 static u32_t lm_loader_opcode_to_mcp_msg( lm_loader_opcode opcode, u8_t b_lock ) 459 { 460 u32_t mcp_msg = 0xffffffff ; 461 462 switch(opcode) 463 { 464 case LM_LOADER_OPCODE_LOAD: 465 mcp_msg = b_lock ? DRV_MSG_CODE_LOAD_REQ : DRV_MSG_CODE_LOAD_DONE ; 466 break; 467 case LM_LOADER_OPCODE_UNLOAD_WOL_EN: 468 mcp_msg = b_lock ? DRV_MSG_CODE_UNLOAD_REQ_WOL_EN : DRV_MSG_CODE_UNLOAD_DONE ; 469 break; 470 case LM_LOADER_OPCODE_UNLOAD_WOL_DIS: 471 mcp_msg = b_lock ? DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS : DRV_MSG_CODE_UNLOAD_DONE ; 472 break; 473 case LM_LOADER_OPCODE_UNLOAD_WOL_MCP: 474 mcp_msg = b_lock ? DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP : DRV_MSG_CODE_UNLOAD_DONE ; 475 break; 476 default: 477 DbgBreakIf(1) ; 478 break; 479 } 480 return mcp_msg ; 481 } 482 /* 483 *Function Name:mcp_resp_to_lm_loader_resp 484 * 485 *Parameters: 486 * 487 *Description: 488 * Translates mcp response to loader response FW_MSG_CODE_DRV_XXX->LM_LOADER_RESPONSE_XX 489 *Returns: 490 * 491 */ 492 lm_loader_response mcp_resp_to_lm_loader_resp( u32_t mcp_resp ) 493 { 494 lm_loader_response resp = LM_LOADER_RESPONSE_INVALID ; 495 switch(mcp_resp) 496 { 497 case FW_MSG_CODE_DRV_LOAD_COMMON: 498 resp = LM_LOADER_RESPONSE_LOAD_COMMON ; 499 break; 500 case FW_MSG_CODE_DRV_LOAD_COMMON_CHIP: 501 resp = LM_LOADER_RESPONSE_LOAD_COMMON_CHIP ; 502 break; 503 case FW_MSG_CODE_DRV_LOAD_PORT: 504 resp = LM_LOADER_RESPONSE_LOAD_PORT ; 505 break; 506 case FW_MSG_CODE_DRV_LOAD_FUNCTION: 507 resp = LM_LOADER_RESPONSE_LOAD_FUNCTION ; 508 break; 509 case FW_MSG_CODE_DRV_UNLOAD_COMMON: 510 resp = LM_LOADER_RESPONSE_UNLOAD_COMMON ; 511 break; 512 case FW_MSG_CODE_DRV_UNLOAD_PORT: 513 resp = LM_LOADER_RESPONSE_UNLOAD_PORT ; 514 break; 515 case FW_MSG_CODE_DRV_UNLOAD_FUNCTION: 516 resp = LM_LOADER_RESPONSE_UNLOAD_FUNCTION ; 517 break; 518 case FW_MSG_CODE_DRV_LOAD_DONE: 519 resp = LM_LOADER_RESPONSE_LOAD_DONE ; 520 break; 521 case FW_MSG_CODE_DRV_UNLOAD_DONE: 522 resp = LM_LOADER_RESPONSE_UNLOAD_DONE ; 523 break; 524 default: 525 DbgMessage(NULL, FATAL, "mcp_resp=0x%x\n", mcp_resp ); 526 DbgBreakIf(1) ; 527 break; 528 } 529 return resp ; 530 } 531 // TBD - should it be the only indication?? 532 #define IS_MCP_ON(_pdev) ( TEST_MODE_NO_MCP != GET_FLAGS(_pdev->params.test_mode, TEST_MODE_NO_MCP ) ) 533 534 /* 535 *Function Name:lm_loader_lock 536 * 537 *Parameters: 538 * 539 *Description: 540 * sync loading/unloading of port/funciton 541 *Returns: 542 * 543 */ 544 lm_loader_response lm_loader_lock( lm_device_t* pdev, lm_loader_opcode opcode ) 545 { 546 u32_t mcp_msg = 0; 547 u32_t param = 0; 548 u32_t fw_resp = 0; 549 lm_loader_response resp = LM_LOADER_RESPONSE_INVALID ; 550 lm_status_t lm_status = LM_STATUS_SUCCESS ; 551 u32_t wait_cnt = 0; 552 u32_t wait_cnt_limit = 5000; 553 const u32_t feature_flags = mm_get_feature_flags( pdev ); 554 const u8_t is_suspend = opcode & LM_LOADER_OPCODE_UNLOAD_SUSPEND; 555 556 opcode &= LM_LOADER_OPCODE_MASK; 557 if( IS_MCP_ON(pdev) ) 558 { 559 mcp_msg = lm_loader_opcode_to_mcp_msg( opcode, TRUE ) ; 560 561 // in case it is load (and not unload) 562 // send mfw LFA param 563 if ( DRV_MSG_CODE_LOAD_REQ == mcp_msg ) 564 { 565 SET_FLAGS(param, DRV_MSG_CODE_LOAD_REQ_WITH_LFA ); 566 567 // in case BFS, set FORCE_LFA flag on 568 if( GET_FLAGS( feature_flags, FEATURE_ETH_BOOTMODE_PXE ) || 569 GET_FLAGS( feature_flags, FEATURE_ETH_BOOTMODE_ISCSI ) || 570 GET_FLAGS( feature_flags, FEATURE_ETH_BOOTMODE_FCOE ) ) 571 { 572 SET_FLAGS( param, DRV_MSG_CODE_LOAD_REQ_FORCE_LFA ); 573 } 574 575 } 576 else if (is_suspend) 577 { 578 SET_FLAGS( param, DRV_MSG_CODE_UNLOAD_NON_D3_POWER ); //temporary 579 } 580 581 //we do this with no locks because acquiring the loader lock may take a long time (e.g in case another function takes a 582 //long time to initialize we will only get a response from the MCP when it's done). We don't need a lock because interrupts 583 //are disabled at this point and we won't get any IOCTLs. 584 lm_status = lm_mcp_cmd_send_recieve_non_atomic( pdev, lm_mcp_mb_header, mcp_msg, param, MCP_CMD_DEFAULT_TIMEOUT, &fw_resp ) ; 585 if ( LM_STATUS_SUCCESS == lm_status ) 586 { 587 resp = mcp_resp_to_lm_loader_resp( fw_resp ) ; 588 pdev->vars.b_in_init_reset_flow = TRUE; 589 } 590 } 591 else // MCP_SIM 592 { 593 if( ERR_IF(PORT_ID(pdev) > 1) || ERR_IF(( FUNC_ID(pdev)) >= ARRSIZE(g_lm_loader.path_arr[PATH_ID(pdev)].func_arr)) ) 594 { 595 DbgBreakMsg("Invalid PORT_ID/FUNC_ID\n"); 596 return resp ; 597 } 598 do 599 { 600 MM_ACQUIRE_LOADER_LOCK(); 601 if( LM_LOADER_IS_LOCKED(PATH_ID(pdev)) ) 602 { 603 MM_RELEASE_LOADER_LOCK(); 604 mm_wait(pdev,20) ; 605 DbgBreakIfAll( ++wait_cnt > wait_cnt_limit ) ; 606 } 607 else 608 { 609 // we'll release the lock when we are finish the work 610 break; 611 } 612 }while(1) ; 613 // Verify no one hold the lock, if so - it's a bug! 614 DbgBreakIf( 0 != g_lm_loader.lock_owner ) ; 615 616 // mark our current function id as owner 617 g_lm_loader.lock_owner = FUNC_ID(pdev)+1 ; 618 619 switch( opcode ) 620 { 621 case LM_LOADER_OPCODE_LOAD: 622 if( LM_LOADER_IS_FIRST_ON_CHIP(pdev) ) 623 { 624 resp = LM_LOADER_RESPONSE_LOAD_COMMON_CHIP; 625 } 626 else if( LM_LOADER_IS_FIRST_ON_COMMON(pdev,PATH_ID(pdev)) ) 627 { 628 resp = LM_LOADER_RESPONSE_LOAD_COMMON ; 629 } 630 else if( LM_LOADER_IS_FIRST_ON_PORT( pdev, PATH_ID(pdev), PORT_ID(pdev) ) ) 631 { 632 resp = LM_LOADER_RESPONSE_LOAD_PORT ; 633 } 634 else 635 { 636 resp = LM_LOADER_RESPONSE_LOAD_FUNCTION ; 637 } 638 break; 639 case LM_LOADER_OPCODE_UNLOAD_WOL_EN: 640 case LM_LOADER_OPCODE_UNLOAD_WOL_DIS: 641 case LM_LOADER_OPCODE_UNLOAD_WOL_MCP: 642 if( LM_LOADER_IS_LAST_ON_COMMON(pdev,PATH_ID(pdev)) ) 643 { 644 resp = LM_LOADER_RESPONSE_UNLOAD_COMMON ; 645 } 646 else if( LM_LOADER_IS_LAST_ON_PORT( pdev, PATH_ID(pdev), PORT_ID(pdev) ) ) 647 { 648 resp = LM_LOADER_RESPONSE_UNLOAD_PORT ; 649 } 650 else 651 { 652 resp = LM_LOADER_RESPONSE_UNLOAD_FUNCTION ; 653 } 654 break; 655 default: 656 DbgBreakIf(1) ; 657 break; 658 } // switch 659 pdev->vars.b_in_init_reset_flow = TRUE; 660 MM_RELEASE_LOADER_LOCK(); 661 } // MCP_SIM 662 return resp ; 663 } 664 /* 665 *Function Name:lm_loader_unlock 666 * 667 *Parameters: 668 * 669 *Description: 670 * sync loading/unloading of port/funciton 671 *Returns: 672 * 673 */ 674 lm_loader_response lm_loader_unlock( struct _lm_device_t *pdev, lm_loader_opcode opcode, OPTIONAL const u32_t* IN p_param ) 675 { 676 u32_t mcp_msg = 0 ; 677 u32_t param = p_param ? (*p_param) : 0 ; 678 lm_loader_response resp = LM_LOADER_RESPONSE_INVALID ; 679 u32_t fw_resp = 0 ; 680 lm_status_t lm_status = LM_STATUS_SUCCESS ; 681 u8_t b_new_state = 0xff ; 682 if CHK_NULL(pdev) 683 { 684 return resp ; 685 } 686 opcode &= LM_LOADER_OPCODE_MASK; 687 if( IS_MCP_ON(pdev) ) 688 { 689 mcp_msg = lm_loader_opcode_to_mcp_msg( opcode, FALSE ); 690 //we do this with no locks because acquiring the loader lock may take a long time (e.g in case another function takes a 691 //long time to initialize we will only get a response from the MCP when it's done). We don't need a lock because interrupts 692 //are disabled at this point and we won't get any IOCTLs. 693 lm_status = lm_mcp_cmd_send_recieve_non_atomic(pdev, lm_mcp_mb_header, mcp_msg, param, MCP_CMD_DEFAULT_TIMEOUT, &fw_resp ) ; 694 if ( LM_STATUS_SUCCESS == lm_status ) 695 { 696 resp = mcp_resp_to_lm_loader_resp( fw_resp ) ; 697 pdev->vars.b_in_init_reset_flow = FALSE; 698 } 699 } 700 else // MCP_SIM 701 { 702 MM_ACQUIRE_LOADER_LOCK(); 703 704 // Verify current function id is the owner 705 DbgBreakIf( g_lm_loader.lock_owner != FUNC_ID(pdev)+1 ) ; 706 707 switch( opcode ) 708 { 709 case LM_LOADER_OPCODE_LOAD: 710 b_new_state = TRUE ; 711 resp = LM_LOADER_RESPONSE_LOAD_DONE ; 712 break; 713 case LM_LOADER_OPCODE_UNLOAD_WOL_EN: 714 case LM_LOADER_OPCODE_UNLOAD_WOL_DIS: 715 case LM_LOADER_OPCODE_UNLOAD_WOL_MCP: 716 b_new_state = FALSE ; 717 resp = LM_LOADER_RESPONSE_UNLOAD_DONE ; 718 break; 719 default: 720 DbgBreakIf(1) ; 721 break; 722 } // switch 723 // verify new state differs than current 724 DbgBreakIf(g_lm_loader.path_arr[PATH_ID(pdev)].func_arr[FUNC_ID(pdev)].b_loaded == b_new_state); 725 726 // assign new state 727 g_lm_loader.path_arr[PATH_ID(pdev)].func_arr[FUNC_ID(pdev)].b_loaded = b_new_state ; 728 729 // mark we don't own the lock anymore 730 g_lm_loader.lock_owner = FALSE ; 731 732 pdev->vars.b_in_init_reset_flow = FALSE; 733 MM_RELEASE_LOADER_LOCK(); 734 } // MCP_SIM 735 return resp ; 736 } 737 738 /* Used for simulating a mcp reset where the mcp no longer knows the state of the uploaded drivers... */ 739 void lm_loader_reset ( struct _lm_device_t *pdev ) 740 { 741 mm_memset(&g_lm_loader, 0, sizeof(g_lm_loader)); 742 } 743 744 /* 745 *Function Name:lm_mcp_cmd_init 746 * 747 *Parameters: 748 * 749 *Description: 750 * initiate sequence of mb + verify boot code version 751 *Returns: 752 * 753 */ 754 lm_status_t lm_mcp_cmd_init( struct _lm_device_t *pdev) 755 { 756 u32_t val = 0 ; 757 u32_t bc_rev = 0 ; 758 u32_t offset = 0 ; 759 u8_t func_mb_id = 0; 760 761 DbgMessage(pdev, INFORMi , "### mcp_cmd_init\n"); 762 763 if CHK_NULL(pdev) 764 { 765 return LM_STATUS_FAILURE ; 766 } 767 768 // we are on NO_MCP mode - nothing to do 769 if( 0 != GET_FLAGS(pdev->params.test_mode, TEST_MODE_NO_MCP ) ) 770 { 771 return LM_STATUS_SUCCESS ; 772 } 773 774 //validtae bc version 775 bc_rev = LM_GET_BC_REV_MAJOR(pdev); 776 777 if (bc_rev < BC_REV_SUPPORTED) 778 { 779 DbgMessage(pdev, FATAL,"bc version is less than 0x%x equal to 0x%x.\n", BC_REV_SUPPORTED, bc_rev ); 780 DbgBreakMsg("Please upgrade the bootcode version.\n"); 781 // TODO add event log 782 return LM_STATUS_INVALID_PARAMETER; 783 } 784 785 // enable optic module verification according to BC version 786 if (bc_rev >= REQ_BC_VER_4_VRFY_FIRST_PHY_OPT_MDL) 787 { 788 SET_FLAGS(pdev->params.link.feature_config_flags, ELINK_FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY); 789 } 790 791 if (bc_rev >= REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL) 792 { 793 SET_FLAGS(pdev->params.link.feature_config_flags, ELINK_FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY); 794 } 795 796 if (bc_rev >= REQ_BC_VER_4_VRFY_AFEX_SUPPORTED) 797 { 798 SET_FLAGS(pdev->params.link.feature_config_flags, ELINK_FEATURE_CONFIG_BC_SUPPORTS_AFEX); 799 } 800 801 if (bc_rev >= REQ_BC_VER_4_SFP_TX_DISABLE_SUPPORTED) 802 { 803 SET_FLAGS(pdev->params.link.feature_config_flags, ELINK_FEATURE_CONFIG_BC_SUPPORTS_SFP_TX_DISABLED); 804 } 805 806 if (bc_rev >= REQ_BC_VER_4_MT_SUPPORTED) 807 { 808 SET_FLAGS(pdev->params.link.feature_config_flags, ELINK_FEATURE_CONFIG_MT_SUPPORT); 809 } 810 811 // regular MCP mode 812 func_mb_id = pdev->params.pfunc_mb_id; 813 814 // read first seq number from shared memory 815 offset = OFFSETOF(shmem_region_t, func_mb[func_mb_id].drv_mb_header); 816 LM_SHMEM_READ(pdev, offset, &val); 817 pdev->vars.fw_wr_seq = (u16_t)(val & DRV_MSG_SEQ_NUMBER_MASK); 818 819 // read current mcp_pulse value 820 offset = OFFSETOF(shmem_region_t,func_mb[func_mb_id].mcp_pulse_mb) ; 821 LM_SHMEM_READ(pdev, offset ,&val); 822 pdev->vars.drv_pulse_wr_seq = (u16_t)(val & MCP_PULSE_SEQ_MASK); 823 824 return LM_STATUS_SUCCESS; 825 } 826 827 lm_status_t lm_mcp_set_mf_bw(struct _lm_device_t *pdev, IN u8_t min_bw, IN u8_t max_bw) 828 { 829 u32_t minmax_param = 0; 830 u32_t resp = 0; 831 lm_status_t lm_status = LM_STATUS_SUCCESS; 832 const u32_t bc_rev = LM_GET_BC_REV_MAJOR(pdev); 833 834 //if in no MCP mode, don't do anything 835 if(!lm_is_mcp_detected(pdev)) 836 { 837 DbgMessage(pdev, WARNmi, "No MCP detected.\n"); 838 return LM_STATUS_SUCCESS; 839 } 840 //if bootcode is less then REQ_BC_VER_4_SET_MF_BW, fail 841 if( bc_rev < REQ_BC_VER_4_SET_MF_BW ) 842 { 843 DbgMessage(pdev, WARNmi, "Invalid bootcode version.\n"); 844 return LM_STATUS_INVALID_PARAMETER; 845 } 846 //if not E2 or not MF mode, fail 847 if(CHIP_IS_E1x(pdev) || !IS_MULTI_VNIC(pdev)) 848 { 849 DbgMessage(pdev, WARNmi, "Device is E1/E1.5 or in SF mode.\n"); 850 return LM_STATUS_INVALID_PARAMETER; 851 } 852 //if the parameters are not valid, fail 853 if (max_bw > 100) 854 { 855 DbgMessage(pdev, WARNmi, "Invalid parameters.\n"); 856 return LM_STATUS_INVALID_PARAMETER; 857 } 858 //build MCP command parameter from min_bw/max_bw 859 //we use FUNC_MF_CFG_MIN_BW_SHIFT because the param structure is supposed to 860 //be equivalent for this opcode and for the DCC opcode, but there is no define 861 //for this opcode. 862 ASSERT_STATIC(FUNC_MF_CFG_MIN_BW_MASK == DRV_MSG_CODE_SET_MF_BW_MIN_MASK); 863 ASSERT_STATIC(FUNC_MF_CFG_MAX_BW_MASK == DRV_MSG_CODE_SET_MF_BW_MAX_MASK); 864 minmax_param = (min_bw << FUNC_MF_CFG_MIN_BW_SHIFT)| 865 (max_bw << FUNC_MF_CFG_MAX_BW_SHIFT); 866 867 //call lm_mcp_cmd_send_recieve with DRV_MSG_CODE_SET_MF_BW opcode and the parameter 868 lm_mcp_cmd_send_recieve(pdev, lm_mcp_mb_header, DRV_MSG_CODE_SET_MF_BW, minmax_param, MCP_CMD_DEFAULT_TIMEOUT, &resp); 869 870 //make sure that the response is FW_MSG_CODE_SET_MF_BW_SENT 871 if(resp != FW_MSG_CODE_SET_MF_BW_SENT) 872 { 873 DbgBreakIf(resp != FW_MSG_CODE_SET_MF_BW_SENT); 874 return LM_STATUS_FAILURE; 875 } 876 877 //return what lm_mcp_cmd_send_recieve returned 878 return lm_status; 879 } 880 881 /* 882 *Function Name:lm_mcp_cmd_send 883 * 884 *Parameters: 885 * 886 *Description: 887 * send 888 *Returns: 889 * 890 */ 891 lm_status_t lm_mcp_cmd_send( struct _lm_device_t *pdev, lm_mcp_mb_type mb_type, u32_t drv_msg, u32_t param ) 892 { 893 u16_t* p_seq = NULL ; 894 u32_t offset = 0 ; 895 u32_t drv_mask = 0 ; 896 const u8_t func_mb_id = pdev->params.pfunc_mb_id; 897 898 DbgMessage(pdev, INFORMi , "### mcp_cmd_send mb_type=0x%x drv_msg=0x%x param=0x%x\n", mb_type, drv_msg, param ); 899 900 // we are on NO_MCP mode - nothing to do 901 if( 0 != GET_FLAGS(pdev->params.test_mode, TEST_MODE_NO_MCP ) ) 902 { 903 return LM_STATUS_SUCCESS ; 904 } 905 906 switch( mb_type ) 907 { 908 case lm_mcp_mb_header: 909 p_seq = &pdev->vars.fw_wr_seq ; 910 drv_mask = DRV_MSG_SEQ_NUMBER_MASK ; 911 offset = OFFSETOF(shmem_region_t, func_mb[func_mb_id].drv_mb_header) ; 912 /* Write the parameter to the mcp */ 913 if (p_seq) 914 { 915 LM_SHMEM_WRITE(pdev,OFFSETOF(shmem_region_t, func_mb[func_mb_id].drv_mb_param),param); 916 } 917 break; 918 919 case lm_mcp_mb_pulse: 920 p_seq = &pdev->vars.drv_pulse_wr_seq ; 921 drv_mask = DRV_PULSE_SEQ_MASK ; 922 offset = OFFSETOF(shmem_region_t, func_mb[func_mb_id].mcp_pulse_mb) ; 923 break; 924 case lm_mcp_mb_param: 925 default: 926 break; 927 } 928 929 if CHK_NULL( p_seq ) 930 { 931 return LM_STATUS_INVALID_PARAMETER ; 932 } 933 934 // incremant sequence 935 ++(*p_seq); 936 937 // prepare message 938 drv_msg |= ( (*p_seq) & drv_mask ); 939 940 LM_SHMEM_WRITE(pdev,offset,drv_msg); 941 942 DbgMessage(pdev, INFORMi , "mcp_cmd_send: Sent driver load cmd to MCP at 0x%x\n", drv_msg); 943 944 return LM_STATUS_SUCCESS ; 945 } 946 947 /* 948 *Function Name:lm_mcp_cmd_response 949 * 950 *Parameters: 951 * TBD - add timeout value 952 *Description: 953 * assumption - only one request can be sent simultaneously 954 *Returns: 955 * 956 */ 957 lm_status_t lm_mcp_cmd_response( struct _lm_device_t *pdev, 958 lm_mcp_mb_type mcp_mb_type, 959 u32_t drv_msg, 960 u32_t timeout, 961 OUT u32_t* p_fw_resp ) 962 { 963 u16_t* p_seq = NULL ; 964 u32_t offset = 0 ; 965 u32_t drv_mask = 0 ; 966 u32_t fw_mask = 0 ; 967 u32_t cnt = 0 ; 968 u32_t wait_itr = 0 ; 969 u32_t resp_mask = 0xffffffff ; 970 lm_status_t lm_status = LM_STATUS_SUCCESS ; 971 const u8_t func_mb_id = pdev->params.pfunc_mb_id; 972 973 UNREFERENCED_PARAMETER_(timeout); 974 975 DbgMessage(pdev, INFORMi, "### mcp_cmd_response mb_type=0x%x drv_msg=0x%x\n", mcp_mb_type, drv_msg ); 976 977 if ( CHK_NULL(p_fw_resp) ) 978 { 979 return LM_STATUS_FAILURE ; 980 } 981 982 switch( mcp_mb_type ) 983 { 984 case lm_mcp_mb_header: 985 p_seq = &pdev->vars.fw_wr_seq ; 986 drv_mask = DRV_MSG_SEQ_NUMBER_MASK ; 987 fw_mask = FW_MSG_SEQ_NUMBER_MASK ; 988 resp_mask = FW_MSG_CODE_MASK ; 989 offset = OFFSETOF(shmem_region_t, func_mb[func_mb_id].fw_mb_header) ; 990 break; 991 992 // TBD - is it needed ?? 993 case lm_mcp_mb_pulse: 994 p_seq = &pdev->vars.drv_pulse_wr_seq ; 995 drv_mask = DRV_PULSE_SEQ_MASK ; 996 fw_mask = MCP_PULSE_SEQ_MASK ; 997 offset = OFFSETOF(shmem_region_t, func_mb[func_mb_id].mcp_pulse_mb) ; 998 break; 999 1000 case lm_mcp_mb_param: 1001 default: 1002 break; 1003 } 1004 1005 if CHK_NULL( p_seq ) 1006 { 1007 return LM_STATUS_INVALID_PARAMETER ; 1008 } 1009 1010 lm_status = LM_STATUS_TIMEOUT ; 1011 1012 // Wait for reply 5 sec per unloading function 1013 //TODO exponential back off 1014 wait_itr = 240 * FW_ACK_NUM_OF_POLL * PORT_MAX * (u32_t)(IS_MULTI_VNIC(pdev) ? MAX_VNIC_NUM : 1); 1015 for(cnt = 0; cnt < wait_itr; cnt++) 1016 { 1017 mm_wait(pdev, FW_ACK_POLL_TIME_MS * 50); 1018 1019 LM_SHMEM_READ(pdev, offset, p_fw_resp); 1020 1021 if(( (*p_fw_resp) & fw_mask) == ( (*p_seq) & drv_mask)) 1022 { 1023 lm_status = LM_STATUS_SUCCESS ; 1024 break; 1025 } 1026 } 1027 1028 *p_fw_resp = (*p_fw_resp & resp_mask); 1029 1030 return lm_status ; 1031 } 1032 1033 lm_status_t lm_mcp_cmd_send_recieve_non_atomic( struct _lm_device_t *pdev, 1034 lm_mcp_mb_type mcp_mb_type, 1035 u32_t drv_msg, 1036 u32_t param, 1037 u32_t timeout, 1038 OUT u32_t* p_fw_resp ) 1039 { 1040 lm_status_t lm_status = LM_STATUS_FAILURE; 1041 u32_t val = 0; 1042 1043 lm_status = lm_mcp_cmd_send( pdev, mcp_mb_type, drv_msg, param) ; 1044 1045 if( LM_STATUS_SUCCESS != lm_status ) 1046 { 1047 val = lm_mcp_check(pdev); 1048 DbgMessage(pdev, FATAL, "mcp_cmd_send_and_recieve: mcp_cmd_send drv_msg=0x%x failed. lm_status=0x%x mcp_check=0x%x\n", drv_msg, lm_status, val); 1049 DbgBreakMsg("mcp_cmd_send_and_recieve: mcp_cmd_send failed!\n"); 1050 return lm_status; 1051 } 1052 1053 DbgMessage(pdev, INFORMi , "mcp_cmd_send_and_recieve: Sent driver cmd=0x%x to MCP\n", drv_msg ); 1054 1055 lm_status = lm_mcp_cmd_response( pdev, mcp_mb_type, drv_msg, timeout, p_fw_resp ) ; 1056 1057 if( LM_STATUS_SUCCESS != lm_status ) 1058 { 1059 val = lm_mcp_check(pdev); 1060 DbgMessage(pdev, FATAL, "mcp_cmd_send_and_recieve: mcp_cmd_response drv_msg=0x%x failed. lm_status=0x%x mcp_check=0x%x\n", drv_msg, lm_status, val); 1061 DbgBreakMsg("mcp_cmd_send_and_recieve: mcp_cmd_response failed!\n"); 1062 return lm_status; 1063 } 1064 1065 DbgMessage(pdev, INFORMi , "mcp_cmd_send_and_recieve: Got response 0x%x from MCP\n", *p_fw_resp ); 1066 1067 return LM_STATUS_SUCCESS; 1068 } 1069 1070 /* 1071 *Function Name:lm_mcp_cmd_send_recieve 1072 * 1073 *Parameters: 1074 * 1075 *Description: 1076 * 1077 *Returns: lm_status_t 1078 * 1079 */ 1080 lm_status_t lm_mcp_cmd_send_recieve( struct _lm_device_t *pdev, 1081 lm_mcp_mb_type mcp_mb_type, 1082 u32_t drv_msg, 1083 u32_t param, 1084 u32_t timeout, 1085 OUT u32_t* p_fw_resp ) 1086 { 1087 lm_status_t lm_status = LM_STATUS_SUCCESS ; 1088 1089 MM_ACQUIRE_MCP_LOCK(pdev); 1090 1091 lm_status = lm_mcp_cmd_send_recieve_non_atomic(pdev, mcp_mb_type, drv_msg, param, timeout, p_fw_resp); 1092 1093 MM_RELEASE_MCP_LOCK(pdev); 1094 1095 return lm_status ; 1096 } 1097 1098 1099 // check if mcp program counter is advancing, In case it doesn't return the value in case it does, return 0 1100 u32_t lm_mcp_check( struct _lm_device_t *pdev) 1101 { 1102 static u32_t const offset = MCP_REG_MCPR_CPU_PROGRAM_COUNTER ; 1103 u32_t reg = 0 ; 1104 u32_t i = 0 ; 1105 1106 reg = REG_RD(pdev, offset); 1107 1108 for( i = 0; i<4; i++ ) 1109 { 1110 if( REG_RD(pdev, offset) != reg ) 1111 { 1112 return 0; // OK 1113 } 1114 } 1115 return reg; // mcp is hang on this value as program counter! 1116 } 1117 1118 /**lm_mcp_cli_idx_to_drv_cap_flag 1119 * Get the flag to set in drv_capabilities_flag for a given LM 1120 * client. 1121 * 1122 * @param cli_id the LM client index. 1123 * 1124 * @return u32_t the appropriate flag for cli_id, or 0 if there 1125 * is no matching flag. 1126 */ 1127 static u32_t lm_mcp_cli_idx_to_drv_cap_flag(IN const lm_cli_idx_t cli_id) 1128 { 1129 switch(cli_id) 1130 { 1131 case LM_CLI_IDX_NDIS: 1132 return DRV_FLAGS_CAPABILITIES_LOADED_L2; 1133 case LM_CLI_IDX_ISCSI: 1134 return DRV_FLAGS_CAPABILITIES_LOADED_ISCSI; 1135 case LM_CLI_IDX_FCOE: 1136 return DRV_FLAGS_CAPABILITIES_LOADED_FCOE; 1137 case LM_CLI_IDX_MAX://may happen for UM clients that have no matching LM client, such as diag. 1138 return 0; 1139 case LM_CLI_IDX_FWD://fallthrough - this client has no bind/unbind flow and no matching UM client 1140 case LM_CLI_IDX_OOO://fallthrough - this client has no bind/unbind flow and no matching UM client 1141 default: 1142 DbgBreakMsg("Invalid client type"); 1143 return 0; 1144 } 1145 } 1146 1147 void lm_mcp_indicate_client_imp(struct _lm_device_t *pdev, IN const lm_cli_idx_t cli_id, IN const u8_t b_bind ) 1148 { 1149 const u32_t drv_cap_client = lm_mcp_cli_idx_to_drv_cap_flag(cli_id); 1150 const u32_t func_mb_id = FUNC_MAILBOX_ID(pdev); 1151 const u32_t shmem_offset = OFFSETOF(shmem2_region_t, drv_capabilities_flag[func_mb_id]); 1152 u32_t drv_cap_shmem = 0; 1153 1154 if (CHIP_IS_E1x(pdev) || 1155 !LM_SHMEM2_HAS(pdev, drv_capabilities_flag)) 1156 { 1157 return; 1158 } 1159 1160 if (0 == drv_cap_client) 1161 { 1162 //this is a client that does not require updating the SHMEM 1163 return; 1164 } 1165 1166 LM_SHMEM2_READ(pdev, shmem_offset, &drv_cap_shmem); 1167 1168 if( b_bind ) 1169 { 1170 SET_FLAGS( drv_cap_shmem, drv_cap_client ); 1171 } 1172 else 1173 { 1174 RESET_FLAGS( drv_cap_shmem, drv_cap_client ); 1175 } 1176 1177 LM_SHMEM2_WRITE(pdev, shmem_offset, drv_cap_shmem); 1178 } 1179 1180 void lm_mcp_indicate_client_bind(struct _lm_device_t *pdev, IN const lm_cli_idx_t cli_id) 1181 { 1182 lm_mcp_indicate_client_imp(pdev, cli_id, TRUE); 1183 } 1184 1185 void lm_mcp_indicate_client_unbind(struct _lm_device_t *pdev, IN const lm_cli_idx_t cli_id) 1186 { 1187 lm_mcp_indicate_client_imp(pdev, cli_id, FALSE); 1188 } 1189