diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-core.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index ca32fb3b9e1..8c8b51dea57 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -704,3 +704,137 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags) | |||
704 | } | 704 | } |
705 | EXPORT_SYMBOL(iwl_send_statistics_request); | 705 | EXPORT_SYMBOL(iwl_send_statistics_request); |
706 | 706 | ||
707 | /** | ||
708 | * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, | ||
709 | * using sample data 100 bytes apart. If these sample points are good, | ||
710 | * it's a pretty good bet that everything between them is good, too. | ||
711 | */ | ||
712 | static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) | ||
713 | { | ||
714 | u32 val; | ||
715 | int ret = 0; | ||
716 | u32 errcnt = 0; | ||
717 | u32 i; | ||
718 | |||
719 | IWL_DEBUG_INFO("ucode inst image size is %u\n", len); | ||
720 | |||
721 | ret = iwl_grab_nic_access(priv); | ||
722 | if (ret) | ||
723 | return ret; | ||
724 | |||
725 | for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) { | ||
726 | /* read data comes through single port, auto-incr addr */ | ||
727 | /* NOTE: Use the debugless read so we don't flood kernel log | ||
728 | * if IWL_DL_IO is set */ | ||
729 | iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, | ||
730 | i + RTC_INST_LOWER_BOUND); | ||
731 | val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | ||
732 | if (val != le32_to_cpu(*image)) { | ||
733 | ret = -EIO; | ||
734 | errcnt++; | ||
735 | if (errcnt >= 3) | ||
736 | break; | ||
737 | } | ||
738 | } | ||
739 | |||
740 | iwl_release_nic_access(priv); | ||
741 | |||
742 | return ret; | ||
743 | } | ||
744 | |||
745 | /** | ||
746 | * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host, | ||
747 | * looking at all data. | ||
748 | */ | ||
749 | static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image, | ||
750 | u32 len) | ||
751 | { | ||
752 | u32 val; | ||
753 | u32 save_len = len; | ||
754 | int ret = 0; | ||
755 | u32 errcnt; | ||
756 | |||
757 | IWL_DEBUG_INFO("ucode inst image size is %u\n", len); | ||
758 | |||
759 | ret = iwl_grab_nic_access(priv); | ||
760 | if (ret) | ||
761 | return ret; | ||
762 | |||
763 | iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); | ||
764 | |||
765 | errcnt = 0; | ||
766 | for (; len > 0; len -= sizeof(u32), image++) { | ||
767 | /* read data comes through single port, auto-incr addr */ | ||
768 | /* NOTE: Use the debugless read so we don't flood kernel log | ||
769 | * if IWL_DL_IO is set */ | ||
770 | val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); | ||
771 | if (val != le32_to_cpu(*image)) { | ||
772 | IWL_ERROR("uCode INST section is invalid at " | ||
773 | "offset 0x%x, is 0x%x, s/b 0x%x\n", | ||
774 | save_len - len, val, le32_to_cpu(*image)); | ||
775 | ret = -EIO; | ||
776 | errcnt++; | ||
777 | if (errcnt >= 20) | ||
778 | break; | ||
779 | } | ||
780 | } | ||
781 | |||
782 | iwl_release_nic_access(priv); | ||
783 | |||
784 | if (!errcnt) | ||
785 | IWL_DEBUG_INFO | ||
786 | ("ucode image in INSTRUCTION memory is good\n"); | ||
787 | |||
788 | return ret; | ||
789 | } | ||
790 | |||
791 | /** | ||
792 | * iwl_verify_ucode - determine which instruction image is in SRAM, | ||
793 | * and verify its contents | ||
794 | */ | ||
795 | int iwl_verify_ucode(struct iwl_priv *priv) | ||
796 | { | ||
797 | __le32 *image; | ||
798 | u32 len; | ||
799 | int ret; | ||
800 | |||
801 | /* Try bootstrap */ | ||
802 | image = (__le32 *)priv->ucode_boot.v_addr; | ||
803 | len = priv->ucode_boot.len; | ||
804 | ret = iwlcore_verify_inst_sparse(priv, image, len); | ||
805 | if (!ret) { | ||
806 | IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n"); | ||
807 | return 0; | ||
808 | } | ||
809 | |||
810 | /* Try initialize */ | ||
811 | image = (__le32 *)priv->ucode_init.v_addr; | ||
812 | len = priv->ucode_init.len; | ||
813 | ret = iwlcore_verify_inst_sparse(priv, image, len); | ||
814 | if (!ret) { | ||
815 | IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n"); | ||
816 | return 0; | ||
817 | } | ||
818 | |||
819 | /* Try runtime/protocol */ | ||
820 | image = (__le32 *)priv->ucode_code.v_addr; | ||
821 | len = priv->ucode_code.len; | ||
822 | ret = iwlcore_verify_inst_sparse(priv, image, len); | ||
823 | if (!ret) { | ||
824 | IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n"); | ||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); | ||
829 | |||
830 | /* Since nothing seems to match, show first several data entries in | ||
831 | * instruction SRAM, so maybe visual inspection will give a clue. | ||
832 | * Selection of bootstrap image (vs. other images) is arbitrary. */ | ||
833 | image = (__le32 *)priv->ucode_boot.v_addr; | ||
834 | len = priv->ucode_boot.len; | ||
835 | ret = iwl_verify_inst_full(priv, image, len); | ||
836 | |||
837 | return ret; | ||
838 | } | ||
839 | EXPORT_SYMBOL(iwl_verify_ucode); | ||
840 | |||