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 | }; |