18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2007 Mellanox Technologies. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/kernel.h> 358c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 368c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 378c2ecf20Sopenharmony_ci#include <linux/delay.h> 388c2ecf20Sopenharmony_ci#include <linux/mlx4/driver.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include "mlx4_en.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic int mlx4_en_test_registers(struct mlx4_en_priv *priv) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci return mlx4_cmd(priv->mdev->dev, 0, 0, 0, MLX4_CMD_HW_HEALTH_CHECK, 468c2ecf20Sopenharmony_ci MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic int mlx4_en_test_loopback_xmit(struct mlx4_en_priv *priv) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct sk_buff *skb; 528c2ecf20Sopenharmony_ci struct ethhdr *ethh; 538c2ecf20Sopenharmony_ci unsigned char *packet; 548c2ecf20Sopenharmony_ci unsigned int packet_size = MLX4_LOOPBACK_TEST_PAYLOAD; 558c2ecf20Sopenharmony_ci unsigned int i; 568c2ecf20Sopenharmony_ci int err; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* build the pkt before xmit */ 608c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(priv->dev, MLX4_LOOPBACK_TEST_PAYLOAD + ETH_HLEN + NET_IP_ALIGN); 618c2ecf20Sopenharmony_ci if (!skb) 628c2ecf20Sopenharmony_ci return -ENOMEM; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci skb_reserve(skb, NET_IP_ALIGN); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci ethh = skb_put(skb, sizeof(struct ethhdr)); 678c2ecf20Sopenharmony_ci packet = skb_put(skb, packet_size); 688c2ecf20Sopenharmony_ci memcpy(ethh->h_dest, priv->dev->dev_addr, ETH_ALEN); 698c2ecf20Sopenharmony_ci eth_zero_addr(ethh->h_source); 708c2ecf20Sopenharmony_ci ethh->h_proto = htons(ETH_P_ARP); 718c2ecf20Sopenharmony_ci skb_reset_mac_header(skb); 728c2ecf20Sopenharmony_ci for (i = 0; i < packet_size; ++i) /* fill our packet */ 738c2ecf20Sopenharmony_ci packet[i] = (unsigned char)(i & 0xff); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* xmit the pkt */ 768c2ecf20Sopenharmony_ci err = mlx4_en_xmit(skb, priv->dev); 778c2ecf20Sopenharmony_ci return err; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int mlx4_en_test_loopback(struct mlx4_en_priv *priv) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci u32 loopback_ok = 0; 838c2ecf20Sopenharmony_ci int i; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci priv->loopback_ok = 0; 868c2ecf20Sopenharmony_ci priv->validate_loopback = 1; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci mlx4_en_update_loopback_state(priv->dev, priv->dev->features); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* xmit */ 918c2ecf20Sopenharmony_ci if (mlx4_en_test_loopback_xmit(priv)) { 928c2ecf20Sopenharmony_ci en_err(priv, "Transmitting loopback packet failed\n"); 938c2ecf20Sopenharmony_ci goto mlx4_en_test_loopback_exit; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* polling for result */ 978c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_EN_LOOPBACK_RETRIES; ++i) { 988c2ecf20Sopenharmony_ci msleep(MLX4_EN_LOOPBACK_TIMEOUT); 998c2ecf20Sopenharmony_ci if (priv->loopback_ok) { 1008c2ecf20Sopenharmony_ci loopback_ok = 1; 1018c2ecf20Sopenharmony_ci break; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci if (!loopback_ok) 1058c2ecf20Sopenharmony_ci en_err(priv, "Loopback packet didn't arrive\n"); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cimlx4_en_test_loopback_exit: 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci priv->validate_loopback = 0; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci mlx4_en_update_loopback_state(priv->dev, priv->dev->features); 1128c2ecf20Sopenharmony_ci return !loopback_ok; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int mlx4_en_test_interrupts(struct mlx4_en_priv *priv) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 1188c2ecf20Sopenharmony_ci int err = 0; 1198c2ecf20Sopenharmony_ci int i = 0; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci err = mlx4_test_async(mdev->dev); 1228c2ecf20Sopenharmony_ci /* When not in MSI_X or slave, test only async */ 1238c2ecf20Sopenharmony_ci if (!(mdev->dev->flags & MLX4_FLAG_MSI_X) || mlx4_is_slave(mdev->dev)) 1248c2ecf20Sopenharmony_ci return err; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* A loop over all completion vectors of current port, 1278c2ecf20Sopenharmony_ci * for each vector check whether it works by mapping command 1288c2ecf20Sopenharmony_ci * completions to that vector and performing a NOP command 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 1318c2ecf20Sopenharmony_ci err = mlx4_test_interrupt(mdev->dev, priv->rx_cq[i]->vector); 1328c2ecf20Sopenharmony_ci if (err) 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return err; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int mlx4_en_test_link(struct mlx4_en_priv *priv) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) 1428c2ecf20Sopenharmony_ci return -ENOMEM; 1438c2ecf20Sopenharmony_ci if (priv->port_state.link_state == 1) 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci else 1468c2ecf20Sopenharmony_ci return 1; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int mlx4_en_test_speed(struct mlx4_en_priv *priv) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) 1538c2ecf20Sopenharmony_ci return -ENOMEM; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* The device supports 100M, 1G, 10G, 20G, 40G and 56G speed */ 1568c2ecf20Sopenharmony_ci if (priv->port_state.link_speed != SPEED_100 && 1578c2ecf20Sopenharmony_ci priv->port_state.link_speed != SPEED_1000 && 1588c2ecf20Sopenharmony_ci priv->port_state.link_speed != SPEED_10000 && 1598c2ecf20Sopenharmony_ci priv->port_state.link_speed != SPEED_20000 && 1608c2ecf20Sopenharmony_ci priv->port_state.link_speed != SPEED_40000 && 1618c2ecf20Sopenharmony_ci priv->port_state.link_speed != SPEED_56000) 1628c2ecf20Sopenharmony_ci return priv->port_state.link_speed; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_civoid mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 1718c2ecf20Sopenharmony_ci int i, carrier_ok; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci memset(buf, 0, sizeof(u64) * MLX4_EN_NUM_SELF_TEST); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (*flags & ETH_TEST_FL_OFFLINE) { 1768c2ecf20Sopenharmony_ci /* disable the interface */ 1778c2ecf20Sopenharmony_ci carrier_ok = netif_carrier_ok(dev); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci netif_carrier_off(dev); 1808c2ecf20Sopenharmony_ci /* Wait until all tx queues are empty. 1818c2ecf20Sopenharmony_ci * there should not be any additional incoming traffic 1828c2ecf20Sopenharmony_ci * since we turned the carrier off */ 1838c2ecf20Sopenharmony_ci msleep(200); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (priv->mdev->dev->caps.flags & 1868c2ecf20Sopenharmony_ci MLX4_DEV_CAP_FLAG_UC_LOOPBACK) { 1878c2ecf20Sopenharmony_ci buf[3] = mlx4_en_test_registers(priv); 1888c2ecf20Sopenharmony_ci if (priv->port_up && dev->mtu >= MLX4_SELFTEST_LB_MIN_MTU) 1898c2ecf20Sopenharmony_ci buf[4] = mlx4_en_test_loopback(priv); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (carrier_ok) 1938c2ecf20Sopenharmony_ci netif_carrier_on(dev); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci buf[0] = mlx4_en_test_interrupts(priv); 1978c2ecf20Sopenharmony_ci buf[1] = mlx4_en_test_link(priv); 1988c2ecf20Sopenharmony_ci buf[2] = mlx4_en_test_speed(priv); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_EN_NUM_SELF_TEST; i++) { 2018c2ecf20Sopenharmony_ci if (buf[i]) 2028c2ecf20Sopenharmony_ci *flags |= ETH_TEST_FL_FAILED; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci} 205