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