aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYevgeny Petrilin <yevgenyp@mellanox.co.il>2010-08-23 23:46:18 -0400
committerDavid S. Miller <davem@davemloft.net>2010-08-24 17:54:51 -0400
commite7c1c2c46201e46f8ce817196507d2ffd3dafd8e (patch)
tree33579da64d2c5dc4502518496097dcf9737e9eb4
parent3005ad40b95168aad530f1179cff47411b3ea8da (diff)
mlx4_en: Added self diagnostics test implementation
The selftest includes 5 features: 1. Interrupt test: Executing commands and receiving command completion on all our interrupt vectors. 2. Link test: Verifying we are connected to valid link partner. 3. Speed test: Check that we negotiated link speed correctly. 4. Registers test: Activate HW health check command. 5. Loopback test: Send a packet on loopback interface and catch it on RX side. Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/mlx4/Makefile2
-rw-r--r--drivers/net/mlx4/en_ethtool.c79
-rw-r--r--drivers/net/mlx4/en_netdev.c2
-rw-r--r--drivers/net/mlx4/en_port.c32
-rw-r--r--drivers/net/mlx4/en_port.h14
-rw-r--r--drivers/net/mlx4/en_rx.c20
-rw-r--r--drivers/net/mlx4/en_selftest.c179
-rw-r--r--drivers/net/mlx4/en_tx.c16
-rw-r--r--drivers/net/mlx4/eq.c44
-rw-r--r--drivers/net/mlx4/fw.c3
-rw-r--r--drivers/net/mlx4/fw.h1
-rw-r--r--drivers/net/mlx4/main.c1
-rw-r--r--drivers/net/mlx4/mlx4_en.h19
-rw-r--r--include/linux/mlx4/cmd.h1
-rw-r--r--include/linux/mlx4/device.h2
15 files changed, 388 insertions, 27 deletions
diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile
index 1fd068e1d930..d1aa45a15854 100644
--- a/drivers/net/mlx4/Makefile
+++ b/drivers/net/mlx4/Makefile
@@ -6,4 +6,4 @@ mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \
6obj-$(CONFIG_MLX4_EN) += mlx4_en.o 6obj-$(CONFIG_MLX4_EN) += mlx4_en.o
7 7
8mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \ 8mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \
9 en_resources.o en_netdev.o 9 en_resources.o en_netdev.o en_selftest.o
diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c
index 398d54136967..f7d72d7a8704 100644
--- a/drivers/net/mlx4/en_ethtool.c
+++ b/drivers/net/mlx4/en_ethtool.c
@@ -125,6 +125,14 @@ static const char main_strings[][ETH_GSTRING_LEN] = {
125#define NUM_MAIN_STATS 21 125#define NUM_MAIN_STATS 21
126#define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS) 126#define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS)
127 127
128static const char mlx4_en_test_names[][ETH_GSTRING_LEN]= {
129 "Interupt Test",
130 "Link Test",
131 "Speed Test",
132 "Register Test",
133 "Loopback Test",
134};
135
128static u32 mlx4_en_get_msglevel(struct net_device *dev) 136static u32 mlx4_en_get_msglevel(struct net_device *dev)
129{ 137{
130 return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable; 138 return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable;
@@ -146,10 +154,15 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
146{ 154{
147 struct mlx4_en_priv *priv = netdev_priv(dev); 155 struct mlx4_en_priv *priv = netdev_priv(dev);
148 156
149 if (sset != ETH_SS_STATS) 157 switch (sset) {
158 case ETH_SS_STATS:
159 return NUM_ALL_STATS +
160 (priv->tx_ring_num + priv->rx_ring_num) * 2;
161 case ETH_SS_TEST:
162 return MLX4_EN_NUM_SELF_TEST - !(priv->mdev->dev->caps.loopback_support) * 2;
163 default:
150 return -EOPNOTSUPP; 164 return -EOPNOTSUPP;
151 165 }
152 return NUM_ALL_STATS + (priv->tx_ring_num + priv->rx_ring_num) * 2;
153} 166}
154 167
155static void mlx4_en_get_ethtool_stats(struct net_device *dev, 168static void mlx4_en_get_ethtool_stats(struct net_device *dev,
@@ -181,6 +194,12 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
181 194
182} 195}
183 196
197static void mlx4_en_self_test(struct net_device *dev,
198 struct ethtool_test *etest, u64 *buf)
199{
200 mlx4_en_ex_selftest(dev, &etest->flags, buf);
201}
202
184static void mlx4_en_get_strings(struct net_device *dev, 203static void mlx4_en_get_strings(struct net_device *dev,
185 uint32_t stringset, uint8_t *data) 204 uint32_t stringset, uint8_t *data)
186{ 205{
@@ -188,30 +207,39 @@ static void mlx4_en_get_strings(struct net_device *dev,
188 int index = 0; 207 int index = 0;
189 int i; 208 int i;
190 209
191 if (stringset != ETH_SS_STATS) 210 switch (stringset) {
192 return; 211 case ETH_SS_TEST:
193 212 for (i = 0; i < MLX4_EN_NUM_SELF_TEST - 2; i++)
194 /* Add main counters */ 213 strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]);
195 for (i = 0; i < NUM_MAIN_STATS; i++) 214 if (priv->mdev->dev->caps.loopback_support)
196 strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]); 215 for (; i < MLX4_EN_NUM_SELF_TEST; i++)
197 for (i = 0; i < NUM_PORT_STATS; i++) 216 strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]);
198 strcpy(data + (index++) * ETH_GSTRING_LEN, 217 break;
218
219 case ETH_SS_STATS:
220 /* Add main counters */
221 for (i = 0; i < NUM_MAIN_STATS; i++)
222 strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]);
223 for (i = 0; i< NUM_PORT_STATS; i++)
224 strcpy(data + (index++) * ETH_GSTRING_LEN,
199 main_strings[i + NUM_MAIN_STATS]); 225 main_strings[i + NUM_MAIN_STATS]);
200 for (i = 0; i < priv->tx_ring_num; i++) { 226 for (i = 0; i < priv->tx_ring_num; i++) {
201 sprintf(data + (index++) * ETH_GSTRING_LEN, 227 sprintf(data + (index++) * ETH_GSTRING_LEN,
202 "tx%d_packets", i); 228 "tx%d_packets", i);
203 sprintf(data + (index++) * ETH_GSTRING_LEN, 229 sprintf(data + (index++) * ETH_GSTRING_LEN,
204 "tx%d_bytes", i); 230 "tx%d_bytes", i);
205 } 231 }
206 for (i = 0; i < priv->rx_ring_num; i++) { 232 for (i = 0; i < priv->rx_ring_num; i++) {
207 sprintf(data + (index++) * ETH_GSTRING_LEN, 233 sprintf(data + (index++) * ETH_GSTRING_LEN,
208 "rx%d_packets", i); 234 "rx%d_packets", i);
209 sprintf(data + (index++) * ETH_GSTRING_LEN, 235 sprintf(data + (index++) * ETH_GSTRING_LEN,
210 "rx%d_bytes", i); 236 "rx%d_bytes", i);
211 } 237 }
212 for (i = 0; i < NUM_PKT_STATS; i++) 238 for (i = 0; i< NUM_PKT_STATS; i++)
213 strcpy(data + (index++) * ETH_GSTRING_LEN, 239 strcpy(data + (index++) * ETH_GSTRING_LEN,
214 main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]); 240 main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]);
241 break;
242 }
215} 243}
216 244
217static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 245static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -439,6 +467,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
439 .get_strings = mlx4_en_get_strings, 467 .get_strings = mlx4_en_get_strings,
440 .get_sset_count = mlx4_en_get_sset_count, 468 .get_sset_count = mlx4_en_get_sset_count,
441 .get_ethtool_stats = mlx4_en_get_ethtool_stats, 469 .get_ethtool_stats = mlx4_en_get_ethtool_stats,
470 .self_test = mlx4_en_self_test,
442 .get_wol = mlx4_en_get_wol, 471 .get_wol = mlx4_en_get_wol,
443 .get_msglevel = mlx4_en_get_msglevel, 472 .get_msglevel = mlx4_en_get_msglevel,
444 .set_msglevel = mlx4_en_set_msglevel, 473 .set_msglevel = mlx4_en_set_msglevel,
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 34cfa3cfbdae..968e75b7acf4 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -109,7 +109,7 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
109 mutex_unlock(&mdev->state_lock); 109 mutex_unlock(&mdev->state_lock);
110} 110}
111 111
112static u64 mlx4_en_mac_to_u64(u8 *addr) 112u64 mlx4_en_mac_to_u64(u8 *addr)
113{ 113{
114 u64 mac = 0; 114 u64 mac = 0;
115 int i; 115 int i;
diff --git a/drivers/net/mlx4/en_port.c b/drivers/net/mlx4/en_port.c
index a29abe845d2e..aa3ef2aee5bf 100644
--- a/drivers/net/mlx4/en_port.c
+++ b/drivers/net/mlx4/en_port.c
@@ -142,6 +142,38 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
142 return err; 142 return err;
143} 143}
144 144
145int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port)
146{
147 struct mlx4_en_query_port_context *qport_context;
148 struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]);
149 struct mlx4_en_port_state *state = &priv->port_state;
150 struct mlx4_cmd_mailbox *mailbox;
151 int err;
152
153 mailbox = mlx4_alloc_cmd_mailbox(mdev->dev);
154 if (IS_ERR(mailbox))
155 return PTR_ERR(mailbox);
156 memset(mailbox->buf, 0, sizeof(*qport_context));
157 err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, port, 0,
158 MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B);
159 if (err)
160 goto out;
161 qport_context = mailbox->buf;
162
163 /* This command is always accessed from Ethtool context
164 * already synchronized, no need in locking */
165 state->link_state = !!(qport_context->link_up & MLX4_EN_LINK_UP_MASK);
166 if ((qport_context->link_speed & MLX4_EN_SPEED_MASK) ==
167 MLX4_EN_1G_SPEED)
168 state->link_speed = 1000;
169 else
170 state->link_speed = 10000;
171 state->transciver = qport_context->transceiver;
172
173out:
174 mlx4_free_cmd_mailbox(mdev->dev, mailbox);
175 return err;
176}
145 177
146int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) 178int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
147{ 179{
diff --git a/drivers/net/mlx4/en_port.h b/drivers/net/mlx4/en_port.h
index e6477f12beb5..f6511aa2b7df 100644
--- a/drivers/net/mlx4/en_port.h
+++ b/drivers/net/mlx4/en_port.h
@@ -84,6 +84,20 @@ enum {
84 MLX4_MCAST_ENABLE = 2, 84 MLX4_MCAST_ENABLE = 2,
85}; 85};
86 86
87struct mlx4_en_query_port_context {
88 u8 link_up;
89#define MLX4_EN_LINK_UP_MASK 0x80
90 u8 reserved;
91 __be16 mtu;
92 u8 reserved2;
93 u8 link_speed;
94#define MLX4_EN_SPEED_MASK 0x3
95#define MLX4_EN_1G_SPEED 0x2
96 u16 reserved3[5];
97 __be64 mac;
98 u8 transceiver;
99};
100
87 101
88struct mlx4_en_stat_out_mbox { 102struct mlx4_en_stat_out_mbox {
89 /* Received frames with a length of 64 octets */ 103 /* Received frames with a length of 64 octets */
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c
index 7a5123c4a366..f421a3d42723 100644
--- a/drivers/net/mlx4/en_rx.c
+++ b/drivers/net/mlx4/en_rx.c
@@ -541,6 +541,21 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
541 return skb; 541 return skb;
542} 542}
543 543
544static void validate_loopback(struct mlx4_en_priv *priv, struct sk_buff *skb)
545{
546 int i;
547 int offset = ETH_HLEN;
548
549 for (i = 0; i < MLX4_LOOPBACK_TEST_PAYLOAD; i++, offset++) {
550 if (*(skb->data + offset) != (unsigned char) (i & 0xff))
551 goto out_loopback;
552 }
553 /* Loopback found */
554 priv->loopback_ok = 1;
555
556out_loopback:
557 dev_kfree_skb_any(skb);
558}
544 559
545int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) 560int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget)
546{ 561{
@@ -655,6 +670,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
655 goto next; 670 goto next;
656 } 671 }
657 672
673 if (unlikely(priv->validate_loopback)) {
674 validate_loopback(priv, skb);
675 goto next;
676 }
677
658 skb->ip_summed = ip_summed; 678 skb->ip_summed = ip_summed;
659 skb->protocol = eth_type_trans(skb, dev); 679 skb->protocol = eth_type_trans(skb, dev);
660 skb_record_rx_queue(skb, cq->ring); 680 skb_record_rx_queue(skb, cq->ring);
diff --git a/drivers/net/mlx4/en_selftest.c b/drivers/net/mlx4/en_selftest.c
new file mode 100644
index 000000000000..43357d35616a
--- /dev/null
+++ b/drivers/net/mlx4/en_selftest.c
@@ -0,0 +1,179 @@
1/*
2 * Copyright (c) 2007 Mellanox Technologies. 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
34#include <linux/kernel.h>
35#include <linux/ethtool.h>
36#include <linux/netdevice.h>
37#include <linux/delay.h>
38#include <linux/mlx4/driver.h>
39
40#include "mlx4_en.h"
41
42
43static int mlx4_en_test_registers(struct mlx4_en_priv *priv)
44{
45 return mlx4_cmd(priv->mdev->dev, 0, 0, 0, MLX4_CMD_HW_HEALTH_CHECK,
46 MLX4_CMD_TIME_CLASS_A);
47}
48
49static int mlx4_en_test_loopback_xmit(struct mlx4_en_priv *priv)
50{
51 struct sk_buff *skb;
52 struct ethhdr *ethh;
53 unsigned char *packet;
54 unsigned int packet_size = MLX4_LOOPBACK_TEST_PAYLOAD;
55 unsigned int i;
56 int err;
57
58
59 /* build the pkt before xmit */
60 skb = netdev_alloc_skb(priv->dev, MLX4_LOOPBACK_TEST_PAYLOAD + ETH_HLEN + NET_IP_ALIGN);
61 if (!skb) {
62 en_err(priv, "-LOOPBACK_TEST_XMIT- failed to create skb for xmit\n");
63 return -ENOMEM;
64 }
65 skb_reserve(skb, NET_IP_ALIGN);
66
67 ethh = (struct ethhdr *)skb_put(skb, sizeof(struct ethhdr));
68 packet = (unsigned char *)skb_put(skb, packet_size);
69 memcpy(ethh->h_dest, priv->dev->dev_addr, ETH_ALEN);
70 memset(ethh->h_source, 0, ETH_ALEN);
71 ethh->h_proto = htons(ETH_P_ARP);
72 skb_set_mac_header(skb, 0);
73 for (i = 0; i < packet_size; ++i) /* fill our packet */
74 packet[i] = (unsigned char)(i & 0xff);
75
76 /* xmit the pkt */
77 err = mlx4_en_xmit(skb, priv->dev);
78 return err;
79}
80
81static int mlx4_en_test_loopback(struct mlx4_en_priv *priv)
82{
83 u32 loopback_ok = 0;
84 int i;
85
86
87 priv->loopback_ok = 0;
88 priv->validate_loopback = 1;
89
90 /* xmit */
91 if (mlx4_en_test_loopback_xmit(priv)) {
92 en_err(priv, "Transmitting loopback packet failed\n");
93 goto mlx4_en_test_loopback_exit;
94 }
95
96 /* polling for result */
97 for (i = 0; i < MLX4_EN_LOOPBACK_RETRIES; ++i) {
98 msleep(MLX4_EN_LOOPBACK_TIMEOUT);
99 if (priv->loopback_ok) {
100 loopback_ok = 1;
101 break;
102 }
103 }
104 if (!loopback_ok)
105 en_err(priv, "Loopback packet didn't arrive\n");
106
107mlx4_en_test_loopback_exit:
108
109 priv->validate_loopback = 0;
110 return (!loopback_ok);
111}
112
113
114static int mlx4_en_test_link(struct mlx4_en_priv *priv)
115{
116 if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
117 return -ENOMEM;
118 if (priv->port_state.link_state == 1)
119 return 0;
120 else
121 return 1;
122}
123
124static int mlx4_en_test_speed(struct mlx4_en_priv *priv)
125{
126
127 if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
128 return -ENOMEM;
129
130 /* The device currently only supports 10G speed */
131 if (priv->port_state.link_speed != SPEED_10000)
132 return priv->port_state.link_speed;
133 return 0;
134}
135
136
137void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf)
138{
139 struct mlx4_en_priv *priv = netdev_priv(dev);
140 struct mlx4_en_dev *mdev = priv->mdev;
141 struct mlx4_en_tx_ring *tx_ring;
142 int i, carrier_ok;
143
144 memset(buf, 0, sizeof(u64) * MLX4_EN_NUM_SELF_TEST);
145
146 if (*flags & ETH_TEST_FL_OFFLINE) {
147 /* disable the interface */
148 carrier_ok = netif_carrier_ok(dev);
149
150 netif_carrier_off(dev);
151retry_tx:
152 /* Wait untill all tx queues are empty.
153 * there should not be any additional incoming traffic
154 * since we turned the carrier off */
155 msleep(200);
156 for (i = 0; i < priv->tx_ring_num && carrier_ok; i++) {
157 tx_ring = &priv->tx_ring[i];
158 if (tx_ring->prod != (tx_ring->cons + tx_ring->last_nr_txbb))
159 goto retry_tx;
160 }
161
162 if (priv->mdev->dev->caps.loopback_support){
163 buf[3] = mlx4_en_test_registers(priv);
164 buf[4] = mlx4_en_test_loopback(priv);
165 }
166
167 if (carrier_ok)
168 netif_carrier_on(dev);
169
170 }
171 buf[0] = mlx4_test_interrupts(mdev->dev);
172 buf[1] = mlx4_en_test_link(priv);
173 buf[2] = mlx4_en_test_speed(priv);
174
175 for (i = 0; i < MLX4_EN_NUM_SELF_TEST; i++) {
176 if (buf[i])
177 *flags |= ETH_TEST_FL_FAILED;
178 }
179}
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c
index 3deabd1d0357..b875f9c38848 100644
--- a/drivers/net/mlx4/en_tx.c
+++ b/drivers/net/mlx4/en_tx.c
@@ -600,6 +600,9 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
600 struct mlx4_wqe_data_seg *data; 600 struct mlx4_wqe_data_seg *data;
601 struct skb_frag_struct *frag; 601 struct skb_frag_struct *frag;
602 struct mlx4_en_tx_info *tx_info; 602 struct mlx4_en_tx_info *tx_info;
603 struct ethhdr *ethh;
604 u64 mac;
605 u32 mac_l, mac_h;
603 int tx_ind = 0; 606 int tx_ind = 0;
604 int nr_txbb; 607 int nr_txbb;
605 int desc_size; 608 int desc_size;
@@ -679,6 +682,19 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
679 priv->port_stats.tx_chksum_offload++; 682 priv->port_stats.tx_chksum_offload++;
680 } 683 }
681 684
685 if (unlikely(priv->validate_loopback)) {
686 /* Copy dst mac address to wqe */
687 skb_reset_mac_header(skb);
688 ethh = eth_hdr(skb);
689 if (ethh && ethh->h_dest) {
690 mac = mlx4_en_mac_to_u64(ethh->h_dest);
691 mac_h = (u32) ((mac & 0xffff00000000ULL) >> 16);
692 mac_l = (u32) (mac & 0xffffffff);
693 tx_desc->ctrl.srcrb_flags |= cpu_to_be32(mac_h);
694 tx_desc->ctrl.imm = cpu_to_be32(mac_l);
695 }
696 }
697
682 /* Handle LSO (TSO) packets */ 698 /* Handle LSO (TSO) packets */
683 if (lso_header_size) { 699 if (lso_header_size) {
684 /* Mark opcode as LSO */ 700 /* Mark opcode as LSO */
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 6d7b2bf210ce..552d0fce6f67 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -699,3 +699,47 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
699 699
700 kfree(priv->eq_table.uar_map); 700 kfree(priv->eq_table.uar_map);
701} 701}
702
703/* A test that verifies that we can accept interrupts on all
704 * the irq vectors of the device.
705 * Interrupts are checked using the NOP command.
706 */
707int mlx4_test_interrupts(struct mlx4_dev *dev)
708{
709 struct mlx4_priv *priv = mlx4_priv(dev);
710 int i;
711 int err;
712
713 err = mlx4_NOP(dev);
714 /* When not in MSI_X, there is only one irq to check */
715 if (!(dev->flags & MLX4_FLAG_MSI_X))
716 return err;
717
718 /* A loop over all completion vectors, for each vector we will check
719 * whether it works by mapping command completions to that vector
720 * and performing a NOP command
721 */
722 for(i = 0; !err && (i < dev->caps.num_comp_vectors); ++i) {
723 /* Temporary use polling for command completions */
724 mlx4_cmd_use_polling(dev);
725
726 /* Map the new eq to handle all asyncronous events */
727 err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
728 priv->eq_table.eq[i].eqn);
729 if (err) {
730 mlx4_warn(dev, "Failed mapping eq for interrupt test\n");
731 mlx4_cmd_use_events(dev);
732 break;
733 }
734
735 /* Go back to using events */
736 mlx4_cmd_use_events(dev);
737 err = mlx4_NOP(dev);
738 }
739
740 /* Return to default */
741 mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0,
742 priv->eq_table.eq[dev->caps.num_comp_vectors].eqn);
743 return err;
744}
745EXPORT_SYMBOL(mlx4_test_interrupts);
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
index 04f42ae1eda0..a87bf3c97055 100644
--- a/drivers/net/mlx4/fw.c
+++ b/drivers/net/mlx4/fw.c
@@ -178,6 +178,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
178#define QUERY_DEV_CAP_MAX_GID_OFFSET 0x3b 178#define QUERY_DEV_CAP_MAX_GID_OFFSET 0x3b
179#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET 0x3c 179#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET 0x3c
180#define QUERY_DEV_CAP_MAX_PKEY_OFFSET 0x3f 180#define QUERY_DEV_CAP_MAX_PKEY_OFFSET 0x3f
181#define QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET 0x43
181#define QUERY_DEV_CAP_FLAGS_OFFSET 0x44 182#define QUERY_DEV_CAP_FLAGS_OFFSET 0x44
182#define QUERY_DEV_CAP_RSVD_UAR_OFFSET 0x48 183#define QUERY_DEV_CAP_RSVD_UAR_OFFSET 0x48
183#define QUERY_DEV_CAP_UAR_SZ_OFFSET 0x49 184#define QUERY_DEV_CAP_UAR_SZ_OFFSET 0x49
@@ -268,6 +269,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
268 dev_cap->max_msg_sz = 1 << (field & 0x1f); 269 dev_cap->max_msg_sz = 1 << (field & 0x1f);
269 MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET); 270 MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET);
270 dev_cap->stat_rate_support = stat_rate; 271 dev_cap->stat_rate_support = stat_rate;
272 MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET);
273 dev_cap->loopback_support = field & 0x1;
271 MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); 274 MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET);
272 MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); 275 MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET);
273 dev_cap->reserved_uars = field >> 4; 276 dev_cap->reserved_uars = field >> 4;
diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h
index 526d7f30c041..2cc1ba5452e3 100644
--- a/drivers/net/mlx4/fw.h
+++ b/drivers/net/mlx4/fw.h
@@ -74,6 +74,7 @@ struct mlx4_dev_cap {
74 u64 def_mac[MLX4_MAX_PORTS + 1]; 74 u64 def_mac[MLX4_MAX_PORTS + 1];
75 u16 eth_mtu[MLX4_MAX_PORTS + 1]; 75 u16 eth_mtu[MLX4_MAX_PORTS + 1];
76 u16 stat_rate_support; 76 u16 stat_rate_support;
77 int loopback_support;
77 u32 flags; 78 u32 flags;
78 int reserved_uars; 79 int reserved_uars;
79 int uar_size; 80 int uar_size;
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 5102ab1ac561..7390cdb19414 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -221,6 +221,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
221 dev->caps.bmme_flags = dev_cap->bmme_flags; 221 dev->caps.bmme_flags = dev_cap->bmme_flags;
222 dev->caps.reserved_lkey = dev_cap->reserved_lkey; 222 dev->caps.reserved_lkey = dev_cap->reserved_lkey;
223 dev->caps.stat_rate_support = dev_cap->stat_rate_support; 223 dev->caps.stat_rate_support = dev_cap->stat_rate_support;
224 dev->caps.loopback_support = dev_cap->loopback_support;
224 dev->caps.max_gso_sz = dev_cap->max_gso_sz; 225 dev->caps.max_gso_sz = dev_cap->max_gso_sz;
225 226
226 dev->caps.log_num_macs = log_num_mac; 227 dev->caps.log_num_macs = log_num_mac;
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h
index edf6523702c0..a09598b2b12e 100644
--- a/drivers/net/mlx4/mlx4_en.h
+++ b/drivers/net/mlx4/mlx4_en.h
@@ -45,6 +45,7 @@
45#include <linux/mlx4/cq.h> 45#include <linux/mlx4/cq.h>
46#include <linux/mlx4/srq.h> 46#include <linux/mlx4/srq.h>
47#include <linux/mlx4/doorbell.h> 47#include <linux/mlx4/doorbell.h>
48#include <linux/mlx4/cmd.h>
48 49
49#include "en_port.h" 50#include "en_port.h"
50 51
@@ -139,10 +140,14 @@ enum {
139 140
140#define SMALL_PACKET_SIZE (256 - NET_IP_ALIGN) 141#define SMALL_PACKET_SIZE (256 - NET_IP_ALIGN)
141#define HEADER_COPY_SIZE (128 - NET_IP_ALIGN) 142#define HEADER_COPY_SIZE (128 - NET_IP_ALIGN)
143#define MLX4_LOOPBACK_TEST_PAYLOAD (HEADER_COPY_SIZE - ETH_HLEN)
142 144
143#define MLX4_EN_MIN_MTU 46 145#define MLX4_EN_MIN_MTU 46
144#define ETH_BCAST 0xffffffffffffULL 146#define ETH_BCAST 0xffffffffffffULL
145 147
148#define MLX4_EN_LOOPBACK_RETRIES 5
149#define MLX4_EN_LOOPBACK_TIMEOUT 100
150
146#ifdef MLX4_EN_PERF_STAT 151#ifdef MLX4_EN_PERF_STAT
147/* Number of samples to 'average' */ 152/* Number of samples to 'average' */
148#define AVG_SIZE 128 153#define AVG_SIZE 128
@@ -356,6 +361,12 @@ struct mlx4_en_rss_context {
356 __be32 rss_key[10]; 361 __be32 rss_key[10];
357}; 362};
358 363
364struct mlx4_en_port_state {
365 int link_state;
366 int link_speed;
367 int transciver;
368};
369
359struct mlx4_en_pkt_stats { 370struct mlx4_en_pkt_stats {
360 unsigned long broadcast; 371 unsigned long broadcast;
361 unsigned long rx_prio[8]; 372 unsigned long rx_prio[8];
@@ -404,6 +415,7 @@ struct mlx4_en_priv {
404 struct vlan_group *vlgrp; 415 struct vlan_group *vlgrp;
405 struct net_device_stats stats; 416 struct net_device_stats stats;
406 struct net_device_stats ret_stats; 417 struct net_device_stats ret_stats;
418 struct mlx4_en_port_state port_state;
407 spinlock_t stats_lock; 419 spinlock_t stats_lock;
408 420
409 unsigned long last_moder_packets; 421 unsigned long last_moder_packets;
@@ -422,6 +434,8 @@ struct mlx4_en_priv {
422 u16 sample_interval; 434 u16 sample_interval;
423 u16 adaptive_rx_coal; 435 u16 adaptive_rx_coal;
424 u32 msg_enable; 436 u32 msg_enable;
437 u32 loopback_ok;
438 u32 validate_loopback;
425 439
426 struct mlx4_hwq_resources res; 440 struct mlx4_hwq_resources res;
427 int link_state; 441 int link_state;
@@ -530,6 +544,11 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
530 u8 promisc); 544 u8 promisc);
531 545
532int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset); 546int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset);
547int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port);
548
549#define MLX4_EN_NUM_SELF_TEST 5
550void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf);
551u64 mlx4_en_mac_to_u64(u8 *addr);
533 552
534/* 553/*
535 * Globals 554 * Globals
diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h
index 0f82293a82ed..78a1b9671752 100644
--- a/include/linux/mlx4/cmd.h
+++ b/include/linux/mlx4/cmd.h
@@ -56,6 +56,7 @@ enum {
56 MLX4_CMD_QUERY_HCA = 0xb, 56 MLX4_CMD_QUERY_HCA = 0xb,
57 MLX4_CMD_QUERY_PORT = 0x43, 57 MLX4_CMD_QUERY_PORT = 0x43,
58 MLX4_CMD_SENSE_PORT = 0x4d, 58 MLX4_CMD_SENSE_PORT = 0x4d,
59 MLX4_CMD_HW_HEALTH_CHECK = 0x50,
59 MLX4_CMD_SET_PORT = 0xc, 60 MLX4_CMD_SET_PORT = 0xc,
60 MLX4_CMD_ACCESS_DDR = 0x2e, 61 MLX4_CMD_ACCESS_DDR = 0x2e,
61 MLX4_CMD_MAP_ICM = 0xffa, 62 MLX4_CMD_MAP_ICM = 0xffa,
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 7a7f9c1e679a..2cec58722738 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -229,6 +229,7 @@ struct mlx4_caps {
229 u32 bmme_flags; 229 u32 bmme_flags;
230 u32 reserved_lkey; 230 u32 reserved_lkey;
231 u16 stat_rate_support; 231 u16 stat_rate_support;
232 int loopback_support;
232 u8 port_width_cap[MLX4_MAX_PORTS + 1]; 233 u8 port_width_cap[MLX4_MAX_PORTS + 1];
233 int max_gso_sz; 234 int max_gso_sz;
234 int reserved_qps_cnt[MLX4_NUM_QP_REGION]; 235 int reserved_qps_cnt[MLX4_NUM_QP_REGION];
@@ -480,5 +481,6 @@ void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr,
480 u32 *lkey, u32 *rkey); 481 u32 *lkey, u32 *rkey);
481int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr); 482int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr);
482int mlx4_SYNC_TPT(struct mlx4_dev *dev); 483int mlx4_SYNC_TPT(struct mlx4_dev *dev);
484int mlx4_test_interrupts(struct mlx4_dev *dev);
483 485
484#endif /* MLX4_DEVICE_H */ 486#endif /* MLX4_DEVICE_H */