diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-ucode.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-ucode.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 637286c396f..6f77441cb65 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c | |||
@@ -423,3 +423,126 @@ int iwlagn_alive_notify(struct iwl_priv *priv) | |||
423 | 423 | ||
424 | return 0; | 424 | return 0; |
425 | } | 425 | } |
426 | |||
427 | |||
428 | /** | ||
429 | * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, | ||
430 | * using sample data 100 bytes apart. If these sample points are good, | ||
431 | * it's a pretty good bet that everything between them is good, too. | ||
432 | */ | ||
433 | static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) | ||
434 | { | ||
435 | u32 val; | ||
436 | int ret = 0; | ||
437 | u32 errcnt = 0; | ||
438 | u32 i; | ||
439 | |||
440 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); | ||
441 | |||
442 | for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { | ||
443 | /* read data comes through single port, auto-incr addr */ | ||
444 | /* NOTE: Use the debugless read so we don't flood kernel log | ||
445 | * if IWL_DL_IO is set */ | ||
446 | iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, | ||
447 | i + IWLAGN_RTC_INST_LOWER_BOUND); | ||
448 | val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | ||
449 | if (val != le32_to_cpu(*image)) { | ||
450 | ret = -EIO; | ||
451 | errcnt++; | ||
452 | if (errcnt >= 3) | ||
453 | break; | ||
454 | } | ||
455 | } | ||
456 | |||
457 | return ret; | ||
458 | } | ||
459 | |||
460 | /** | ||
461 | * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host, | ||
462 | * looking at all data. | ||
463 | */ | ||
464 | static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, | ||
465 | u32 len) | ||
466 | { | ||
467 | u32 val; | ||
468 | u32 save_len = len; | ||
469 | int ret = 0; | ||
470 | u32 errcnt; | ||
471 | |||
472 | IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len); | ||
473 | |||
474 | iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, | ||
475 | IWLAGN_RTC_INST_LOWER_BOUND); | ||
476 | |||
477 | errcnt = 0; | ||
478 | for (; len > 0; len -= sizeof(u32), image++) { | ||
479 | /* read data comes through single port, auto-incr addr */ | ||
480 | /* NOTE: Use the debugless read so we don't flood kernel log | ||
481 | * if IWL_DL_IO is set */ | ||
482 | val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | ||
483 | if (val != le32_to_cpu(*image)) { | ||
484 | IWL_ERR(priv, "uCode INST section is invalid at " | ||
485 | "offset 0x%x, is 0x%x, s/b 0x%x\n", | ||
486 | save_len - len, val, le32_to_cpu(*image)); | ||
487 | ret = -EIO; | ||
488 | errcnt++; | ||
489 | if (errcnt >= 20) | ||
490 | break; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | if (!errcnt) | ||
495 | IWL_DEBUG_INFO(priv, | ||
496 | "ucode image in INSTRUCTION memory is good\n"); | ||
497 | |||
498 | return ret; | ||
499 | } | ||
500 | |||
501 | /** | ||
502 | * iwl_verify_ucode - determine which instruction image is in SRAM, | ||
503 | * and verify its contents | ||
504 | */ | ||
505 | int iwl_verify_ucode(struct iwl_priv *priv) | ||
506 | { | ||
507 | __le32 *image; | ||
508 | u32 len; | ||
509 | int ret; | ||
510 | |||
511 | /* Try bootstrap */ | ||
512 | image = (__le32 *)priv->ucode_boot.v_addr; | ||
513 | len = priv->ucode_boot.len; | ||
514 | ret = iwlcore_verify_inst_sparse(priv, image, len); | ||
515 | if (!ret) { | ||
516 | IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n"); | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | /* Try initialize */ | ||
521 | image = (__le32 *)priv->ucode_init.v_addr; | ||
522 | len = priv->ucode_init.len; | ||
523 | ret = iwlcore_verify_inst_sparse(priv, image, len); | ||
524 | if (!ret) { | ||
525 | IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n"); | ||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | /* Try runtime/protocol */ | ||
530 | image = (__le32 *)priv->ucode_code.v_addr; | ||
531 | len = priv->ucode_code.len; | ||
532 | ret = iwlcore_verify_inst_sparse(priv, image, len); | ||
533 | if (!ret) { | ||
534 | IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n"); | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); | ||
539 | |||
540 | /* Since nothing seems to match, show first several data entries in | ||
541 | * instruction SRAM, so maybe visual inspection will give a clue. | ||
542 | * Selection of bootstrap image (vs. other images) is arbitrary. */ | ||
543 | image = (__le32 *)priv->ucode_boot.v_addr; | ||
544 | len = priv->ucode_boot.len; | ||
545 | ret = iwl_verify_inst_full(priv, image, len); | ||
546 | |||
547 | return ret; | ||
548 | } | ||