aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2011-04-13 07:05:08 -0400
committerDavid S. Miller <davem@davemloft.net>2011-04-13 20:10:08 -0400
commitc3e945006ab2295e9a3f4327aa74a502ad123fe6 (patch)
tree06bb8b4e44ea7db96f3c6c751a39020ad3d76b47
parent4852a8614f63999e38539ad16615054dcd20a05d (diff)
tg3: Add support for extended VPD blocks
In some devices, the VPD block is relocated to a different area in NVRAM. The original location can still contain old, but still valid VPD data. This patch changes the code to look for an extended VPD block in NVRAM. If one is found, that block is used for all VPD operations instead. Signed-off-by: Matt Carlson <mcarlson@broadcom.com> Reviewed-by: Michael Chan <mchan@broadcom.com> Reviewed-by: Benjamin Li <benli@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/tg3.c125
-rw-r--r--drivers/net/tg3.h2
2 files changed, 83 insertions, 44 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 52dd516ba786..10fa476fede3 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -10416,6 +10416,81 @@ static void tg3_get_ethtool_stats(struct net_device *dev,
10416 memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats)); 10416 memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats));
10417} 10417}
10418 10418
10419static __be32 * tg3_vpd_readblock(struct tg3 *tp)
10420{
10421 int i;
10422 __be32 *buf;
10423 u32 offset = 0, len = 0;
10424 u32 magic, val;
10425
10426 if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) ||
10427 tg3_nvram_read(tp, 0, &magic))
10428 return NULL;
10429
10430 if (magic == TG3_EEPROM_MAGIC) {
10431 for (offset = TG3_NVM_DIR_START;
10432 offset < TG3_NVM_DIR_END;
10433 offset += TG3_NVM_DIRENT_SIZE) {
10434 if (tg3_nvram_read(tp, offset, &val))
10435 return NULL;
10436
10437 if ((val >> TG3_NVM_DIRTYPE_SHIFT) ==
10438 TG3_NVM_DIRTYPE_EXTVPD)
10439 break;
10440 }
10441
10442 if (offset != TG3_NVM_DIR_END) {
10443 len = (val & TG3_NVM_DIRTYPE_LENMSK) * 4;
10444 if (tg3_nvram_read(tp, offset + 4, &offset))
10445 return NULL;
10446
10447 offset = tg3_nvram_logical_addr(tp, offset);
10448 }
10449 }
10450
10451 if (!offset || !len) {
10452 offset = TG3_NVM_VPD_OFF;
10453 len = TG3_NVM_VPD_LEN;
10454 }
10455
10456 buf = kmalloc(len, GFP_KERNEL);
10457 if (buf == NULL)
10458 return NULL;
10459
10460 if (magic == TG3_EEPROM_MAGIC) {
10461 for (i = 0; i < len; i += 4) {
10462 /* The data is in little-endian format in NVRAM.
10463 * Use the big-endian read routines to preserve
10464 * the byte order as it exists in NVRAM.
10465 */
10466 if (tg3_nvram_read_be32(tp, offset + i, &buf[i/4]))
10467 goto error;
10468 }
10469 } else {
10470 u8 *ptr;
10471 ssize_t cnt;
10472 unsigned int pos = 0;
10473
10474 ptr = (u8 *)&buf[0];
10475 for (i = 0; pos < len && i < 3; i++, pos += cnt, ptr += cnt) {
10476 cnt = pci_read_vpd(tp->pdev, pos,
10477 len - pos, ptr);
10478 if (cnt == -ETIMEDOUT || cnt == -EINTR)
10479 cnt = 0;
10480 else if (cnt < 0)
10481 goto error;
10482 }
10483 if (pos != len)
10484 goto error;
10485 }
10486
10487 return buf;
10488
10489error:
10490 kfree(buf);
10491 return NULL;
10492}
10493
10419#define NVRAM_TEST_SIZE 0x100 10494#define NVRAM_TEST_SIZE 0x100
10420#define NVRAM_SELFBOOT_FORMAT1_0_SIZE 0x14 10495#define NVRAM_SELFBOOT_FORMAT1_0_SIZE 0x14
10421#define NVRAM_SELFBOOT_FORMAT1_2_SIZE 0x18 10496#define NVRAM_SELFBOOT_FORMAT1_2_SIZE 0x18
@@ -10555,14 +10630,11 @@ static int tg3_test_nvram(struct tg3 *tp)
10555 if (csum != le32_to_cpu(buf[0xfc/4])) 10630 if (csum != le32_to_cpu(buf[0xfc/4]))
10556 goto out; 10631 goto out;
10557 10632
10558 for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) { 10633 kfree(buf);
10559 /* The data is in little-endian format in NVRAM. 10634
10560 * Use the big-endian read routines to preserve 10635 buf = tg3_vpd_readblock(tp);
10561 * the byte order as it exists in NVRAM. 10636 if (!buf)
10562 */ 10637 return -ENOMEM;
10563 if (tg3_nvram_read_be32(tp, TG3_NVM_VPD_OFF + i, &buf[i/4]))
10564 goto out;
10565 }
10566 10638
10567 i = pci_vpd_find_tag((u8 *)buf, 0, TG3_NVM_VPD_LEN, 10639 i = pci_vpd_find_tag((u8 *)buf, 0, TG3_NVM_VPD_LEN,
10568 PCI_VPD_LRDT_RO_DATA); 10640 PCI_VPD_LRDT_RO_DATA);
@@ -12905,46 +12977,11 @@ static void __devinit tg3_read_vpd(struct tg3 *tp)
12905 u8 *vpd_data; 12977 u8 *vpd_data;
12906 unsigned int block_end, rosize, len; 12978 unsigned int block_end, rosize, len;
12907 int j, i = 0; 12979 int j, i = 0;
12908 u32 magic;
12909
12910 if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) ||
12911 tg3_nvram_read(tp, 0x0, &magic))
12912 goto out_no_vpd;
12913 12980
12914 vpd_data = kmalloc(TG3_NVM_VPD_LEN, GFP_KERNEL); 12981 vpd_data = (u8 *)tg3_vpd_readblock(tp);
12915 if (!vpd_data) 12982 if (!vpd_data)
12916 goto out_no_vpd; 12983 goto out_no_vpd;
12917 12984
12918 if (magic == TG3_EEPROM_MAGIC) {
12919 for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) {
12920 u32 tmp;
12921
12922 /* The data is in little-endian format in NVRAM.
12923 * Use the big-endian read routines to preserve
12924 * the byte order as it exists in NVRAM.
12925 */
12926 if (tg3_nvram_read_be32(tp, TG3_NVM_VPD_OFF + i, &tmp))
12927 goto out_not_found;
12928
12929 memcpy(&vpd_data[i], &tmp, sizeof(tmp));
12930 }
12931 } else {
12932 ssize_t cnt;
12933 unsigned int pos = 0;
12934
12935 for (; pos < TG3_NVM_VPD_LEN && i < 3; i++, pos += cnt) {
12936 cnt = pci_read_vpd(tp->pdev, pos,
12937 TG3_NVM_VPD_LEN - pos,
12938 &vpd_data[pos]);
12939 if (cnt == -ETIMEDOUT || cnt == -EINTR)
12940 cnt = 0;
12941 else if (cnt < 0)
12942 goto out_not_found;
12943 }
12944 if (pos != TG3_NVM_VPD_LEN)
12945 goto out_not_found;
12946 }
12947
12948 i = pci_vpd_find_tag(vpd_data, 0, TG3_NVM_VPD_LEN, 12985 i = pci_vpd_find_tag(vpd_data, 0, TG3_NVM_VPD_LEN,
12949 PCI_VPD_LRDT_RO_DATA); 12986 PCI_VPD_LRDT_RO_DATA);
12950 if (i < 0) 12987 if (i < 0)
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index b3ccfcc9ffea..224c3e0ec695 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2009,7 +2009,9 @@
2009#define TG3_NVM_DIR_END 0x78 2009#define TG3_NVM_DIR_END 0x78
2010#define TG3_NVM_DIRENT_SIZE 0xc 2010#define TG3_NVM_DIRENT_SIZE 0xc
2011#define TG3_NVM_DIRTYPE_SHIFT 24 2011#define TG3_NVM_DIRTYPE_SHIFT 24
2012#define TG3_NVM_DIRTYPE_LENMSK 0x003fffff
2012#define TG3_NVM_DIRTYPE_ASFINI 1 2013#define TG3_NVM_DIRTYPE_ASFINI 1
2014#define TG3_NVM_DIRTYPE_EXTVPD 20
2013#define TG3_NVM_PTREV_BCVER 0x94 2015#define TG3_NVM_PTREV_BCVER 0x94
2014#define TG3_NVM_BCVER_MAJMSK 0x0000ff00 2016#define TG3_NVM_BCVER_MAJMSK 0x0000ff00
2015#define TG3_NVM_BCVER_MAJSFT 8 2017#define TG3_NVM_BCVER_MAJSFT 8