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