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