Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Matt Carlson and committed by
David S. Miller
c3e94500 4852a861

+83 -44
+81 -44
drivers/net/tg3.c
··· 10416 10416 memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats)); 10417 10417 } 10418 10418 10419 + static __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 + 10489 + error: 10490 + kfree(buf); 10491 + return NULL; 10492 + } 10493 + 10419 10494 #define NVRAM_TEST_SIZE 0x100 10420 10495 #define NVRAM_SELFBOOT_FORMAT1_0_SIZE 0x14 10421 10496 #define NVRAM_SELFBOOT_FORMAT1_2_SIZE 0x18 ··· 10630 10555 if (csum != le32_to_cpu(buf[0xfc/4])) 10631 10556 goto out; 10632 10557 10633 - for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) { 10634 - /* The data is in little-endian format in NVRAM. 10635 - * Use the big-endian read routines to preserve 10636 - * the byte order as it exists in NVRAM. 10637 - */ 10638 - if (tg3_nvram_read_be32(tp, TG3_NVM_VPD_OFF + i, &buf[i/4])) 10639 - goto out; 10640 - } 10558 + kfree(buf); 10559 + 10560 + buf = tg3_vpd_readblock(tp); 10561 + if (!buf) 10562 + return -ENOMEM; 10641 10563 10642 10564 i = pci_vpd_find_tag((u8 *)buf, 0, TG3_NVM_VPD_LEN, 10643 10565 PCI_VPD_LRDT_RO_DATA); ··· 12977 12905 u8 *vpd_data; 12978 12906 unsigned int block_end, rosize, len; 12979 12907 int j, i = 0; 12980 - u32 magic; 12981 12908 12982 - if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) || 12983 - tg3_nvram_read(tp, 0x0, &magic)) 12984 - goto out_no_vpd; 12985 - 12986 - vpd_data = kmalloc(TG3_NVM_VPD_LEN, GFP_KERNEL); 12909 + vpd_data = (u8 *)tg3_vpd_readblock(tp); 12987 12910 if (!vpd_data) 12988 12911 goto out_no_vpd; 12989 - 12990 - if (magic == TG3_EEPROM_MAGIC) { 12991 - for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) { 12992 - u32 tmp; 12993 - 12994 - /* The data is in little-endian format in NVRAM. 12995 - * Use the big-endian read routines to preserve 12996 - * the byte order as it exists in NVRAM. 12997 - */ 12998 - if (tg3_nvram_read_be32(tp, TG3_NVM_VPD_OFF + i, &tmp)) 12999 - goto out_not_found; 13000 - 13001 - memcpy(&vpd_data[i], &tmp, sizeof(tmp)); 13002 - } 13003 - } else { 13004 - ssize_t cnt; 13005 - unsigned int pos = 0; 13006 - 13007 - for (; pos < TG3_NVM_VPD_LEN && i < 3; i++, pos += cnt) { 13008 - cnt = pci_read_vpd(tp->pdev, pos, 13009 - TG3_NVM_VPD_LEN - pos, 13010 - &vpd_data[pos]); 13011 - if (cnt == -ETIMEDOUT || cnt == -EINTR) 13012 - cnt = 0; 13013 - else if (cnt < 0) 13014 - goto out_not_found; 13015 - } 13016 - if (pos != TG3_NVM_VPD_LEN) 13017 - goto out_not_found; 13018 - } 13019 12912 13020 12913 i = pci_vpd_find_tag(vpd_data, 0, TG3_NVM_VPD_LEN, 13021 12914 PCI_VPD_LRDT_RO_DATA);
+2
drivers/net/tg3.h
··· 2009 2009 #define TG3_NVM_DIR_END 0x78 2010 2010 #define TG3_NVM_DIRENT_SIZE 0xc 2011 2011 #define TG3_NVM_DIRTYPE_SHIFT 24 2012 + #define TG3_NVM_DIRTYPE_LENMSK 0x003fffff 2012 2013 #define TG3_NVM_DIRTYPE_ASFINI 1 2014 + #define TG3_NVM_DIRTYPE_EXTVPD 20 2013 2015 #define TG3_NVM_PTREV_BCVER 0x94 2014 2016 #define TG3_NVM_BCVER_MAJMSK 0x0000ff00 2015 2017 #define TG3_NVM_BCVER_MAJSFT 8