diff options
Diffstat (limited to 'drivers/net/netxen/netxen_nic_init.c')
-rw-r--r-- | drivers/net/netxen/netxen_nic_init.c | 167 |
1 files changed, 152 insertions, 15 deletions
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 1c63610ead42..388feaf60ee7 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | #include <linux/netdevice.h> | 26 | #include <linux/netdevice.h> |
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | #include <linux/slab.h> | ||
28 | #include "netxen_nic.h" | 29 | #include "netxen_nic.h" |
29 | #include "netxen_nic_hw.h" | 30 | #include "netxen_nic_hw.h" |
30 | 31 | ||
@@ -613,22 +614,123 @@ static struct uni_table_desc *nx_get_table_desc(const u8 *unirom, int section) | |||
613 | return NULL; | 614 | return NULL; |
614 | } | 615 | } |
615 | 616 | ||
617 | #define QLCNIC_FILEHEADER_SIZE (14 * 4) | ||
618 | |||
616 | static int | 619 | static int |
617 | nx_set_product_offs(struct netxen_adapter *adapter) | 620 | netxen_nic_validate_header(struct netxen_adapter *adapter) |
618 | { | 621 | { |
619 | struct uni_table_desc *ptab_descr; | ||
620 | const u8 *unirom = adapter->fw->data; | 622 | const u8 *unirom = adapter->fw->data; |
621 | uint32_t i; | 623 | struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0]; |
624 | u32 fw_file_size = adapter->fw->size; | ||
625 | u32 tab_size; | ||
622 | __le32 entries; | 626 | __le32 entries; |
627 | __le32 entry_size; | ||
628 | |||
629 | if (fw_file_size < QLCNIC_FILEHEADER_SIZE) | ||
630 | return -EINVAL; | ||
631 | |||
632 | entries = cpu_to_le32(directory->num_entries); | ||
633 | entry_size = cpu_to_le32(directory->entry_size); | ||
634 | tab_size = cpu_to_le32(directory->findex) + (entries * entry_size); | ||
635 | |||
636 | if (fw_file_size < tab_size) | ||
637 | return -EINVAL; | ||
638 | |||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | static int | ||
643 | netxen_nic_validate_bootld(struct netxen_adapter *adapter) | ||
644 | { | ||
645 | struct uni_table_desc *tab_desc; | ||
646 | struct uni_data_desc *descr; | ||
647 | const u8 *unirom = adapter->fw->data; | ||
648 | __le32 idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] + | ||
649 | NX_UNI_BOOTLD_IDX_OFF)); | ||
650 | u32 offs; | ||
651 | u32 tab_size; | ||
652 | u32 data_size; | ||
653 | |||
654 | tab_desc = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_BOOTLD); | ||
655 | |||
656 | if (!tab_desc) | ||
657 | return -EINVAL; | ||
658 | |||
659 | tab_size = cpu_to_le32(tab_desc->findex) + | ||
660 | (cpu_to_le32(tab_desc->entry_size) * (idx + 1)); | ||
661 | |||
662 | if (adapter->fw->size < tab_size) | ||
663 | return -EINVAL; | ||
664 | |||
665 | offs = cpu_to_le32(tab_desc->findex) + | ||
666 | (cpu_to_le32(tab_desc->entry_size) * (idx)); | ||
667 | descr = (struct uni_data_desc *)&unirom[offs]; | ||
668 | |||
669 | data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size); | ||
670 | |||
671 | if (adapter->fw->size < data_size) | ||
672 | return -EINVAL; | ||
623 | 673 | ||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | static int | ||
678 | netxen_nic_validate_fw(struct netxen_adapter *adapter) | ||
679 | { | ||
680 | struct uni_table_desc *tab_desc; | ||
681 | struct uni_data_desc *descr; | ||
682 | const u8 *unirom = adapter->fw->data; | ||
683 | __le32 idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] + | ||
684 | NX_UNI_FIRMWARE_IDX_OFF)); | ||
685 | u32 offs; | ||
686 | u32 tab_size; | ||
687 | u32 data_size; | ||
688 | |||
689 | tab_desc = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_FW); | ||
690 | |||
691 | if (!tab_desc) | ||
692 | return -EINVAL; | ||
693 | |||
694 | tab_size = cpu_to_le32(tab_desc->findex) + | ||
695 | (cpu_to_le32(tab_desc->entry_size) * (idx + 1)); | ||
696 | |||
697 | if (adapter->fw->size < tab_size) | ||
698 | return -EINVAL; | ||
699 | |||
700 | offs = cpu_to_le32(tab_desc->findex) + | ||
701 | (cpu_to_le32(tab_desc->entry_size) * (idx)); | ||
702 | descr = (struct uni_data_desc *)&unirom[offs]; | ||
703 | data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size); | ||
704 | |||
705 | if (adapter->fw->size < data_size) | ||
706 | return -EINVAL; | ||
707 | |||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | |||
712 | static int | ||
713 | netxen_nic_validate_product_offs(struct netxen_adapter *adapter) | ||
714 | { | ||
715 | struct uni_table_desc *ptab_descr; | ||
716 | const u8 *unirom = adapter->fw->data; | ||
624 | int mn_present = (NX_IS_REVISION_P2(adapter->ahw.revision_id)) ? | 717 | int mn_present = (NX_IS_REVISION_P2(adapter->ahw.revision_id)) ? |
625 | 1 : netxen_p3_has_mn(adapter); | 718 | 1 : netxen_p3_has_mn(adapter); |
719 | __le32 entries; | ||
720 | __le32 entry_size; | ||
721 | u32 tab_size; | ||
722 | u32 i; | ||
626 | 723 | ||
627 | ptab_descr = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_PRODUCT_TBL); | 724 | ptab_descr = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_PRODUCT_TBL); |
628 | if (ptab_descr == NULL) | 725 | if (ptab_descr == NULL) |
629 | return -1; | 726 | return -EINVAL; |
630 | 727 | ||
631 | entries = cpu_to_le32(ptab_descr->num_entries); | 728 | entries = cpu_to_le32(ptab_descr->num_entries); |
729 | entry_size = cpu_to_le32(ptab_descr->entry_size); | ||
730 | tab_size = cpu_to_le32(ptab_descr->findex) + (entries * entry_size); | ||
731 | |||
732 | if (adapter->fw->size < tab_size) | ||
733 | return -EINVAL; | ||
632 | 734 | ||
633 | nomn: | 735 | nomn: |
634 | for (i = 0; i < entries; i++) { | 736 | for (i = 0; i < entries; i++) { |
@@ -657,9 +759,38 @@ nomn: | |||
657 | goto nomn; | 759 | goto nomn; |
658 | } | 760 | } |
659 | 761 | ||
660 | return -1; | 762 | return -EINVAL; |
661 | } | 763 | } |
662 | 764 | ||
765 | static int | ||
766 | netxen_nic_validate_unified_romimage(struct netxen_adapter *adapter) | ||
767 | { | ||
768 | if (netxen_nic_validate_header(adapter)) { | ||
769 | dev_err(&adapter->pdev->dev, | ||
770 | "unified image: header validation failed\n"); | ||
771 | return -EINVAL; | ||
772 | } | ||
773 | |||
774 | if (netxen_nic_validate_product_offs(adapter)) { | ||
775 | dev_err(&adapter->pdev->dev, | ||
776 | "unified image: product validation failed\n"); | ||
777 | return -EINVAL; | ||
778 | } | ||
779 | |||
780 | if (netxen_nic_validate_bootld(adapter)) { | ||
781 | dev_err(&adapter->pdev->dev, | ||
782 | "unified image: bootld validation failed\n"); | ||
783 | return -EINVAL; | ||
784 | } | ||
785 | |||
786 | if (netxen_nic_validate_fw(adapter)) { | ||
787 | dev_err(&adapter->pdev->dev, | ||
788 | "unified image: firmware validation failed\n"); | ||
789 | return -EINVAL; | ||
790 | } | ||
791 | |||
792 | return 0; | ||
793 | } | ||
663 | 794 | ||
664 | static struct uni_data_desc *nx_get_data_desc(struct netxen_adapter *adapter, | 795 | static struct uni_data_desc *nx_get_data_desc(struct netxen_adapter *adapter, |
665 | u32 section, u32 idx_offset) | 796 | u32 section, u32 idx_offset) |
@@ -761,7 +892,7 @@ nx_get_bios_version(struct netxen_adapter *adapter) | |||
761 | if (adapter->fw_type == NX_UNIFIED_ROMIMAGE) { | 892 | if (adapter->fw_type == NX_UNIFIED_ROMIMAGE) { |
762 | bios_ver = cpu_to_le32(*((u32 *) (&fw->data[prd_off]) | 893 | bios_ver = cpu_to_le32(*((u32 *) (&fw->data[prd_off]) |
763 | + NX_UNI_BIOS_VERSION_OFF)); | 894 | + NX_UNI_BIOS_VERSION_OFF)); |
764 | return (bios_ver << 24) + ((bios_ver >> 8) & 0xff00) + | 895 | return (bios_ver << 16) + ((bios_ver >> 8) & 0xff00) + |
765 | (bios_ver >> 24); | 896 | (bios_ver >> 24); |
766 | } else | 897 | } else |
767 | return cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]); | 898 | return cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]); |
@@ -889,6 +1020,16 @@ netxen_load_firmware(struct netxen_adapter *adapter) | |||
889 | 1020 | ||
890 | flashaddr += 8; | 1021 | flashaddr += 8; |
891 | } | 1022 | } |
1023 | |||
1024 | size = (__force u32)nx_get_fw_size(adapter) % 8; | ||
1025 | if (size) { | ||
1026 | data = cpu_to_le64(ptr64[i]); | ||
1027 | |||
1028 | if (adapter->pci_mem_write(adapter, | ||
1029 | flashaddr, data)) | ||
1030 | return -EIO; | ||
1031 | } | ||
1032 | |||
892 | } else { | 1033 | } else { |
893 | u64 data; | 1034 | u64 data; |
894 | u32 hi, lo; | 1035 | u32 hi, lo; |
@@ -933,27 +1074,23 @@ static int | |||
933 | netxen_validate_firmware(struct netxen_adapter *adapter) | 1074 | netxen_validate_firmware(struct netxen_adapter *adapter) |
934 | { | 1075 | { |
935 | __le32 val; | 1076 | __le32 val; |
936 | u32 ver, min_ver, bios, min_size; | 1077 | u32 ver, min_ver, bios; |
937 | struct pci_dev *pdev = adapter->pdev; | 1078 | struct pci_dev *pdev = adapter->pdev; |
938 | const struct firmware *fw = adapter->fw; | 1079 | const struct firmware *fw = adapter->fw; |
939 | u8 fw_type = adapter->fw_type; | 1080 | u8 fw_type = adapter->fw_type; |
940 | 1081 | ||
941 | if (fw_type == NX_UNIFIED_ROMIMAGE) { | 1082 | if (fw_type == NX_UNIFIED_ROMIMAGE) { |
942 | if (nx_set_product_offs(adapter)) | 1083 | if (netxen_nic_validate_unified_romimage(adapter)) |
943 | return -EINVAL; | 1084 | return -EINVAL; |
944 | |||
945 | min_size = NX_UNI_FW_MIN_SIZE; | ||
946 | } else { | 1085 | } else { |
947 | val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]); | 1086 | val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]); |
948 | if ((__force u32)val != NETXEN_BDINFO_MAGIC) | 1087 | if ((__force u32)val != NETXEN_BDINFO_MAGIC) |
949 | return -EINVAL; | 1088 | return -EINVAL; |
950 | 1089 | ||
951 | min_size = NX_FW_MIN_SIZE; | 1090 | if (fw->size < NX_FW_MIN_SIZE) |
1091 | return -EINVAL; | ||
952 | } | 1092 | } |
953 | 1093 | ||
954 | if (fw->size < min_size) | ||
955 | return -EINVAL; | ||
956 | |||
957 | val = nx_get_fw_version(adapter); | 1094 | val = nx_get_fw_version(adapter); |
958 | 1095 | ||
959 | if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) | 1096 | if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) |