cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

en_selftest.c (9026B)


      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/ip.h>
     34#include <linux/udp.h>
     35#include <net/udp.h>
     36#include "en.h"
     37#include "en/port.h"
     38#include "eswitch.h"
     39
     40static int mlx5e_test_health_info(struct mlx5e_priv *priv)
     41{
     42	struct mlx5_core_health *health = &priv->mdev->priv.health;
     43
     44	return health->fatal_error ? 1 : 0;
     45}
     46
     47static int mlx5e_test_link_state(struct mlx5e_priv *priv)
     48{
     49	u8 port_state;
     50
     51	if (!netif_carrier_ok(priv->netdev))
     52		return 1;
     53
     54	port_state = mlx5_query_vport_state(priv->mdev, MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT, 0);
     55	return port_state == VPORT_STATE_UP ? 0 : 1;
     56}
     57
     58static int mlx5e_test_link_speed(struct mlx5e_priv *priv)
     59{
     60	u32 speed;
     61
     62	if (!netif_carrier_ok(priv->netdev))
     63		return 1;
     64
     65	return mlx5e_port_linkspeed(priv->mdev, &speed);
     66}
     67
     68struct mlx5ehdr {
     69	__be32 version;
     70	__be64 magic;
     71};
     72
     73#ifdef CONFIG_INET
     74/* loopback test */
     75#define MLX5E_TEST_PKT_SIZE (sizeof(struct ethhdr) + sizeof(struct iphdr) +\
     76			     sizeof(struct udphdr) + sizeof(struct mlx5ehdr))
     77#define MLX5E_TEST_MAGIC 0x5AEED15C001ULL
     78
     79static struct sk_buff *mlx5e_test_get_udp_skb(struct mlx5e_priv *priv)
     80{
     81	struct sk_buff *skb = NULL;
     82	struct mlx5ehdr *mlxh;
     83	struct ethhdr *ethh;
     84	struct udphdr *udph;
     85	struct iphdr *iph;
     86	int    iplen;
     87
     88	skb = netdev_alloc_skb(priv->netdev, MLX5E_TEST_PKT_SIZE);
     89	if (!skb) {
     90		netdev_err(priv->netdev, "\tFailed to alloc loopback skb\n");
     91		return NULL;
     92	}
     93
     94	net_prefetchw(skb->data);
     95	skb_reserve(skb, NET_IP_ALIGN);
     96
     97	/*  Reserve for ethernet and IP header  */
     98	ethh = skb_push(skb, ETH_HLEN);
     99	skb_reset_mac_header(skb);
    100
    101	skb_set_network_header(skb, skb->len);
    102	iph = skb_put(skb, sizeof(struct iphdr));
    103
    104	skb_set_transport_header(skb, skb->len);
    105	udph = skb_put(skb, sizeof(struct udphdr));
    106
    107	/* Fill ETH header */
    108	ether_addr_copy(ethh->h_dest, priv->netdev->dev_addr);
    109	eth_zero_addr(ethh->h_source);
    110	ethh->h_proto = htons(ETH_P_IP);
    111
    112	/* Fill UDP header */
    113	udph->source = htons(9);
    114	udph->dest = htons(9); /* Discard Protocol */
    115	udph->len = htons(sizeof(struct mlx5ehdr) + sizeof(struct udphdr));
    116	udph->check = 0;
    117
    118	/* Fill IP header */
    119	iph->ihl = 5;
    120	iph->ttl = 32;
    121	iph->version = 4;
    122	iph->protocol = IPPROTO_UDP;
    123	iplen = sizeof(struct iphdr) + sizeof(struct udphdr) +
    124		sizeof(struct mlx5ehdr);
    125	iph->tot_len = htons(iplen);
    126	iph->frag_off = 0;
    127	iph->saddr = 0;
    128	iph->daddr = 0;
    129	iph->tos = 0;
    130	iph->id = 0;
    131	ip_send_check(iph);
    132
    133	/* Fill test header and data */
    134	mlxh = skb_put(skb, sizeof(*mlxh));
    135	mlxh->version = 0;
    136	mlxh->magic = cpu_to_be64(MLX5E_TEST_MAGIC);
    137
    138	skb->csum = 0;
    139	skb->ip_summed = CHECKSUM_PARTIAL;
    140	udp4_hwcsum(skb, iph->saddr, iph->daddr);
    141
    142	skb->protocol = htons(ETH_P_IP);
    143	skb->pkt_type = PACKET_HOST;
    144	skb->dev = priv->netdev;
    145
    146	return skb;
    147}
    148
    149struct mlx5e_lbt_priv {
    150	struct packet_type pt;
    151	struct completion comp;
    152	bool loopback_ok;
    153	bool local_lb;
    154};
    155
    156static int
    157mlx5e_test_loopback_validate(struct sk_buff *skb,
    158			     struct net_device *ndev,
    159			     struct packet_type *pt,
    160			     struct net_device *orig_ndev)
    161{
    162	struct mlx5e_lbt_priv *lbtp = pt->af_packet_priv;
    163	struct mlx5ehdr *mlxh;
    164	struct ethhdr *ethh;
    165	struct udphdr *udph;
    166	struct iphdr *iph;
    167
    168	/* We are only going to peek, no need to clone the SKB */
    169	if (MLX5E_TEST_PKT_SIZE - ETH_HLEN > skb_headlen(skb))
    170		goto out;
    171
    172	ethh = (struct ethhdr *)skb_mac_header(skb);
    173	if (!ether_addr_equal(ethh->h_dest, orig_ndev->dev_addr))
    174		goto out;
    175
    176	iph = ip_hdr(skb);
    177	if (iph->protocol != IPPROTO_UDP)
    178		goto out;
    179
    180	/* Don't assume skb_transport_header() was set */
    181	udph = (struct udphdr *)((u8 *)iph + 4 * iph->ihl);
    182	if (udph->dest != htons(9))
    183		goto out;
    184
    185	mlxh = (struct mlx5ehdr *)((char *)udph + sizeof(*udph));
    186	if (mlxh->magic != cpu_to_be64(MLX5E_TEST_MAGIC))
    187		goto out; /* so close ! */
    188
    189	/* bingo */
    190	lbtp->loopback_ok = true;
    191	complete(&lbtp->comp);
    192out:
    193	kfree_skb(skb);
    194	return 0;
    195}
    196
    197static int mlx5e_test_loopback_setup(struct mlx5e_priv *priv,
    198				     struct mlx5e_lbt_priv *lbtp)
    199{
    200	int err = 0;
    201
    202	/* Temporarily enable local_lb */
    203	err = mlx5_nic_vport_query_local_lb(priv->mdev, &lbtp->local_lb);
    204	if (err)
    205		return err;
    206
    207	if (!lbtp->local_lb) {
    208		err = mlx5_nic_vport_update_local_lb(priv->mdev, true);
    209		if (err)
    210			return err;
    211	}
    212
    213	err = mlx5e_refresh_tirs(priv, true, false);
    214	if (err)
    215		goto out;
    216
    217	lbtp->loopback_ok = false;
    218	init_completion(&lbtp->comp);
    219
    220	lbtp->pt.type = htons(ETH_P_IP);
    221	lbtp->pt.func = mlx5e_test_loopback_validate;
    222	lbtp->pt.dev = priv->netdev;
    223	lbtp->pt.af_packet_priv = lbtp;
    224	dev_add_pack(&lbtp->pt);
    225
    226	return 0;
    227
    228out:
    229	if (!lbtp->local_lb)
    230		mlx5_nic_vport_update_local_lb(priv->mdev, false);
    231
    232	return err;
    233}
    234
    235static void mlx5e_test_loopback_cleanup(struct mlx5e_priv *priv,
    236					struct mlx5e_lbt_priv *lbtp)
    237{
    238	if (!lbtp->local_lb)
    239		mlx5_nic_vport_update_local_lb(priv->mdev, false);
    240
    241	dev_remove_pack(&lbtp->pt);
    242	mlx5e_refresh_tirs(priv, false, false);
    243}
    244
    245static int mlx5e_cond_loopback(struct mlx5e_priv *priv)
    246{
    247	if (is_mdev_switchdev_mode(priv->mdev))
    248		return -EOPNOTSUPP;
    249
    250	return 0;
    251}
    252
    253#define MLX5E_LB_VERIFY_TIMEOUT (msecs_to_jiffies(200))
    254static int mlx5e_test_loopback(struct mlx5e_priv *priv)
    255{
    256	struct mlx5e_lbt_priv *lbtp;
    257	struct sk_buff *skb = NULL;
    258	int err;
    259
    260	if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
    261		netdev_err(priv->netdev,
    262			   "\tCan't perform loopback test while device is down\n");
    263		return -ENODEV;
    264	}
    265
    266	lbtp = kzalloc(sizeof(*lbtp), GFP_KERNEL);
    267	if (!lbtp)
    268		return -ENOMEM;
    269	lbtp->loopback_ok = false;
    270
    271	err = mlx5e_test_loopback_setup(priv, lbtp);
    272	if (err)
    273		goto out;
    274
    275	skb = mlx5e_test_get_udp_skb(priv);
    276	if (!skb) {
    277		err = -ENOMEM;
    278		goto cleanup;
    279	}
    280
    281	skb_set_queue_mapping(skb, 0);
    282	err = dev_queue_xmit(skb);
    283	if (err) {
    284		netdev_err(priv->netdev,
    285			   "\tFailed to xmit loopback packet err(%d)\n",
    286			   err);
    287		goto cleanup;
    288	}
    289
    290	wait_for_completion_timeout(&lbtp->comp, MLX5E_LB_VERIFY_TIMEOUT);
    291	err = !lbtp->loopback_ok;
    292
    293cleanup:
    294	mlx5e_test_loopback_cleanup(priv, lbtp);
    295out:
    296	kfree(lbtp);
    297	return err;
    298}
    299#endif
    300
    301typedef int (*mlx5e_st_func)(struct mlx5e_priv *);
    302
    303struct mlx5e_st {
    304	char name[ETH_GSTRING_LEN];
    305	mlx5e_st_func st_func;
    306	mlx5e_st_func cond_func;
    307};
    308
    309static struct mlx5e_st mlx5e_sts[] = {
    310	{ "Link Test", mlx5e_test_link_state },
    311	{ "Speed Test", mlx5e_test_link_speed },
    312	{ "Health Test", mlx5e_test_health_info },
    313#ifdef CONFIG_INET
    314	{ "Loopback Test", mlx5e_test_loopback, mlx5e_cond_loopback },
    315#endif
    316};
    317
    318#define MLX5E_ST_NUM ARRAY_SIZE(mlx5e_sts)
    319
    320void mlx5e_self_test(struct net_device *ndev, struct ethtool_test *etest,
    321		     u64 *buf)
    322{
    323	struct mlx5e_priv *priv = netdev_priv(ndev);
    324	int i, count = 0;
    325
    326	mutex_lock(&priv->state_lock);
    327	netdev_info(ndev, "Self test begin..\n");
    328
    329	for (i = 0; i < MLX5E_ST_NUM; i++) {
    330		struct mlx5e_st st = mlx5e_sts[i];
    331
    332		if (st.cond_func && st.cond_func(priv))
    333			continue;
    334		netdev_info(ndev, "\t[%d] %s start..\n", i, st.name);
    335		buf[count] = st.st_func(priv);
    336		netdev_info(ndev, "\t[%d] %s end: result(%lld)\n", i, st.name, buf[count]);
    337		count++;
    338	}
    339
    340	mutex_unlock(&priv->state_lock);
    341
    342	for (i = 0; i < count; i++) {
    343		if (buf[i]) {
    344			etest->flags |= ETH_TEST_FL_FAILED;
    345			break;
    346		}
    347	}
    348	netdev_info(ndev, "Self test out: status flags(0x%x)\n",
    349		    etest->flags);
    350}
    351
    352int mlx5e_self_test_fill_strings(struct mlx5e_priv *priv, u8 *data)
    353{
    354	int i, count = 0;
    355
    356	for (i = 0; i < MLX5E_ST_NUM; i++) {
    357		struct mlx5e_st st = mlx5e_sts[i];
    358
    359		if (st.cond_func && st.cond_func(priv))
    360			continue;
    361		if (data)
    362			strcpy(data + count * ETH_GSTRING_LEN, st.name);
    363		count++;
    364	}
    365	return count;
    366}
    367
    368int mlx5e_self_test_num(struct mlx5e_priv *priv)
    369{
    370	return mlx5e_self_test_fill_strings(priv, NULL);
    371}