1219820Sjeff/* 2219820Sjeff * Copyright (c) 2007 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 "mlx4_en.h" 35219820Sjeff 36219820Sjeff#include <linux/kernel.h> 37219820Sjeff#include <linux/ethtool.h> 38219820Sjeff#include <linux/netdevice.h> 39219820Sjeff#include <linux/delay.h> 40219820Sjeff#include <linux/mlx4/driver.h> 41219820Sjeff 42219820Sjeff 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, 46219820Sjeff MLX4_CMD_TIME_CLASS_A); 47219820Sjeff} 48219820Sjeff 49219820Sjeffstatic int mlx4_en_test_loopback_xmit(struct mlx4_en_priv *priv) 50219820Sjeff{ 51219820Sjeff struct mbuf *mb; 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 */ 60219820Sjeff mb = netdev_alloc_mb(priv->dev, MLX4_LOOPBACK_TEST_PAYLOAD + ETH_HLEN + NET_IP_ALIGN); 61219820Sjeff if (!mb) { 62219820Sjeff en_err(priv, "-LOOPBACK_TEST_XMIT- failed to create mb for xmit\n"); 63219820Sjeff return -ENOMEM; 64219820Sjeff } 65219820Sjeff mb_reserve(mb, NET_IP_ALIGN); 66219820Sjeff 67219820Sjeff ethh = (struct ethhdr *)mb_put(mb, sizeof(struct ethhdr)); 68219820Sjeff packet = (unsigned char *)mb_put(mb, 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); 72219820Sjeff mb_set_mac_header(mb, 0); 73219820Sjeff for (i = 0; i < packet_size; ++i) /* fill our packet */ 74219820Sjeff packet[i] = (unsigned char)(i & 0xff); 75219820Sjeff 76219820Sjeff /* xmit the pkt */ 77219820Sjeff err = mlx4_en_xmit(mb, 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 90219820Sjeff /* xmit */ 91219820Sjeff if (mlx4_en_test_loopback_xmit(priv)) { 92219820Sjeff en_err(priv, "Transmitting loopback packet failed\n"); 93219820Sjeff goto mlx4_en_test_loopback_exit; 94219820Sjeff } 95219820Sjeff 96219820Sjeff /* polling for result */ 97219820Sjeff for (i = 0; i < MLX4_EN_LOOPBACK_RETRIES; ++i) { 98219820Sjeff msleep(MLX4_EN_LOOPBACK_TIMEOUT); 99219820Sjeff if (priv->loopback_ok) { 100219820Sjeff loopback_ok = 1; 101219820Sjeff break; 102219820Sjeff } 103219820Sjeff } 104219820Sjeff if (!loopback_ok) 105219820Sjeff en_err(priv, "Loopback packet didn't arrive\n"); 106219820Sjeff 107219820Sjeffmlx4_en_test_loopback_exit: 108219820Sjeff 109219820Sjeff priv->validate_loopback = 0; 110219820Sjeff return (!loopback_ok); 111219820Sjeff} 112219820Sjeff 113219820Sjeff 114219820Sjeffstatic int mlx4_en_test_link(struct mlx4_en_priv *priv) 115219820Sjeff{ 116219820Sjeff if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) 117219820Sjeff return -ENOMEM; 118219820Sjeff if (priv->port_state.link_state == 1) 119219820Sjeff return 0; 120219820Sjeff else 121219820Sjeff return 1; 122219820Sjeff} 123219820Sjeff 124219820Sjeffstatic int mlx4_en_test_speed(struct mlx4_en_priv *priv) 125219820Sjeff{ 126219820Sjeff 127219820Sjeff if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) 128219820Sjeff return -ENOMEM; 129219820Sjeff 130219820Sjeff /* The device currently only supports 10G speed */ 131219820Sjeff if (priv->port_state.link_speed != SPEED_10000) 132219820Sjeff return priv->port_state.link_speed; 133219820Sjeff return 0; 134219820Sjeff} 135219820Sjeff 136219820Sjeff 137219820Sjeffvoid mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf) 138219820Sjeff{ 139219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 140219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 141219820Sjeff struct mlx4_en_tx_ring *tx_ring; 142219820Sjeff int i, carrier_ok; 143219820Sjeff 144219820Sjeff memset(buf, 0, sizeof(u64) * MLX4_EN_NUM_SELF_TEST); 145219820Sjeff 146219820Sjeff if (*flags & ETH_TEST_FL_OFFLINE) { 147219820Sjeff /* disable the interface */ 148219820Sjeff carrier_ok = netif_carrier_ok(dev); 149219820Sjeff 150219820Sjeff netif_carrier_off(dev); 151219820Sjeffretry_tx: 152219820Sjeff /* Wait untill all tx queues are empty. 153219820Sjeff * there should not be any additional incoming traffic 154219820Sjeff * since we turned the carrier off */ 155219820Sjeff msleep(200); 156219820Sjeff for (i = 0; i < priv->tx_ring_num && carrier_ok; i++) { 157219820Sjeff tx_ring = &priv->tx_ring[i]; 158219820Sjeff if (tx_ring->prod != (tx_ring->cons + tx_ring->last_nr_txbb)) 159219820Sjeff goto retry_tx; 160219820Sjeff } 161219820Sjeff 162219820Sjeff if (priv->mdev->dev->caps.loopback_support){ 163219820Sjeff buf[3] = mlx4_en_test_registers(priv); 164219820Sjeff 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