cxgb4: parse the VPD instead of relying on a static VPD layout
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>
This commit is contained in:
parent
c377411f24
commit
226ec5fd67
|
@ -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
|
||||
|
@ -398,16 +386,36 @@ 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,
|
||||
|
@ -415,12 +423,18 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
|
|||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue