summaryrefslogtreecommitdiff
path: root/drivers/net/bnx2.c
diff options
context:
space:
mode:
authorMichael Chan <mchan@broadcom.com>2009-12-03 12:46:34 +0300
committerDavid S. Miller <davem@davemloft.net>2009-12-04 00:18:13 +0300
commit76d9906170259b581691c3cec6bc5d4ab3aaaede (patch)
treeba70b891341fe7e3c3a4b2c014cf2e64c313d465 /drivers/net/bnx2.c
parentb929e53cb7796a8abe47174dfdfdf90cbb65a8bf (diff)
downloadlinux-76d9906170259b581691c3cec6bc5d4ab3aaaede.tar.xz
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.c102
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)
}
+static void __devinit
+bnx2_read_vpd_fw_ver(struct bnx2 *bp)
+{
+ int rc, i, v0_len = 0;
+ u8 *data;
+ u8 *v0_str = NULL;
+ bool mn_match = false;
+
+#define BNX2_MAX_VER_SLEN 30
+
+ data = kmalloc(256, GFP_KERNEL);
+ if (!data)
+ return;
+
+ rc = bnx2_nvram_read(bp, 0x300, data + 128, 128);
+ if (rc)
+ goto vpd_done;
+
+ for (i = 0; i < 128; i += 4) {
+ data[i] = data[i + 131];
+ data[i + 1] = data[i + 130];
+ data[i + 2] = data[i + 129];
+ data[i + 3] = data[i + 128];
+ }
+
+ for (i = 0; i < 128; ) {
+ unsigned char val = data[i];
+ unsigned int block_end;
+
+ if (val == 0x82 || val == 0x91) {
+ i = (i + 3 + (data[i + 1] + (data[i + 2] << 8)));
+ continue;
+ }
+
+ if (val != 0x90)
+ goto vpd_done;
+
+ block_end = (i + 3 + (data[i + 1] + (data[i + 2] << 8)));
+ i += 3;
+
+ if (block_end > 128)
+ goto vpd_done;
+
+ while (i < (block_end - 2)) {
+ if (data[i] == 'M' && data[i + 1] == 'N') {
+ int mn_len = data[i + 2];
+
+ if (mn_len != 4)
+ goto vpd_done;
+
+ i += 3;
+ if (memcmp(&data[i], "1028", 4))
+ goto vpd_done;
+ mn_match = true;
+ i += 4;
+
+ } else if (data[i] == 'V' && data[i + 1] == '0') {
+ v0_len = data[i + 2];
+
+ i += 3;
+ if (v0_len > BNX2_MAX_VER_SLEN ||
+ (v0_len + i) > 128)
+ goto vpd_done;
+
+ if (v0_len > BNX2_MAX_VER_SLEN)
+ v0_len = BNX2_MAX_VER_SLEN;
+
+ v0_str = &data[i];
+ i += data[i + 2];
+
+ } else {
+ i += 3 + data[i + 2];
+ }
+
+ if (mn_match && v0_str) {
+ memcpy(bp->fw_version, v0_str, v0_len);
+ bp->fw_version[v0_len] = ' ';
+ goto vpd_done;
+ }
+ }
+ goto vpd_done;
+ }
+
+vpd_done:
+ kfree(data);
+}
+
static int __devinit
bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
{
@@ -7895,10 +7982,18 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
goto err_out_unmap;
}
+ bnx2_read_vpd_fw_ver(bp);
+
+ j = strlen(bp->fw_version);
reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV);
- for (i = 0, j = 0; i < 3; i++) {
+ for (i = 0; i < 3 && j < 24; i++) {
u8 num, k, skip0;
+ if (i == 0) {
+ bp->fw_version[j++] = 'b';
+ bp->fw_version[j++] = 'c';
+ bp->fw_version[j++] = ' ';
+ }
num = (u8) (reg >> (24 - (i * 8)));
for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
if (num >= k || !skip0 || k == 1) {
@@ -7929,8 +8024,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
reg != BNX2_CONDITION_MFW_RUN_NONE) {
u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR);
- bp->fw_version[j++] = ' ';
- for (i = 0; i < 3; i++) {
+ if (j < 32)
+ bp->fw_version[j++] = ' ';
+ for (i = 0; i < 3 && j < 28; i++) {
reg = bnx2_reg_rd_ind(bp, addr + i * 4);
reg = swab32(reg);
memcpy(&bp->fw_version[j], &reg, 4);