diff options
| author | Suresh R <sureshr@serverengines.com> | 2009-12-03 19:15:52 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-12-03 19:15:52 -0500 |
| commit | ff33a6e2ab97f4cde484cdf1a41778af6d6b7cff (patch) | |
| tree | 655e8cc5a61e6ed5245b182217fbca9632d17499 | |
| parent | 49d09007879ce7bee36ab453c73e97c00adce884 (diff) | |
be2net: Add support for ethtool self test
This patch adds support for ethtool selftest.
From: Suresh R <sureshr@serverengines.com>
Signed-off-by: Ajit Khaparde <ajitk@serverengines.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | drivers/net/benet/be_cmds.c | 93 | ||||
| -rw-r--r-- | drivers/net/benet/be_cmds.h | 48 | ||||
| -rw-r--r-- | drivers/net/benet/be_ethtool.c | 82 |
3 files changed, 223 insertions, 0 deletions
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index bee7b822d120..1b68bd98dc0c 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c | |||
| @@ -1478,3 +1478,96 @@ err: | |||
| 1478 | spin_unlock_bh(&adapter->mcc_lock); | 1478 | spin_unlock_bh(&adapter->mcc_lock); |
| 1479 | return status; | 1479 | return status; |
| 1480 | } | 1480 | } |
| 1481 | |||
| 1482 | int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, | ||
| 1483 | u32 loopback_type, u32 pkt_size, u32 num_pkts, u64 pattern) | ||
| 1484 | { | ||
| 1485 | struct be_mcc_wrb *wrb; | ||
| 1486 | struct be_cmd_req_loopback_test *req; | ||
| 1487 | int status; | ||
| 1488 | |||
| 1489 | spin_lock_bh(&adapter->mcc_lock); | ||
| 1490 | |||
| 1491 | wrb = wrb_from_mccq(adapter); | ||
| 1492 | if (!wrb) { | ||
| 1493 | status = -EBUSY; | ||
| 1494 | goto err; | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | req = embedded_payload(wrb); | ||
| 1498 | |||
| 1499 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, | ||
| 1500 | OPCODE_LOWLEVEL_LOOPBACK_TEST); | ||
| 1501 | |||
| 1502 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, | ||
| 1503 | OPCODE_LOWLEVEL_LOOPBACK_TEST, sizeof(*req)); | ||
| 1504 | |||
| 1505 | req->pattern = cpu_to_le64(pattern); | ||
| 1506 | req->src_port = cpu_to_le32(port_num); | ||
| 1507 | req->dest_port = cpu_to_le32(port_num); | ||
| 1508 | req->pkt_size = cpu_to_le32(pkt_size); | ||
| 1509 | req->num_pkts = cpu_to_le32(num_pkts); | ||
| 1510 | req->loopback_type = cpu_to_le32(loopback_type); | ||
| 1511 | |||
| 1512 | status = be_mcc_notify_wait(adapter); | ||
| 1513 | if (!status) { | ||
| 1514 | struct be_cmd_resp_loopback_test *resp = embedded_payload(wrb); | ||
| 1515 | status = le32_to_cpu(resp->status); | ||
| 1516 | } | ||
| 1517 | |||
| 1518 | err: | ||
| 1519 | spin_unlock_bh(&adapter->mcc_lock); | ||
| 1520 | return status; | ||
| 1521 | } | ||
| 1522 | |||
| 1523 | int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern, | ||
| 1524 | u32 byte_cnt, struct be_dma_mem *cmd) | ||
| 1525 | { | ||
| 1526 | struct be_mcc_wrb *wrb; | ||
| 1527 | struct be_cmd_req_ddrdma_test *req; | ||
| 1528 | struct be_sge *sge; | ||
| 1529 | int status; | ||
| 1530 | int i, j = 0; | ||
| 1531 | |||
| 1532 | spin_lock_bh(&adapter->mcc_lock); | ||
| 1533 | |||
| 1534 | wrb = wrb_from_mccq(adapter); | ||
| 1535 | if (!wrb) { | ||
| 1536 | status = -EBUSY; | ||
| 1537 | goto err; | ||
| 1538 | } | ||
| 1539 | req = cmd->va; | ||
| 1540 | sge = nonembedded_sgl(wrb); | ||
| 1541 | be_wrb_hdr_prepare(wrb, cmd->size, false, 1, | ||
| 1542 | OPCODE_LOWLEVEL_HOST_DDR_DMA); | ||
| 1543 | be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, | ||
| 1544 | OPCODE_LOWLEVEL_HOST_DDR_DMA, cmd->size); | ||
| 1545 | |||
| 1546 | sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma)); | ||
| 1547 | sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF); | ||
| 1548 | sge->len = cpu_to_le32(cmd->size); | ||
| 1549 | |||
| 1550 | req->pattern = cpu_to_le64(pattern); | ||
| 1551 | req->byte_count = cpu_to_le32(byte_cnt); | ||
| 1552 | for (i = 0; i < byte_cnt; i++) { | ||
| 1553 | req->snd_buff[i] = (u8)(pattern >> (j*8)); | ||
| 1554 | j++; | ||
| 1555 | if (j > 7) | ||
| 1556 | j = 0; | ||
| 1557 | } | ||
| 1558 | |||
| 1559 | status = be_mcc_notify_wait(adapter); | ||
| 1560 | |||
| 1561 | if (!status) { | ||
| 1562 | struct be_cmd_resp_ddrdma_test *resp; | ||
| 1563 | resp = cmd->va; | ||
| 1564 | if ((memcmp(resp->rcv_buff, req->snd_buff, byte_cnt) != 0) || | ||
| 1565 | resp->snd_err) { | ||
| 1566 | status = -1; | ||
| 1567 | } | ||
| 1568 | } | ||
| 1569 | |||
| 1570 | err: | ||
| 1571 | spin_unlock_bh(&adapter->mcc_lock); | ||
| 1572 | return status; | ||
| 1573 | } | ||
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index e8512a144f5e..e7323be507d0 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h | |||
| @@ -112,6 +112,7 @@ struct be_mcc_mailbox { | |||
| 112 | 112 | ||
| 113 | #define CMD_SUBSYSTEM_COMMON 0x1 | 113 | #define CMD_SUBSYSTEM_COMMON 0x1 |
| 114 | #define CMD_SUBSYSTEM_ETH 0x3 | 114 | #define CMD_SUBSYSTEM_ETH 0x3 |
| 115 | #define CMD_SUBSYSTEM_LOWLEVEL 0xb | ||
| 115 | 116 | ||
| 116 | #define OPCODE_COMMON_NTWK_MAC_QUERY 1 | 117 | #define OPCODE_COMMON_NTWK_MAC_QUERY 1 |
| 117 | #define OPCODE_COMMON_NTWK_MAC_SET 2 | 118 | #define OPCODE_COMMON_NTWK_MAC_SET 2 |
| @@ -152,6 +153,9 @@ struct be_mcc_mailbox { | |||
| 152 | #define OPCODE_ETH_RX_DESTROY 10 | 153 | #define OPCODE_ETH_RX_DESTROY 10 |
| 153 | #define OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG 12 | 154 | #define OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG 12 |
| 154 | 155 | ||
| 156 | #define OPCODE_LOWLEVEL_HOST_DDR_DMA 17 | ||
| 157 | #define OPCODE_LOWLEVEL_LOOPBACK_TEST 18 | ||
| 158 | |||
| 155 | struct be_cmd_req_hdr { | 159 | struct be_cmd_req_hdr { |
| 156 | u8 opcode; /* dword 0 */ | 160 | u8 opcode; /* dword 0 */ |
| 157 | u8 subsystem; /* dword 0 */ | 161 | u8 subsystem; /* dword 0 */ |
| @@ -797,6 +801,45 @@ struct be_cmd_req_acpi_wol_magic_config{ | |||
| 797 | u8 rsvd2[2]; | 801 | u8 rsvd2[2]; |
| 798 | } __packed; | 802 | } __packed; |
| 799 | 803 | ||
| 804 | /********************** LoopBack test *********************/ | ||
| 805 | struct be_cmd_req_loopback_test { | ||
| 806 | struct be_cmd_req_hdr hdr; | ||
| 807 | u32 loopback_type; | ||
| 808 | u32 num_pkts; | ||
| 809 | u64 pattern; | ||
| 810 | u32 src_port; | ||
| 811 | u32 dest_port; | ||
| 812 | u32 pkt_size; | ||
| 813 | }; | ||
| 814 | |||
| 815 | struct be_cmd_resp_loopback_test { | ||
| 816 | struct be_cmd_resp_hdr resp_hdr; | ||
| 817 | u32 status; | ||
| 818 | u32 num_txfer; | ||
| 819 | u32 num_rx; | ||
| 820 | u32 miscomp_off; | ||
| 821 | u32 ticks_compl; | ||
| 822 | }; | ||
| 823 | |||
| 824 | /********************** DDR DMA test *********************/ | ||
| 825 | struct be_cmd_req_ddrdma_test { | ||
| 826 | struct be_cmd_req_hdr hdr; | ||
| 827 | u64 pattern; | ||
| 828 | u32 byte_count; | ||
| 829 | u32 rsvd0; | ||
| 830 | u8 snd_buff[4096]; | ||
| 831 | u8 rsvd1[4096]; | ||
| 832 | }; | ||
| 833 | |||
| 834 | struct be_cmd_resp_ddrdma_test { | ||
| 835 | struct be_cmd_resp_hdr hdr; | ||
| 836 | u64 pattern; | ||
| 837 | u32 byte_cnt; | ||
| 838 | u32 snd_err; | ||
| 839 | u8 rsvd0[4096]; | ||
| 840 | u8 rcv_buff[4096]; | ||
| 841 | }; | ||
| 842 | |||
| 800 | extern int be_pci_fnum_get(struct be_adapter *adapter); | 843 | extern int be_pci_fnum_get(struct be_adapter *adapter); |
| 801 | extern int be_cmd_POST(struct be_adapter *adapter); | 844 | extern int be_cmd_POST(struct be_adapter *adapter); |
| 802 | extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, | 845 | extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, |
| @@ -864,3 +907,8 @@ extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, | |||
| 864 | struct be_dma_mem *nonemb_cmd); | 907 | struct be_dma_mem *nonemb_cmd); |
| 865 | extern int be_cmd_fw_init(struct be_adapter *adapter); | 908 | extern int be_cmd_fw_init(struct be_adapter *adapter); |
| 866 | extern int be_cmd_fw_clean(struct be_adapter *adapter); | 909 | extern int be_cmd_fw_clean(struct be_adapter *adapter); |
| 910 | extern int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, | ||
| 911 | u32 loopback_type, u32 pkt_size, | ||
| 912 | u32 num_pkts, u64 pattern); | ||
| 913 | extern int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern, | ||
| 914 | u32 byte_cnt, struct be_dma_mem *cmd); | ||
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index 83a2fc703995..298b92cbd689 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c | |||
| @@ -107,6 +107,18 @@ static const struct be_ethtool_stat et_stats[] = { | |||
| 107 | }; | 107 | }; |
| 108 | #define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats) | 108 | #define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats) |
| 109 | 109 | ||
| 110 | static const char et_self_tests[][ETH_GSTRING_LEN] = { | ||
| 111 | "MAC Loopback test", | ||
| 112 | "PHY Loopback test", | ||
| 113 | "External Loopback test", | ||
| 114 | "DDR DMA test" | ||
| 115 | }; | ||
| 116 | |||
| 117 | #define ETHTOOL_TESTS_NUM ARRAY_SIZE(et_self_tests) | ||
| 118 | #define BE_MAC_LOOPBACK 0x0 | ||
| 119 | #define BE_PHY_LOOPBACK 0x1 | ||
| 120 | #define BE_ONE_PORT_EXT_LOOPBACK 0x2 | ||
| 121 | |||
| 110 | static void | 122 | static void |
| 111 | be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) | 123 | be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) |
| 112 | { | 124 | { |
| @@ -278,12 +290,20 @@ be_get_stat_strings(struct net_device *netdev, uint32_t stringset, | |||
| 278 | data += ETH_GSTRING_LEN; | 290 | data += ETH_GSTRING_LEN; |
| 279 | } | 291 | } |
| 280 | break; | 292 | break; |
| 293 | case ETH_SS_TEST: | ||
| 294 | for (i = 0; i < ETHTOOL_TESTS_NUM; i++) { | ||
| 295 | memcpy(data, et_self_tests[i], ETH_GSTRING_LEN); | ||
| 296 | data += ETH_GSTRING_LEN; | ||
| 297 | } | ||
| 298 | break; | ||
| 281 | } | 299 | } |
| 282 | } | 300 | } |
| 283 | 301 | ||
| 284 | static int be_get_sset_count(struct net_device *netdev, int stringset) | 302 | static int be_get_sset_count(struct net_device *netdev, int stringset) |
| 285 | { | 303 | { |
| 286 | switch (stringset) { | 304 | switch (stringset) { |
| 305 | case ETH_SS_TEST: | ||
| 306 | return ETHTOOL_TESTS_NUM; | ||
| 287 | case ETH_SS_STATS: | 307 | case ETH_SS_STATS: |
| 288 | return ETHTOOL_STATS_NUM; | 308 | return ETHTOOL_STATS_NUM; |
| 289 | default: | 309 | default: |
| @@ -442,6 +462,67 @@ be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) | |||
| 442 | } | 462 | } |
| 443 | 463 | ||
| 444 | static int | 464 | static int |
| 465 | be_test_ddr_dma(struct be_adapter *adapter) | ||
| 466 | { | ||
| 467 | int ret, i; | ||
| 468 | struct be_dma_mem ddrdma_cmd; | ||
| 469 | u64 pattern[2] = {0x5a5a5a5a5a5a5a5a, 0xa5a5a5a5a5a5a5a5}; | ||
| 470 | |||
| 471 | ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test); | ||
| 472 | ddrdma_cmd.va = pci_alloc_consistent(adapter->pdev, ddrdma_cmd.size, | ||
| 473 | &ddrdma_cmd.dma); | ||
| 474 | if (!ddrdma_cmd.va) { | ||
| 475 | dev_err(&adapter->pdev->dev, "Memory allocation failure \n"); | ||
| 476 | return -ENOMEM; | ||
| 477 | } | ||
| 478 | |||
| 479 | for (i = 0; i < 2; i++) { | ||
| 480 | ret = be_cmd_ddr_dma_test(adapter, pattern[i], | ||
| 481 | 4096, &ddrdma_cmd); | ||
| 482 | if (ret != 0) | ||
| 483 | goto err; | ||
| 484 | } | ||
| 485 | |||
| 486 | err: | ||
| 487 | pci_free_consistent(adapter->pdev, ddrdma_cmd.size, | ||
| 488 | ddrdma_cmd.va, ddrdma_cmd.dma); | ||
| 489 | return ret; | ||
| 490 | } | ||
| 491 | |||
| 492 | static void | ||
| 493 | be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) | ||
| 494 | { | ||
| 495 | struct be_adapter *adapter = netdev_priv(netdev); | ||
| 496 | |||
| 497 | memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM); | ||
| 498 | |||
| 499 | if (test->flags & ETH_TEST_FL_OFFLINE) { | ||
| 500 | data[0] = be_cmd_loopback_test(adapter, adapter->port_num, | ||
| 501 | BE_MAC_LOOPBACK, 1500, | ||
| 502 | 2, 0xabc); | ||
| 503 | if (data[0] != 0) | ||
| 504 | test->flags |= ETH_TEST_FL_FAILED; | ||
| 505 | |||
| 506 | data[1] = be_cmd_loopback_test(adapter, adapter->port_num, | ||
| 507 | BE_PHY_LOOPBACK, 1500, | ||
| 508 | 2, 0xabc); | ||
| 509 | if (data[1] != 0) | ||
| 510 | test->flags |= ETH_TEST_FL_FAILED; | ||
| 511 | |||
| 512 | data[2] = be_cmd_loopback_test(adapter, adapter->port_num, | ||
| 513 | BE_ONE_PORT_EXT_LOOPBACK, | ||
| 514 | 1500, 2, 0xabc); | ||
| 515 | if (data[2] != 0) | ||
| 516 | test->flags |= ETH_TEST_FL_FAILED; | ||
| 517 | |||
| 518 | data[3] = be_test_ddr_dma(adapter); | ||
| 519 | if (data[3] != 0) | ||
| 520 | test->flags |= ETH_TEST_FL_FAILED; | ||
| 521 | } | ||
| 522 | |||
| 523 | } | ||
| 524 | |||
| 525 | static int | ||
| 445 | be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) | 526 | be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) |
| 446 | { | 527 | { |
| 447 | struct be_adapter *adapter = netdev_priv(netdev); | 528 | struct be_adapter *adapter = netdev_priv(netdev); |
| @@ -479,4 +560,5 @@ const struct ethtool_ops be_ethtool_ops = { | |||
| 479 | .get_sset_count = be_get_sset_count, | 560 | .get_sset_count = be_get_sset_count, |
| 480 | .get_ethtool_stats = be_get_ethtool_stats, | 561 | .get_ethtool_stats = be_get_ethtool_stats, |
| 481 | .flash_device = be_do_flash, | 562 | .flash_device = be_do_flash, |
| 563 | .self_test = be_self_test, | ||
| 482 | }; | 564 | }; |
