root/drivers/net/ethernet/mellanox/mlx5/core/en_selftest.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlx5e_self_test_num
  2. mlx5e_test_health_info
  3. mlx5e_test_link_state
  4. mlx5e_test_link_speed
  5. mlx5e_test_get_udp_skb
  6. mlx5e_test_loopback_validate
  7. mlx5e_test_loopback_setup
  8. mlx5e_test_loopback_cleanup
  9. mlx5e_test_loopback
  10. mlx5e_self_test

   1 /*
   2  * Copyright (c) 2016, Mellanox Technologies, Ltd.  All rights reserved.
   3  *
   4  * This software is available to you under a choice of one of two
   5  * licenses.  You may choose to be licensed under the terms of the GNU
   6  * General Public License (GPL) Version 2, available from the file
   7  * COPYING in the main directory of this source tree, or the
   8  * OpenIB.org BSD license below:
   9  *
  10  *     Redistribution and use in source and binary forms, with or
  11  *     without modification, are permitted provided that the following
  12  *     conditions are met:
  13  *
  14  *      - Redistributions of source code must retain the above
  15  *        copyright notice, this list of conditions and the following
  16  *        disclaimer.
  17  *
  18  *      - Redistributions in binary form must reproduce the above
  19  *        copyright notice, this list of conditions and the following
  20  *        disclaimer in the documentation and/or other materials
  21  *        provided with the distribution.
  22  *
  23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30  * SOFTWARE.
  31  */
  32 
  33 #include <linux/prefetch.h>
  34 #include <linux/ip.h>
  35 #include <linux/udp.h>
  36 #include <net/udp.h>
  37 #include "en.h"
  38 #include "en/port.h"
  39 
  40 enum {
  41         MLX5E_ST_LINK_STATE,
  42         MLX5E_ST_LINK_SPEED,
  43         MLX5E_ST_HEALTH_INFO,
  44 #ifdef CONFIG_INET
  45         MLX5E_ST_LOOPBACK,
  46 #endif
  47         MLX5E_ST_NUM,
  48 };
  49 
  50 const char mlx5e_self_tests[MLX5E_ST_NUM][ETH_GSTRING_LEN] = {
  51         "Link Test",
  52         "Speed Test",
  53         "Health Test",
  54 #ifdef CONFIG_INET
  55         "Loopback Test",
  56 #endif
  57 };
  58 
  59 int mlx5e_self_test_num(struct mlx5e_priv *priv)
  60 {
  61         return ARRAY_SIZE(mlx5e_self_tests);
  62 }
  63 
  64 static int mlx5e_test_health_info(struct mlx5e_priv *priv)
  65 {
  66         struct mlx5_core_health *health = &priv->mdev->priv.health;
  67 
  68         return health->fatal_error ? 1 : 0;
  69 }
  70 
  71 static int mlx5e_test_link_state(struct mlx5e_priv *priv)
  72 {
  73         u8 port_state;
  74 
  75         if (!netif_carrier_ok(priv->netdev))
  76                 return 1;
  77 
  78         port_state = mlx5_query_vport_state(priv->mdev, MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT, 0);
  79         return port_state == VPORT_STATE_UP ? 0 : 1;
  80 }
  81 
  82 static int mlx5e_test_link_speed(struct mlx5e_priv *priv)
  83 {
  84         u32 speed;
  85 
  86         if (!netif_carrier_ok(priv->netdev))
  87                 return 1;
  88 
  89         return mlx5e_port_linkspeed(priv->mdev, &speed);
  90 }
  91 
  92 struct mlx5ehdr {
  93         __be32 version;
  94         __be64 magic;
  95 };
  96 
  97 #ifdef CONFIG_INET
  98 /* loopback test */
  99 #define MLX5E_TEST_PKT_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) +\
 100                              sizeof(struct udphdr) + sizeof(struct mlx5ehdr))
 101 #define MLX5E_TEST_MAGIC 0x5AEED15C001ULL
 102 
 103 static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv)
 104 {
 105         struct sk_buff *skb = NULL;
 106         struct mlx5ehdr *mlxh;
 107         struct ethhdr *ethh;
 108         struct udphdr *udph;
 109         struct iphdr *iph;
 110         int    iplen;
 111 
 112         skb = netdev_alloc_skb(priv->netdev, MLX5E_TEST_PKT_SIZE);
 113         if (!skb) {
 114                 netdev_err(priv->netdev, "\tFailed to alloc loopback skb\n");
 115                 return NULL;
 116         }
 117 
 118         prefetchw(skb->data);
 119         skb_reserve(skb, NET_IP_ALIGN);
 120 
 121         /*  Reserve for ethernet and IP header  */
 122         ethh = skb_push(skb, ETH_HLEN);
 123         skb_reset_mac_header(skb);
 124 
 125         skb_set_network_header(skb, skb->len);
 126         iph = skb_put(skb, sizeof(struct iphdr));
 127 
 128         skb_set_transport_header(skb, skb->len);
 129         udph = skb_put(skb, sizeof(struct udphdr));
 130 
 131         /* Fill ETH header */
 132         ether_addr_copy(ethh->h_dest, priv->netdev->dev_addr);
 133         eth_zero_addr(ethh->h_source);
 134         ethh->h_proto = htons(ETH_P_IP);
 135 
 136         /* Fill UDP header */
 137         udph->source = htons(9);
 138         udph->dest = htons(9); /* Discard Protocol */
 139         udph->len = htons(sizeof(struct mlx5ehdr) + sizeof(struct udphdr));
 140         udph->check = 0;
 141 
 142         /* Fill IP header */
 143         iph->ihl = 5;
 144         iph->ttl = 32;
 145         iph->version = 4;
 146         iph->protocol = IPPROTO_UDP;
 147         iplen = sizeof(struct iphdr) + sizeof(struct udphdr) +
 148                 sizeof(struct mlx5ehdr);
 149         iph->tot_len = htons(iplen);
 150         iph->frag_off = 0;
 151         iph->saddr = 0;
 152         iph->daddr = 0;
 153         iph->tos = 0;
 154         iph->id = 0;
 155         ip_send_check(iph);
 156 
 157         /* Fill test header and data */
 158         mlxh = skb_put(skb, sizeof(*mlxh));
 159         mlxh->version = 0;
 160         mlxh->magic = cpu_to_be64(MLX5E_TEST_MAGIC);
 161 
 162         skb->csum = 0;
 163         skb->ip_summed = CHECKSUM_PARTIAL;
 164         udp4_hwcsum(skb, iph->saddr, iph->daddr);
 165 
 166         skb->protocol = htons(ETH_P_IP);
 167         skb->pkt_type = PACKET_HOST;
 168         skb->dev = priv->netdev;
 169 
 170         return skb;
 171 }
 172 
 173 struct mlx5e_lbt_priv {
 174         struct packet_type pt;
 175         struct completion comp;
 176         bool loopback_ok;
 177         bool local_lb;
 178 };
 179 
 180 static int
 181 mlx5e_test_loopback_validate(struct sk_buff *skb,
 182                              struct net_device *ndev,
 183                              struct packet_type *pt,
 184                              struct net_device *orig_ndev)
 185 {
 186         struct mlx5e_lbt_priv *lbtp = pt->af_packet_priv;
 187         struct mlx5ehdr *mlxh;
 188         struct ethhdr *ethh;
 189         struct udphdr *udph;
 190         struct iphdr *iph;
 191 
 192         /* We are only going to peek, no need to clone the SKB */
 193         if (MLX5E_TEST_PKT_SIZE - ETH_HLEN > skb_headlen(skb))
 194                 goto out;
 195 
 196         ethh = (struct ethhdr *)skb_mac_header(skb);
 197         if (!ether_addr_equal(ethh->h_dest, orig_ndev->dev_addr))
 198                 goto out;
 199 
 200         iph = ip_hdr(skb);
 201         if (iph->protocol != IPPROTO_UDP)
 202                 goto out;
 203 
 204         /* Don't assume skb_transport_header() was set */
 205         udph = (struct udphdr *)((u8 *)iph + 4 * iph->ihl);
 206         if (udph->dest != htons(9))
 207                 goto out;
 208 
 209         mlxh = (struct mlx5ehdr *)((char *)udph + sizeof(*udph));
 210         if (mlxh->magic != cpu_to_be64(MLX5E_TEST_MAGIC))
 211                 goto out; /* so close ! */
 212 
 213         /* bingo */
 214         lbtp->loopback_ok = true;
 215         complete(&lbtp->comp);
 216 out:
 217         kfree_skb(skb);
 218         return 0;
 219 }
 220 
 221 static int mlx5e_test_loopback_setup(struct mlx5e_priv *priv,
 222                                      struct mlx5e_lbt_priv *lbtp)
 223 {
 224         int err = 0;
 225 
 226         /* Temporarily enable local_lb */
 227         err = mlx5_nic_vport_query_local_lb(priv->mdev, &lbtp->local_lb);
 228         if (err)
 229                 return err;
 230 
 231         if (!lbtp->local_lb) {
 232                 err = mlx5_nic_vport_update_local_lb(priv->mdev, true);
 233                 if (err)
 234                         return err;
 235         }
 236 
 237         err = mlx5e_refresh_tirs(priv, true);
 238         if (err)
 239                 goto out;
 240 
 241         lbtp->loopback_ok = false;
 242         init_completion(&lbtp->comp);
 243 
 244         lbtp->pt.type = htons(ETH_P_IP);
 245         lbtp->pt.func = mlx5e_test_loopback_validate;
 246         lbtp->pt.dev = priv->netdev;
 247         lbtp->pt.af_packet_priv = lbtp;
 248         dev_add_pack(&lbtp->pt);
 249 
 250         return 0;
 251 
 252 out:
 253         if (!lbtp->local_lb)
 254                 mlx5_nic_vport_update_local_lb(priv->mdev, false);
 255 
 256         return err;
 257 }
 258 
 259 static void mlx5e_test_loopback_cleanup(struct mlx5e_priv *priv,
 260                                         struct mlx5e_lbt_priv *lbtp)
 261 {
 262         if (!lbtp->local_lb)
 263                 mlx5_nic_vport_update_local_lb(priv->mdev, false);
 264 
 265         dev_remove_pack(&lbtp->pt);
 266         mlx5e_refresh_tirs(priv, false);
 267 }
 268 
 269 #define MLX5E_LB_VERIFY_TIMEOUT (msecs_to_jiffies(200))
 270 static int mlx5e_test_loopback(struct mlx5e_priv *priv)
 271 {
 272         struct mlx5e_lbt_priv *lbtp;
 273         struct sk_buff *skb = NULL;
 274         int err;
 275 
 276         if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
 277                 netdev_err(priv->netdev,
 278                            "\tCan't perform loopback test while device is down\n");
 279                 return -ENODEV;
 280         }
 281 
 282         lbtp = kzalloc(sizeof(*lbtp), GFP_KERNEL);
 283         if (!lbtp)
 284                 return -ENOMEM;
 285         lbtp->loopback_ok = false;
 286 
 287         err = mlx5e_test_loopback_setup(priv, lbtp);
 288         if (err)
 289                 goto out;
 290 
 291         skb = mlx5e_test_get_udp_skb(priv);
 292         if (!skb) {
 293                 err = -ENOMEM;
 294                 goto cleanup;
 295         }
 296 
 297         skb_set_queue_mapping(skb, 0);
 298         err = dev_queue_xmit(skb);
 299         if (err) {
 300                 netdev_err(priv->netdev,
 301                            "\tFailed to xmit loopback packet err(%d)\n",
 302                            err);
 303                 goto cleanup;
 304         }
 305 
 306         wait_for_completion_timeout(&lbtp->comp, MLX5E_LB_VERIFY_TIMEOUT);
 307         err = !lbtp->loopback_ok;
 308 
 309 cleanup:
 310         mlx5e_test_loopback_cleanup(priv, lbtp);
 311 out:
 312         kfree(lbtp);
 313         return err;
 314 }
 315 #endif
 316 
 317 static int (*mlx5e_st_func[MLX5E_ST_NUM])(struct mlx5e_priv *) = {
 318         mlx5e_test_link_state,
 319         mlx5e_test_link_speed,
 320         mlx5e_test_health_info,
 321 #ifdef CONFIG_INET
 322         mlx5e_test_loopback,
 323 #endif
 324 };
 325 
 326 void mlx5e_self_test(struct net_device *ndev, struct ethtool_test *etest,
 327                      u64 *buf)
 328 {
 329         struct mlx5e_priv *priv = netdev_priv(ndev);
 330         int i;
 331 
 332         memset(buf, 0, sizeof(u64) * MLX5E_ST_NUM);
 333 
 334         mutex_lock(&priv->state_lock);
 335         netdev_info(ndev, "Self test begin..\n");
 336 
 337         for (i = 0; i < MLX5E_ST_NUM; i++) {
 338                 netdev_info(ndev, "\t[%d] %s start..\n",
 339                             i, mlx5e_self_tests[i]);
 340                 buf[i] = mlx5e_st_func[i](priv);
 341                 netdev_info(ndev, "\t[%d] %s end: result(%lld)\n",
 342                             i, mlx5e_self_tests[i], buf[i]);
 343         }
 344 
 345         mutex_unlock(&priv->state_lock);
 346 
 347         for (i = 0; i < MLX5E_ST_NUM; i++) {
 348                 if (buf[i]) {
 349                         etest->flags |= ETH_TEST_FL_FAILED;
 350                         break;
 351                 }
 352         }
 353         netdev_info(ndev, "Self test out: status flags(0x%x)\n",
 354                     etest->flags);
 355 }

/* [<][>][^][v][top][bottom][index][help] */