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)) |
