aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/cxgb4
diff options
context:
space:
mode:
authorDimitris Michailidis <dm@chelsio.com>2010-04-27 08:24:15 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-27 18:46:42 -0400
commit226ec5fd6746c0ef2e9efb583b44d01264ea0bb5 (patch)
tree6191d304c270c8abae9bd99f9f942a439c1b3ad3 /drivers/net/cxgb4
parentc377411f2494a931ff7facdbb3a6839b1266bcf6 (diff)
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>
Diffstat (limited to 'drivers/net/cxgb4')
-rw-r--r--drivers/net/cxgb4/t4_hw.c64
1 files changed, 39 insertions, 25 deletions
diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c
index cadead5170f5..2923dd43523d 100644
--- a/drivers/net/cxgb4/t4_hw.c
+++ b/drivers/net/cxgb4/t4_hw.c
@@ -347,33 +347,21 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
347 return 0; 347 return 0;
348} 348}
349 349
350#define VPD_ENTRY(name, len) \
351 u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
352
353/* 350/*
354 * Partial EEPROM Vital Product Data structure. Includes only the ID and 351 * Partial EEPROM Vital Product Data structure. Includes only the ID and
355 * VPD-R sections. 352 * VPD-R header.
356 */ 353 */
357struct t4_vpd { 354struct t4_vpd_hdr {
358 u8 id_tag; 355 u8 id_tag;
359 u8 id_len[2]; 356 u8 id_len[2];
360 u8 id_data[ID_LEN]; 357 u8 id_data[ID_LEN];
361 u8 vpdr_tag; 358 u8 vpdr_tag;
362 u8 vpdr_len[2]; 359 u8 vpdr_len[2];
363 VPD_ENTRY(pn, 16); /* part number */
364 VPD_ENTRY(ec, EC_LEN); /* EC level */
365 VPD_ENTRY(sn, SERNUM_LEN); /* serial number */
366 VPD_ENTRY(na, 12); /* MAC address base */
367 VPD_ENTRY(port_type, 8); /* port types */
368 VPD_ENTRY(gpio, 14); /* GPIO usage */
369 VPD_ENTRY(cclk, 6); /* core clock */
370 VPD_ENTRY(port_addr, 8); /* port MDIO addresses */
371 VPD_ENTRY(rv, 1); /* csum */
372 u32 pad; /* for multiple-of-4 sizing and alignment */
373}; 360};
374 361
375#define EEPROM_STAT_ADDR 0x7bfc 362#define EEPROM_STAT_ADDR 0x7bfc
376#define VPD_BASE 0 363#define VPD_BASE 0
364#define VPD_LEN 512
377 365
378/** 366/**
379 * t4_seeprom_wp - enable/disable EEPROM write protection 367 * t4_seeprom_wp - enable/disable EEPROM write protection
@@ -398,16 +386,36 @@ int t4_seeprom_wp(struct adapter *adapter, bool enable)
398 */ 386 */
399static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) 387static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
400{ 388{
401 int ret; 389 int i, ret;
402 struct t4_vpd vpd; 390 int ec, sn, v2;
403 u8 *q = (u8 *)&vpd, csum; 391 u8 vpd[VPD_LEN], csum;
392 unsigned int vpdr_len;
393 const struct t4_vpd_hdr *v;
404 394
405 ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(vpd), &vpd); 395 ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(vpd), vpd);
406 if (ret < 0) 396 if (ret < 0)
407 return ret; 397 return ret;
408 398
409 for (csum = 0; q <= vpd.rv_data; q++) 399 v = (const struct t4_vpd_hdr *)vpd;
410 csum += *q; 400 vpdr_len = pci_vpd_lrdt_size(&v->vpdr_tag);
401 if (vpdr_len + sizeof(struct t4_vpd_hdr) > VPD_LEN) {
402 dev_err(adapter->pdev_dev, "bad VPD-R length %u\n", vpdr_len);
403 return -EINVAL;
404 }
405
406#define FIND_VPD_KW(var, name) do { \
407 var = pci_vpd_find_info_keyword(&v->id_tag, sizeof(struct t4_vpd_hdr), \
408 vpdr_len, name); \
409 if (var < 0) { \
410 dev_err(adapter->pdev_dev, "missing VPD keyword " name "\n"); \
411 return -EINVAL; \
412 } \
413 var += PCI_VPD_INFO_FLD_HDR_SIZE; \
414} while (0)
415
416 FIND_VPD_KW(i, "RV");
417 for (csum = 0; i >= 0; i--)
418 csum += vpd[i];
411 419
412 if (csum) { 420 if (csum) {
413 dev_err(adapter->pdev_dev, 421 dev_err(adapter->pdev_dev,
@@ -415,12 +423,18 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
415 return -EINVAL; 423 return -EINVAL;
416 } 424 }
417 425
418 p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10); 426 FIND_VPD_KW(ec, "EC");
419 memcpy(p->id, vpd.id_data, sizeof(vpd.id_data)); 427 FIND_VPD_KW(sn, "SN");
428 FIND_VPD_KW(v2, "V2");
429#undef FIND_VPD_KW
430
431 p->cclk = simple_strtoul(vpd + v2, NULL, 10);
432 memcpy(p->id, v->id_data, ID_LEN);
420 strim(p->id); 433 strim(p->id);
421 memcpy(p->ec, vpd.ec_data, sizeof(vpd.ec_data)); 434 memcpy(p->ec, vpd + ec, EC_LEN);
422 strim(p->ec); 435 strim(p->ec);
423 memcpy(p->sn, vpd.sn_data, sizeof(vpd.sn_data)); 436 i = pci_vpd_info_field_size(vpd + sn - PCI_VPD_INFO_FLD_HDR_SIZE);
437 memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN));
424 strim(p->sn); 438 strim(p->sn);
425 return 0; 439 return 0;
426} 440}