1219820Sjeff/* 2272407Shselasky * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff * 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#include <linux/kernel.h> 35219820Sjeff#include <linux/ethtool.h> 36219820Sjeff#include <linux/netdevice.h> 37219820Sjeff#include <linux/delay.h> 38219820Sjeff#include <linux/mlx4/driver.h> 39219820Sjeff 40272407Shselasky#include "mlx4_en.h" 41219820Sjeff 42272407Shselasky 43219820Sjeffstatic int mlx4_en_test_registers(struct mlx4_en_priv *priv) 44219820Sjeff{ 45219820Sjeff return mlx4_cmd(priv->mdev->dev, 0, 0, 0, MLX4_CMD_HW_HEALTH_CHECK, 46272407Shselasky MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 47219820Sjeff} 48219820Sjeff 49219820Sjeffstatic int mlx4_en_test_loopback_xmit(struct mlx4_en_priv *priv) 50219820Sjeff{ 51272407Shselasky struct sk_buff *skb; 52219820Sjeff struct ethhdr *ethh; 53219820Sjeff unsigned char *packet; 54219820Sjeff unsigned int packet_size = MLX4_LOOPBACK_TEST_PAYLOAD; 55219820Sjeff unsigned int i; 56219820Sjeff int err; 57219820Sjeff 58219820Sjeff 59219820Sjeff /* build the pkt before xmit */ 60272407Shselasky skb = netdev_alloc_skb(priv->dev, MLX4_LOOPBACK_TEST_PAYLOAD + ETH_HLEN + NET_IP_ALIGN); 61272407Shselasky if (!skb) { 62272407Shselasky en_err(priv, "-LOOPBACK_TEST_XMIT- failed to create skb for xmit\n"); 63219820Sjeff return -ENOMEM; 64219820Sjeff } 65272407Shselasky skb_reserve(skb, NET_IP_ALIGN); 66219820Sjeff 67272407Shselasky ethh = (struct ethhdr *)skb_put(skb, sizeof(struct ethhdr)); 68272407Shselasky packet = (unsigned char *)skb_put(skb, packet_size); 69219820Sjeff memcpy(ethh->h_dest, priv->dev->dev_addr, ETH_ALEN); 70219820Sjeff memset(ethh->h_source, 0, ETH_ALEN); 71219820Sjeff ethh->h_proto = htons(ETH_P_ARP); 72272407Shselasky skb_set_mac_header(skb, 0); 73219820Sjeff for (i = 0; i < packet_size; ++i) /* fill our packet */ 74219820Sjeff packet[i] = (unsigned char)(i & 0xff); 75219820Sjeff 76219820Sjeff /* xmit the pkt */ 77272407Shselasky err = mlx4_en_xmit(skb, priv->dev); 78219820Sjeff return err; 79219820Sjeff} 80219820Sjeff 81219820Sjeffstatic int mlx4_en_test_loopback(struct mlx4_en_priv *priv) 82219820Sjeff{ 83219820Sjeff u32 loopback_ok = 0; 84219820Sjeff int i; 85219820Sjeff 86219820Sjeff 87219820Sjeff priv->loopback_ok = 0; 88219820Sjeff priv->validate_loopback = 1; 89219820Sjeff 90272407Shselasky mlx4_en_update_loopback_state(priv->dev, priv->dev->features); 91272407Shselasky 92219820Sjeff /* xmit */ 93219820Sjeff if (mlx4_en_test_loopback_xmit(priv)) { 94219820Sjeff en_err(priv, "Transmitting loopback packet failed\n"); 95219820Sjeff goto mlx4_en_test_loopback_exit; 96219820Sjeff } 97219820Sjeff 98219820Sjeff /* polling for result */ 99219820Sjeff for (i = 0; i < MLX4_EN_LOOPBACK_RETRIES; ++i) { 100219820Sjeff msleep(MLX4_EN_LOOPBACK_TIMEOUT); 101219820Sjeff if (priv->loopback_ok) { 102219820Sjeff loopback_ok = 1; 103219820Sjeff break; 104219820Sjeff } 105219820Sjeff } 106219820Sjeff if (!loopback_ok) 107219820Sjeff en_err(priv, "Loopback packet didn't arrive\n"); 108219820Sjeff 109219820Sjeffmlx4_en_test_loopback_exit: 110219820Sjeff 111219820Sjeff priv->validate_loopback = 0; 112272407Shselasky mlx4_en_update_loopback_state(priv->dev, priv->dev->features); 113272407Shselasky return !loopback_ok; 114219820Sjeff} 115219820Sjeff 116219820Sjeff 117219820Sjeffstatic int mlx4_en_test_link(struct mlx4_en_priv *priv) 118219820Sjeff{ 119219820Sjeff if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) 120219820Sjeff return -ENOMEM; 121219820Sjeff if (priv->port_state.link_state == 1) 122219820Sjeff return 0; 123219820Sjeff else 124219820Sjeff return 1; 125219820Sjeff} 126219820Sjeff 127219820Sjeffstatic int mlx4_en_test_speed(struct mlx4_en_priv *priv) 128219820Sjeff{ 129219820Sjeff 130219820Sjeff if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) 131219820Sjeff return -ENOMEM; 132219820Sjeff 133272407Shselasky /* The device supports 1G, 10G and 40G speed */ 134272407Shselasky if (priv->port_state.link_speed != MLX4_EN_LINK_SPEED_1G && 135272407Shselasky priv->port_state.link_speed != MLX4_EN_LINK_SPEED_10G && 136272407Shselasky priv->port_state.link_speed != MLX4_EN_LINK_SPEED_40G) 137219820Sjeff return priv->port_state.link_speed; 138219820Sjeff return 0; 139219820Sjeff} 140219820Sjeff 141219820Sjeff 142219820Sjeffvoid mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf) 143219820Sjeff{ 144219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 145219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 146219820Sjeff int i, carrier_ok; 147219820Sjeff 148219820Sjeff memset(buf, 0, sizeof(u64) * MLX4_EN_NUM_SELF_TEST); 149219820Sjeff 150219820Sjeff if (*flags & ETH_TEST_FL_OFFLINE) { 151219820Sjeff /* disable the interface */ 152219820Sjeff carrier_ok = netif_carrier_ok(dev); 153219820Sjeff 154219820Sjeff netif_carrier_off(dev); 155272407Shselasky /* Wait until all tx queues are empty. 156219820Sjeff * there should not be any additional incoming traffic 157219820Sjeff * since we turned the carrier off */ 158219820Sjeff msleep(200); 159219820Sjeff 160272407Shselasky if (priv->mdev->dev->caps.flags & 161272407Shselasky MLX4_DEV_CAP_FLAG_UC_LOOPBACK) { 162219820Sjeff buf[3] = mlx4_en_test_registers(priv); 163272407Shselasky if (priv->port_up) 164272407Shselasky buf[4] = mlx4_en_test_loopback(priv); 165219820Sjeff } 166219820Sjeff 167219820Sjeff if (carrier_ok) 168219820Sjeff netif_carrier_on(dev); 169219820Sjeff 170219820Sjeff } 171219820Sjeff buf[0] = mlx4_test_interrupts(mdev->dev); 172219820Sjeff buf[1] = mlx4_en_test_link(priv); 173219820Sjeff buf[2] = mlx4_en_test_speed(priv); 174219820Sjeff 175219820Sjeff for (i = 0; i < MLX4_EN_NUM_SELF_TEST; i++) { 176219820Sjeff if (buf[i]) 177219820Sjeff *flags |= ETH_TEST_FL_FAILED; 178219820Sjeff } 179219820Sjeff} 180