Skip to content

Commit

Permalink
cxgb4: parse the VPD instead of relying on a static VPD layout
Browse files Browse the repository at this point in the history
Some boards' VPDs contain additional keywords or have longer serial numbers,
meaning the keyword locations are variable.  Ditch the static layout and
use the pci_vpd_* family of functions to parse the VPD instead.

Signed-off-by: Dimitris Michailidis <dm@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Dimitris Michailidis authored and David S. Miller committed Apr 27, 2010
1 parent c377411 commit 226ec5f
Showing 1 changed file with 39 additions and 25 deletions.
64 changes: 39 additions & 25 deletions drivers/net/cxgb4/t4_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,33 +347,21 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
return 0;
}

#define VPD_ENTRY(name, len) \
u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]

/*
* Partial EEPROM Vital Product Data structure. Includes only the ID and
* VPD-R sections.
* VPD-R header.
*/
struct t4_vpd {
struct t4_vpd_hdr {
u8 id_tag;
u8 id_len[2];
u8 id_data[ID_LEN];
u8 vpdr_tag;
u8 vpdr_len[2];
VPD_ENTRY(pn, 16); /* part number */
VPD_ENTRY(ec, EC_LEN); /* EC level */
VPD_ENTRY(sn, SERNUM_LEN); /* serial number */
VPD_ENTRY(na, 12); /* MAC address base */
VPD_ENTRY(port_type, 8); /* port types */
VPD_ENTRY(gpio, 14); /* GPIO usage */
VPD_ENTRY(cclk, 6); /* core clock */
VPD_ENTRY(port_addr, 8); /* port MDIO addresses */
VPD_ENTRY(rv, 1); /* csum */
u32 pad; /* for multiple-of-4 sizing and alignment */
};

#define EEPROM_STAT_ADDR 0x7bfc
#define VPD_BASE 0
#define VPD_LEN 512

/**
* t4_seeprom_wp - enable/disable EEPROM write protection
Expand All @@ -398,29 +386,55 @@ int t4_seeprom_wp(struct adapter *adapter, bool enable)
*/
static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
{
int ret;
struct t4_vpd vpd;
u8 *q = (u8 *)&vpd, csum;
int i, ret;
int ec, sn, v2;
u8 vpd[VPD_LEN], csum;
unsigned int vpdr_len;
const struct t4_vpd_hdr *v;

ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(vpd), &vpd);
ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(vpd), vpd);
if (ret < 0)
return ret;

for (csum = 0; q <= vpd.rv_data; q++)
csum += *q;
v = (const struct t4_vpd_hdr *)vpd;
vpdr_len = pci_vpd_lrdt_size(&v->vpdr_tag);
if (vpdr_len + sizeof(struct t4_vpd_hdr) > VPD_LEN) {
dev_err(adapter->pdev_dev, "bad VPD-R length %u\n", vpdr_len);
return -EINVAL;
}

#define FIND_VPD_KW(var, name) do { \
var = pci_vpd_find_info_keyword(&v->id_tag, sizeof(struct t4_vpd_hdr), \
vpdr_len, name); \
if (var < 0) { \
dev_err(adapter->pdev_dev, "missing VPD keyword " name "\n"); \
return -EINVAL; \
} \
var += PCI_VPD_INFO_FLD_HDR_SIZE; \
} while (0)

FIND_VPD_KW(i, "RV");
for (csum = 0; i >= 0; i--)
csum += vpd[i];

if (csum) {
dev_err(adapter->pdev_dev,
"corrupted VPD EEPROM, actual csum %u\n", csum);
return -EINVAL;
}

p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10);
memcpy(p->id, vpd.id_data, sizeof(vpd.id_data));
FIND_VPD_KW(ec, "EC");
FIND_VPD_KW(sn, "SN");
FIND_VPD_KW(v2, "V2");
#undef FIND_VPD_KW

p->cclk = simple_strtoul(vpd + v2, NULL, 10);
memcpy(p->id, v->id_data, ID_LEN);
strim(p->id);
memcpy(p->ec, vpd.ec_data, sizeof(vpd.ec_data));
memcpy(p->ec, vpd + ec, EC_LEN);
strim(p->ec);
memcpy(p->sn, vpd.sn_data, sizeof(vpd.sn_data));
i = pci_vpd_info_field_size(vpd + sn - PCI_VPD_INFO_FLD_HDR_SIZE);
memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN));
strim(p->sn);
return 0;
}
Expand Down

0 comments on commit 226ec5f

Please sign in to comment.