diff options
author | Michael Chan <mchan@broadcom.com> | 2009-12-03 04:46:34 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-12-03 16:18:13 -0500 |
commit | 76d9906170259b581691c3cec6bc5d4ab3aaaede (patch) | |
tree | ba70b891341fe7e3c3a4b2c014cf2e64c313d465 /drivers/net/bnx2.c | |
parent | b929e53cb7796a8abe47174dfdfdf90cbb65a8bf (diff) |
bnx2: Read firmware version from VPD.
And display it through ethtool -i.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bnx2.c')
-rw-r--r-- | drivers/net/bnx2.c | 102 |
1 files changed, 99 insertions, 3 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index dba3840d7df9..b7bc74b0d1b6 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -7722,6 +7722,93 @@ bnx2_get_pci_speed(struct bnx2 *bp) | |||
7722 | 7722 | ||
7723 | } | 7723 | } |
7724 | 7724 | ||
7725 | static void __devinit | ||
7726 | bnx2_read_vpd_fw_ver(struct bnx2 *bp) | ||
7727 | { | ||
7728 | int rc, i, v0_len = 0; | ||
7729 | u8 *data; | ||
7730 | u8 *v0_str = NULL; | ||
7731 | bool mn_match = false; | ||
7732 | |||
7733 | #define BNX2_MAX_VER_SLEN 30 | ||
7734 | |||
7735 | data = kmalloc(256, GFP_KERNEL); | ||
7736 | if (!data) | ||
7737 | return; | ||
7738 | |||
7739 | rc = bnx2_nvram_read(bp, 0x300, data + 128, 128); | ||
7740 | if (rc) | ||
7741 | goto vpd_done; | ||
7742 | |||
7743 | for (i = 0; i < 128; i += 4) { | ||
7744 | data[i] = data[i + 131]; | ||
7745 | data[i + 1] = data[i + 130]; | ||
7746 | data[i + 2] = data[i + 129]; | ||
7747 | data[i + 3] = data[i + 128]; | ||
7748 | } | ||
7749 | |||
7750 | for (i = 0; i < 128; ) { | ||
7751 | unsigned char val = data[i]; | ||
7752 | unsigned int block_end; | ||
7753 | |||
7754 | if (val == 0x82 || val == 0x91) { | ||
7755 | i = (i + 3 + (data[i + 1] + (data[i + 2] << 8))); | ||
7756 | continue; | ||
7757 | } | ||
7758 | |||
7759 | if (val != 0x90) | ||
7760 | goto vpd_done; | ||
7761 | |||
7762 | block_end = (i + 3 + (data[i + 1] + (data[i + 2] << 8))); | ||
7763 | i += 3; | ||
7764 | |||
7765 | if (block_end > 128) | ||
7766 | goto vpd_done; | ||
7767 | |||
7768 | while (i < (block_end - 2)) { | ||
7769 | if (data[i] == 'M' && data[i + 1] == 'N') { | ||
7770 | int mn_len = data[i + 2]; | ||
7771 | |||
7772 | if (mn_len != 4) | ||
7773 | goto vpd_done; | ||
7774 | |||
7775 | i += 3; | ||
7776 | if (memcmp(&data[i], "1028", 4)) | ||
7777 | goto vpd_done; | ||
7778 | mn_match = true; | ||
7779 | i += 4; | ||
7780 | |||
7781 | } else if (data[i] == 'V' && data[i + 1] == '0') { | ||
7782 | v0_len = data[i + 2]; | ||
7783 | |||
7784 | i += 3; | ||
7785 | if (v0_len > BNX2_MAX_VER_SLEN || | ||
7786 | (v0_len + i) > 128) | ||
7787 | goto vpd_done; | ||
7788 | |||
7789 | if (v0_len > BNX2_MAX_VER_SLEN) | ||
7790 | v0_len = BNX2_MAX_VER_SLEN; | ||
7791 | |||
7792 | v0_str = &data[i]; | ||
7793 | i += data[i + 2]; | ||
7794 | |||
7795 | } else { | ||
7796 | i += 3 + data[i + 2]; | ||
7797 | } | ||
7798 | |||
7799 | if (mn_match && v0_str) { | ||
7800 | memcpy(bp->fw_version, v0_str, v0_len); | ||
7801 | bp->fw_version[v0_len] = ' '; | ||
7802 | goto vpd_done; | ||
7803 | } | ||
7804 | } | ||
7805 | goto vpd_done; | ||
7806 | } | ||
7807 | |||
7808 | vpd_done: | ||
7809 | kfree(data); | ||
7810 | } | ||
7811 | |||
7725 | static int __devinit | 7812 | static int __devinit |
7726 | bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) | 7813 | bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) |
7727 | { | 7814 | { |
@@ -7895,10 +7982,18 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) | |||
7895 | goto err_out_unmap; | 7982 | goto err_out_unmap; |
7896 | } | 7983 | } |
7897 | 7984 | ||
7985 | bnx2_read_vpd_fw_ver(bp); | ||
7986 | |||
7987 | j = strlen(bp->fw_version); | ||
7898 | reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV); | 7988 | reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV); |
7899 | for (i = 0, j = 0; i < 3; i++) { | 7989 | for (i = 0; i < 3 && j < 24; i++) { |
7900 | u8 num, k, skip0; | 7990 | u8 num, k, skip0; |
7901 | 7991 | ||
7992 | if (i == 0) { | ||
7993 | bp->fw_version[j++] = 'b'; | ||
7994 | bp->fw_version[j++] = 'c'; | ||
7995 | bp->fw_version[j++] = ' '; | ||
7996 | } | ||
7902 | num = (u8) (reg >> (24 - (i * 8))); | 7997 | num = (u8) (reg >> (24 - (i * 8))); |
7903 | for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) { | 7998 | for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) { |
7904 | if (num >= k || !skip0 || k == 1) { | 7999 | if (num >= k || !skip0 || k == 1) { |
@@ -7929,8 +8024,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) | |||
7929 | reg != BNX2_CONDITION_MFW_RUN_NONE) { | 8024 | reg != BNX2_CONDITION_MFW_RUN_NONE) { |
7930 | u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR); | 8025 | u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR); |
7931 | 8026 | ||
7932 | bp->fw_version[j++] = ' '; | 8027 | if (j < 32) |
7933 | for (i = 0; i < 3; i++) { | 8028 | bp->fw_version[j++] = ' '; |
8029 | for (i = 0; i < 3 && j < 28; i++) { | ||
7934 | reg = bnx2_reg_rd_ind(bp, addr + i * 4); | 8030 | reg = bnx2_reg_rd_ind(bp, addr + i * 4); |
7935 | reg = swab32(reg); | 8031 | reg = swab32(reg); |
7936 | memcpy(&bp->fw_version[j], ®, 4); | 8032 | memcpy(&bp->fw_version[j], ®, 4); |