@@ -133,6 +133,16 @@ static struct hw2ethtool_link_mode
133133 },
134134};
135135
136+ #define LP_DEFAULT_TIME 5 /* seconds */
137+ #define LP_PKT_LEN 1514
138+
139+ #define PORT_DOWN_ERR_IDX 0
140+ enum diag_test_index {
141+ INTERNAL_LP_TEST = 0 ,
142+ EXTERNAL_LP_TEST = 1 ,
143+ DIAG_TEST_MAX = 2 ,
144+ };
145+
136146static void set_link_speed (struct ethtool_link_ksettings * link_ksettings ,
137147 enum hinic_speed speed )
138148{
@@ -1244,6 +1254,11 @@ static struct hinic_stats hinic_function_stats[] = {
12441254 HINIC_FUNC_STAT (rx_err_vport ),
12451255};
12461256
1257+ static char hinic_test_strings [][ETH_GSTRING_LEN ] = {
1258+ "Internal lb test (on/offline)" ,
1259+ "External lb test (external_lb)" ,
1260+ };
1261+
12471262#define HINIC_PORT_STAT (_stat_item ) { \
12481263 .name = #_stat_item, \
12491264 .size = sizeof_field(struct hinic_phy_port_stats, _stat_item), \
@@ -1453,6 +1468,8 @@ static int hinic_get_sset_count(struct net_device *netdev, int sset)
14531468 int count , q_num ;
14541469
14551470 switch (sset ) {
1471+ case ETH_SS_TEST :
1472+ return ARRAY_LEN (hinic_test_strings );
14561473 case ETH_SS_STATS :
14571474 q_num = nic_dev -> num_qps ;
14581475 count = ARRAY_LEN (hinic_function_stats ) +
@@ -1475,6 +1492,9 @@ static void hinic_get_strings(struct net_device *netdev,
14751492 u16 i , j ;
14761493
14771494 switch (stringset ) {
1495+ case ETH_SS_TEST :
1496+ memcpy (data , * hinic_test_strings , sizeof (hinic_test_strings ));
1497+ return ;
14781498 case ETH_SS_STATS :
14791499 for (i = 0 ; i < ARRAY_LEN (hinic_function_stats ); i ++ ) {
14801500 memcpy (p , hinic_function_stats [i ].name ,
@@ -1508,6 +1528,162 @@ static void hinic_get_strings(struct net_device *netdev,
15081528 }
15091529}
15101530
1531+ static int hinic_run_lp_test (struct hinic_dev * nic_dev , u32 test_time )
1532+ {
1533+ u8 * lb_test_rx_buf = nic_dev -> lb_test_rx_buf ;
1534+ struct net_device * netdev = nic_dev -> netdev ;
1535+ struct sk_buff * skb_tmp = NULL ;
1536+ struct sk_buff * skb = NULL ;
1537+ u32 cnt = test_time * 5 ;
1538+ u8 * test_data = NULL ;
1539+ u32 i ;
1540+ u8 j ;
1541+
1542+ skb_tmp = alloc_skb (LP_PKT_LEN , GFP_ATOMIC );
1543+ if (!skb_tmp )
1544+ return - ENOMEM ;
1545+
1546+ test_data = __skb_put (skb_tmp , LP_PKT_LEN );
1547+
1548+ memset (test_data , 0xFF , 2 * ETH_ALEN );
1549+ test_data [ETH_ALEN ] = 0xFE ;
1550+ test_data [2 * ETH_ALEN ] = 0x08 ;
1551+ test_data [2 * ETH_ALEN + 1 ] = 0x0 ;
1552+
1553+ for (i = ETH_HLEN ; i < LP_PKT_LEN ; i ++ )
1554+ test_data [i ] = i & 0xFF ;
1555+
1556+ skb_tmp -> queue_mapping = 0 ;
1557+ skb_tmp -> ip_summed = CHECKSUM_COMPLETE ;
1558+ skb_tmp -> dev = netdev ;
1559+
1560+ for (i = 0 ; i < cnt ; i ++ ) {
1561+ nic_dev -> lb_test_rx_idx = 0 ;
1562+ memset (lb_test_rx_buf , 0 , LP_PKT_CNT * LP_PKT_LEN );
1563+
1564+ for (j = 0 ; j < LP_PKT_CNT ; j ++ ) {
1565+ skb = pskb_copy (skb_tmp , GFP_ATOMIC );
1566+ if (!skb ) {
1567+ dev_kfree_skb_any (skb_tmp );
1568+ netif_err (nic_dev , drv , netdev ,
1569+ "Copy skb failed for loopback test\n" );
1570+ return - ENOMEM ;
1571+ }
1572+
1573+ /* mark index for every pkt */
1574+ skb -> data [LP_PKT_LEN - 1 ] = j ;
1575+
1576+ if (hinic_lb_xmit_frame (skb , netdev )) {
1577+ dev_kfree_skb_any (skb );
1578+ dev_kfree_skb_any (skb_tmp );
1579+ netif_err (nic_dev , drv , netdev ,
1580+ "Xmit pkt failed for loopback test\n" );
1581+ return - EBUSY ;
1582+ }
1583+ }
1584+
1585+ /* wait till all pkts received to RX buffer */
1586+ msleep (200 );
1587+
1588+ for (j = 0 ; j < LP_PKT_CNT ; j ++ ) {
1589+ if (memcmp (lb_test_rx_buf + j * LP_PKT_LEN ,
1590+ skb_tmp -> data , LP_PKT_LEN - 1 ) ||
1591+ (* (lb_test_rx_buf + j * LP_PKT_LEN +
1592+ LP_PKT_LEN - 1 ) != j )) {
1593+ dev_kfree_skb_any (skb_tmp );
1594+ netif_err (nic_dev , drv , netdev ,
1595+ "Compare pkt failed in loopback test(index=0x%02x, data[%d]=0x%02x)\n" ,
1596+ j + i * LP_PKT_CNT ,
1597+ LP_PKT_LEN - 1 ,
1598+ * (lb_test_rx_buf + j * LP_PKT_LEN +
1599+ LP_PKT_LEN - 1 ));
1600+ return - EIO ;
1601+ }
1602+ }
1603+ }
1604+
1605+ dev_kfree_skb_any (skb_tmp );
1606+ return 0 ;
1607+ }
1608+
1609+ static int do_lp_test (struct hinic_dev * nic_dev , u32 flags , u32 test_time ,
1610+ enum diag_test_index * test_index )
1611+ {
1612+ struct net_device * netdev = nic_dev -> netdev ;
1613+ u8 * lb_test_rx_buf = NULL ;
1614+ int err = 0 ;
1615+
1616+ if (!(flags & ETH_TEST_FL_EXTERNAL_LB )) {
1617+ * test_index = INTERNAL_LP_TEST ;
1618+ if (hinic_set_loopback_mode (nic_dev -> hwdev ,
1619+ HINIC_INTERNAL_LP_MODE , true)) {
1620+ netif_err (nic_dev , drv , netdev ,
1621+ "Failed to set port loopback mode before loopback test\n" );
1622+ return - EIO ;
1623+ }
1624+ } else {
1625+ * test_index = EXTERNAL_LP_TEST ;
1626+ }
1627+
1628+ lb_test_rx_buf = vmalloc (LP_PKT_CNT * LP_PKT_LEN );
1629+ if (!lb_test_rx_buf ) {
1630+ err = - ENOMEM ;
1631+ } else {
1632+ nic_dev -> lb_test_rx_buf = lb_test_rx_buf ;
1633+ nic_dev -> lb_pkt_len = LP_PKT_LEN ;
1634+ nic_dev -> flags |= HINIC_LP_TEST ;
1635+ err = hinic_run_lp_test (nic_dev , test_time );
1636+ nic_dev -> flags &= ~HINIC_LP_TEST ;
1637+ msleep (100 );
1638+ vfree (lb_test_rx_buf );
1639+ nic_dev -> lb_test_rx_buf = NULL ;
1640+ }
1641+
1642+ if (!(flags & ETH_TEST_FL_EXTERNAL_LB )) {
1643+ if (hinic_set_loopback_mode (nic_dev -> hwdev ,
1644+ HINIC_INTERNAL_LP_MODE , false)) {
1645+ netif_err (nic_dev , drv , netdev ,
1646+ "Failed to cancel port loopback mode after loopback test\n" );
1647+ err = - EIO ;
1648+ }
1649+ }
1650+
1651+ return err ;
1652+ }
1653+
1654+ static void hinic_diag_test (struct net_device * netdev ,
1655+ struct ethtool_test * eth_test , u64 * data )
1656+ {
1657+ struct hinic_dev * nic_dev = netdev_priv (netdev );
1658+ enum hinic_port_link_state link_state ;
1659+ enum diag_test_index test_index = 0 ;
1660+ int err = 0 ;
1661+
1662+ memset (data , 0 , DIAG_TEST_MAX * sizeof (u64 ));
1663+
1664+ /* don't support loopback test when netdev is closed. */
1665+ if (!(nic_dev -> flags & HINIC_INTF_UP )) {
1666+ netif_err (nic_dev , drv , netdev ,
1667+ "Do not support loopback test when netdev is closed\n" );
1668+ eth_test -> flags |= ETH_TEST_FL_FAILED ;
1669+ data [PORT_DOWN_ERR_IDX ] = 1 ;
1670+ return ;
1671+ }
1672+
1673+ netif_carrier_off (netdev );
1674+
1675+ err = do_lp_test (nic_dev , eth_test -> flags , LP_DEFAULT_TIME ,
1676+ & test_index );
1677+ if (err ) {
1678+ eth_test -> flags |= ETH_TEST_FL_FAILED ;
1679+ data [test_index ] = 1 ;
1680+ }
1681+
1682+ err = hinic_port_link_state (nic_dev , & link_state );
1683+ if (!err && link_state == HINIC_LINK_STATE_UP )
1684+ netif_carrier_on (netdev );
1685+ }
1686+
15111687static const struct ethtool_ops hinic_ethtool_ops = {
15121688 .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
15131689 ETHTOOL_COALESCE_RX_MAX_FRAMES |
@@ -1537,6 +1713,7 @@ static const struct ethtool_ops hinic_ethtool_ops = {
15371713 .get_sset_count = hinic_get_sset_count ,
15381714 .get_ethtool_stats = hinic_get_ethtool_stats ,
15391715 .get_strings = hinic_get_strings ,
1716+ .self_test = hinic_diag_test ,
15401717};
15411718
15421719static const struct ethtool_ops hinicvf_ethtool_ops = {
0 commit comments