11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (c) 2004 Topspin Communications. All rights reserved. 32a1d9b7fSRoland Dreier * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 42a1d9b7fSRoland Dreier * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This software is available to you under a choice of one of two 71da177e4SLinus Torvalds * licenses. You may choose to be licensed under the terms of the GNU 81da177e4SLinus Torvalds * General Public License (GPL) Version 2, available from the file 91da177e4SLinus Torvalds * COPYING in the main directory of this source tree, or the 101da177e4SLinus Torvalds * OpenIB.org BSD license below: 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * Redistribution and use in source and binary forms, with or 131da177e4SLinus Torvalds * without modification, are permitted provided that the following 141da177e4SLinus Torvalds * conditions are met: 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * - Redistributions of source code must retain the above 171da177e4SLinus Torvalds * copyright notice, this list of conditions and the following 181da177e4SLinus Torvalds * disclaimer. 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds * - Redistributions in binary form must reproduce the above 211da177e4SLinus Torvalds * copyright notice, this list of conditions and the following 221da177e4SLinus Torvalds * disclaimer in the documentation and/or other materials 231da177e4SLinus Torvalds * provided with the distribution. 241da177e4SLinus Torvalds * 251da177e4SLinus Torvalds * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 261da177e4SLinus Torvalds * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 271da177e4SLinus Torvalds * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 281da177e4SLinus Torvalds * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 291da177e4SLinus Torvalds * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 301da177e4SLinus Torvalds * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 311da177e4SLinus Torvalds * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 321da177e4SLinus Torvalds * SOFTWARE. 331da177e4SLinus Torvalds * 341da177e4SLinus Torvalds * $Id: ipoib_main.c 1377 2004-12-23 19:57:12Z roland $ 351da177e4SLinus Torvalds */ 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds #include "ipoib.h" 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds #include <linux/module.h> 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds #include <linux/init.h> 421da177e4SLinus Torvalds #include <linux/slab.h> 430f485251SShirley Ma #include <linux/kernel.h> 4410313cbbSRoland Dreier #include <linux/vmalloc.h> 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds #include <linux/if_arp.h> /* For ARPHRD_xxx */ 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds #include <linux/ip.h> 491da177e4SLinus Torvalds #include <linux/in.h> 501da177e4SLinus Torvalds 5114c85021SArnaldo Carvalho de Melo #include <net/dst.h> 5214c85021SArnaldo Carvalho de Melo 531da177e4SLinus Torvalds MODULE_AUTHOR("Roland Dreier"); 541da177e4SLinus Torvalds MODULE_DESCRIPTION("IP-over-InfiniBand net driver"); 551da177e4SLinus Torvalds MODULE_LICENSE("Dual BSD/GPL"); 561da177e4SLinus Torvalds 570f485251SShirley Ma int ipoib_sendq_size __read_mostly = IPOIB_TX_RING_SIZE; 580f485251SShirley Ma int ipoib_recvq_size __read_mostly = IPOIB_RX_RING_SIZE; 590f485251SShirley Ma 600f485251SShirley Ma module_param_named(send_queue_size, ipoib_sendq_size, int, 0444); 610f485251SShirley Ma MODULE_PARM_DESC(send_queue_size, "Number of descriptors in send queue"); 620f485251SShirley Ma module_param_named(recv_queue_size, ipoib_recvq_size, int, 0444); 630f485251SShirley Ma MODULE_PARM_DESC(recv_queue_size, "Number of descriptors in receive queue"); 640f485251SShirley Ma 651da177e4SLinus Torvalds #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 661da177e4SLinus Torvalds int ipoib_debug_level; 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds module_param_named(debug_level, ipoib_debug_level, int, 0644); 691da177e4SLinus Torvalds MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); 701da177e4SLinus Torvalds #endif 711da177e4SLinus Torvalds 721732b0efSRoland Dreier struct ipoib_path_iter { 731732b0efSRoland Dreier struct net_device *dev; 741732b0efSRoland Dreier struct ipoib_path path; 751732b0efSRoland Dreier }; 761732b0efSRoland Dreier 771da177e4SLinus Torvalds static const u8 ipv4_bcast_addr[] = { 781da177e4SLinus Torvalds 0x00, 0xff, 0xff, 0xff, 791da177e4SLinus Torvalds 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, 801da177e4SLinus Torvalds 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff 811da177e4SLinus Torvalds }; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds struct workqueue_struct *ipoib_workqueue; 841da177e4SLinus Torvalds 85c1a0b23bSMichael S. Tsirkin struct ib_sa_client ipoib_sa_client; 86c1a0b23bSMichael S. Tsirkin 871da177e4SLinus Torvalds static void ipoib_add_one(struct ib_device *device); 881da177e4SLinus Torvalds static void ipoib_remove_one(struct ib_device *device); 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds static struct ib_client ipoib_client = { 911da177e4SLinus Torvalds .name = "ipoib", 921da177e4SLinus Torvalds .add = ipoib_add_one, 931da177e4SLinus Torvalds .remove = ipoib_remove_one 941da177e4SLinus Torvalds }; 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds int ipoib_open(struct net_device *dev) 971da177e4SLinus Torvalds { 981da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds ipoib_dbg(priv, "bringing up interface\n"); 1011da177e4SLinus Torvalds 102bea3348eSStephen Hemminger napi_enable(&priv->napi); 1031da177e4SLinus Torvalds set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds if (ipoib_pkey_dev_delay_open(dev)) 1061da177e4SLinus Torvalds return 0; 1071da177e4SLinus Torvalds 108bea3348eSStephen Hemminger if (ipoib_ib_dev_open(dev)) { 109bea3348eSStephen Hemminger napi_disable(&priv->napi); 1101da177e4SLinus Torvalds return -EINVAL; 111bea3348eSStephen Hemminger } 1121da177e4SLinus Torvalds 113267ee88eSRoland Dreier if (ipoib_ib_dev_up(dev)) { 11426bbf13cSYosef Etigin ipoib_ib_dev_stop(dev, 1); 115bea3348eSStephen Hemminger napi_disable(&priv->napi); 1161da177e4SLinus Torvalds return -EINVAL; 117267ee88eSRoland Dreier } 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { 1201da177e4SLinus Torvalds struct ipoib_dev_priv *cpriv; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds /* Bring up any child interfaces too */ 12395ed644fSIngo Molnar mutex_lock(&priv->vlan_mutex); 1241da177e4SLinus Torvalds list_for_each_entry(cpriv, &priv->child_intfs, list) { 1251da177e4SLinus Torvalds int flags; 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds flags = cpriv->dev->flags; 1281da177e4SLinus Torvalds if (flags & IFF_UP) 1291da177e4SLinus Torvalds continue; 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds dev_change_flags(cpriv->dev, flags | IFF_UP); 1321da177e4SLinus Torvalds } 13395ed644fSIngo Molnar mutex_unlock(&priv->vlan_mutex); 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds netif_start_queue(dev); 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds return 0; 1391da177e4SLinus Torvalds } 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds static int ipoib_stop(struct net_device *dev) 1421da177e4SLinus Torvalds { 1431da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds ipoib_dbg(priv, "stopping interface\n"); 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); 148bea3348eSStephen Hemminger napi_disable(&priv->napi); 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds netif_stop_queue(dev); 1511da177e4SLinus Torvalds 1520b3ea082SJack Morgenstein /* 1530b3ea082SJack Morgenstein * Now flush workqueue to make sure a scheduled task doesn't 1540b3ea082SJack Morgenstein * bring our internal state back up. 1550b3ea082SJack Morgenstein */ 1560b3ea082SJack Morgenstein flush_workqueue(ipoib_workqueue); 1570b3ea082SJack Morgenstein 1580b3ea082SJack Morgenstein ipoib_ib_dev_down(dev, 1); 15926bbf13cSYosef Etigin ipoib_ib_dev_stop(dev, 1); 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { 1621da177e4SLinus Torvalds struct ipoib_dev_priv *cpriv; 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds /* Bring down any child interfaces too */ 16595ed644fSIngo Molnar mutex_lock(&priv->vlan_mutex); 1661da177e4SLinus Torvalds list_for_each_entry(cpriv, &priv->child_intfs, list) { 1671da177e4SLinus Torvalds int flags; 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds flags = cpriv->dev->flags; 1701da177e4SLinus Torvalds if (!(flags & IFF_UP)) 1711da177e4SLinus Torvalds continue; 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds dev_change_flags(cpriv->dev, flags & ~IFF_UP); 1741da177e4SLinus Torvalds } 17595ed644fSIngo Molnar mutex_unlock(&priv->vlan_mutex); 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds return 0; 1791da177e4SLinus Torvalds } 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds static int ipoib_change_mtu(struct net_device *dev, int new_mtu) 1821da177e4SLinus Torvalds { 1831da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 1841da177e4SLinus Torvalds 185839fcabaSMichael S. Tsirkin /* dev->mtu > 2K ==> connected mode */ 186586a6934SPradeep Satyanarayana if (ipoib_cm_admin_enabled(dev)) { 187586a6934SPradeep Satyanarayana if (new_mtu > ipoib_cm_max_mtu(dev)) 188586a6934SPradeep Satyanarayana return -EINVAL; 189586a6934SPradeep Satyanarayana 190839fcabaSMichael S. Tsirkin if (new_mtu > priv->mcast_mtu) 191839fcabaSMichael S. Tsirkin ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n", 192839fcabaSMichael S. Tsirkin priv->mcast_mtu); 193586a6934SPradeep Satyanarayana 194839fcabaSMichael S. Tsirkin dev->mtu = new_mtu; 195839fcabaSMichael S. Tsirkin return 0; 196839fcabaSMichael S. Tsirkin } 197839fcabaSMichael S. Tsirkin 198bc7b3a36SShirley Ma if (new_mtu > IPOIB_UD_MTU(priv->max_ib_mtu)) 1991da177e4SLinus Torvalds return -EINVAL; 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds priv->admin_mtu = new_mtu; 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds dev->mtu = min(priv->mcast_mtu, priv->admin_mtu); 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds return 0; 2061da177e4SLinus Torvalds } 2071da177e4SLinus Torvalds 20837c22a77SJack Morgenstein static struct ipoib_path *__path_find(struct net_device *dev, void *gid) 2091da177e4SLinus Torvalds { 2101da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 2111da177e4SLinus Torvalds struct rb_node *n = priv->path_tree.rb_node; 2121da177e4SLinus Torvalds struct ipoib_path *path; 2131da177e4SLinus Torvalds int ret; 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds while (n) { 2161da177e4SLinus Torvalds path = rb_entry(n, struct ipoib_path, rb_node); 2171da177e4SLinus Torvalds 21837c22a77SJack Morgenstein ret = memcmp(gid, path->pathrec.dgid.raw, 2191da177e4SLinus Torvalds sizeof (union ib_gid)); 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds if (ret < 0) 2221da177e4SLinus Torvalds n = n->rb_left; 2231da177e4SLinus Torvalds else if (ret > 0) 2241da177e4SLinus Torvalds n = n->rb_right; 2251da177e4SLinus Torvalds else 2261da177e4SLinus Torvalds return path; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds return NULL; 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds static int __path_add(struct net_device *dev, struct ipoib_path *path) 2331da177e4SLinus Torvalds { 2341da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 2351da177e4SLinus Torvalds struct rb_node **n = &priv->path_tree.rb_node; 2361da177e4SLinus Torvalds struct rb_node *pn = NULL; 2371da177e4SLinus Torvalds struct ipoib_path *tpath; 2381da177e4SLinus Torvalds int ret; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds while (*n) { 2411da177e4SLinus Torvalds pn = *n; 2421da177e4SLinus Torvalds tpath = rb_entry(pn, struct ipoib_path, rb_node); 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds ret = memcmp(path->pathrec.dgid.raw, tpath->pathrec.dgid.raw, 2451da177e4SLinus Torvalds sizeof (union ib_gid)); 2461da177e4SLinus Torvalds if (ret < 0) 2471da177e4SLinus Torvalds n = &pn->rb_left; 2481da177e4SLinus Torvalds else if (ret > 0) 2491da177e4SLinus Torvalds n = &pn->rb_right; 2501da177e4SLinus Torvalds else 2511da177e4SLinus Torvalds return -EEXIST; 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds rb_link_node(&path->rb_node, pn, n); 2551da177e4SLinus Torvalds rb_insert_color(&path->rb_node, &priv->path_tree); 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds list_add_tail(&path->list, &priv->path_list); 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds return 0; 2601da177e4SLinus Torvalds } 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds static void path_free(struct net_device *dev, struct ipoib_path *path) 2631da177e4SLinus Torvalds { 2641da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 2651da177e4SLinus Torvalds struct ipoib_neigh *neigh, *tn; 2661da177e4SLinus Torvalds struct sk_buff *skb; 2671da177e4SLinus Torvalds unsigned long flags; 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds while ((skb = __skb_dequeue(&path->queue))) 2701da177e4SLinus Torvalds dev_kfree_skb_irq(skb); 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds list_for_each_entry_safe(neigh, tn, &path->neigh_list, list) { 2751da177e4SLinus Torvalds /* 2761da177e4SLinus Torvalds * It's safe to call ipoib_put_ah() inside priv->lock 2771da177e4SLinus Torvalds * here, because we know that path->ah will always 2781da177e4SLinus Torvalds * hold one more reference, so ipoib_put_ah() will 2791da177e4SLinus Torvalds * never do more than decrement the ref count. 2801da177e4SLinus Torvalds */ 2811da177e4SLinus Torvalds if (neigh->ah) 2821da177e4SLinus Torvalds ipoib_put_ah(neigh->ah); 283d2e0655eSMichael S. Tsirkin 2842745b5b7SMichael S. Tsirkin ipoib_neigh_free(dev, neigh); 2851da177e4SLinus Torvalds } 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds if (path->ah) 2901da177e4SLinus Torvalds ipoib_put_ah(path->ah); 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds kfree(path); 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2951732b0efSRoland Dreier #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 2961732b0efSRoland Dreier 2971732b0efSRoland Dreier struct ipoib_path_iter *ipoib_path_iter_init(struct net_device *dev) 2981732b0efSRoland Dreier { 2991732b0efSRoland Dreier struct ipoib_path_iter *iter; 3001732b0efSRoland Dreier 3011732b0efSRoland Dreier iter = kmalloc(sizeof *iter, GFP_KERNEL); 3021732b0efSRoland Dreier if (!iter) 3031732b0efSRoland Dreier return NULL; 3041732b0efSRoland Dreier 3051732b0efSRoland Dreier iter->dev = dev; 3061732b0efSRoland Dreier memset(iter->path.pathrec.dgid.raw, 0, 16); 3071732b0efSRoland Dreier 3081732b0efSRoland Dreier if (ipoib_path_iter_next(iter)) { 3091732b0efSRoland Dreier kfree(iter); 3101732b0efSRoland Dreier return NULL; 3111732b0efSRoland Dreier } 3121732b0efSRoland Dreier 3131732b0efSRoland Dreier return iter; 3141732b0efSRoland Dreier } 3151732b0efSRoland Dreier 3161732b0efSRoland Dreier int ipoib_path_iter_next(struct ipoib_path_iter *iter) 3171732b0efSRoland Dreier { 3181732b0efSRoland Dreier struct ipoib_dev_priv *priv = netdev_priv(iter->dev); 3191732b0efSRoland Dreier struct rb_node *n; 3201732b0efSRoland Dreier struct ipoib_path *path; 3211732b0efSRoland Dreier int ret = 1; 3221732b0efSRoland Dreier 3231732b0efSRoland Dreier spin_lock_irq(&priv->lock); 3241732b0efSRoland Dreier 3251732b0efSRoland Dreier n = rb_first(&priv->path_tree); 3261732b0efSRoland Dreier 3271732b0efSRoland Dreier while (n) { 3281732b0efSRoland Dreier path = rb_entry(n, struct ipoib_path, rb_node); 3291732b0efSRoland Dreier 3301732b0efSRoland Dreier if (memcmp(iter->path.pathrec.dgid.raw, path->pathrec.dgid.raw, 3311732b0efSRoland Dreier sizeof (union ib_gid)) < 0) { 3321732b0efSRoland Dreier iter->path = *path; 3331732b0efSRoland Dreier ret = 0; 3341732b0efSRoland Dreier break; 3351732b0efSRoland Dreier } 3361732b0efSRoland Dreier 3371732b0efSRoland Dreier n = rb_next(n); 3381732b0efSRoland Dreier } 3391732b0efSRoland Dreier 3401732b0efSRoland Dreier spin_unlock_irq(&priv->lock); 3411732b0efSRoland Dreier 3421732b0efSRoland Dreier return ret; 3431732b0efSRoland Dreier } 3441732b0efSRoland Dreier 3451732b0efSRoland Dreier void ipoib_path_iter_read(struct ipoib_path_iter *iter, 3461732b0efSRoland Dreier struct ipoib_path *path) 3471732b0efSRoland Dreier { 3481732b0efSRoland Dreier *path = iter->path; 3491732b0efSRoland Dreier } 3501732b0efSRoland Dreier 3511732b0efSRoland Dreier #endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */ 3521732b0efSRoland Dreier 3531da177e4SLinus Torvalds void ipoib_flush_paths(struct net_device *dev) 3541da177e4SLinus Torvalds { 3551da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 3561da177e4SLinus Torvalds struct ipoib_path *path, *tp; 3571da177e4SLinus Torvalds LIST_HEAD(remove_list); 3581da177e4SLinus Torvalds 3599217b27bSMichael S. Tsirkin spin_lock_irq(&priv->tx_lock); 3609217b27bSMichael S. Tsirkin spin_lock(&priv->lock); 3611da177e4SLinus Torvalds 362157de229SRobert P. J. Day list_splice_init(&priv->path_list, &remove_list); 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds list_for_each_entry(path, &remove_list, list) 3651da177e4SLinus Torvalds rb_erase(&path->rb_node, &priv->path_tree); 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds list_for_each_entry_safe(path, tp, &remove_list, list) { 3681da177e4SLinus Torvalds if (path->query) 3691da177e4SLinus Torvalds ib_sa_cancel_query(path->query_id, path->query); 3709217b27bSMichael S. Tsirkin spin_unlock(&priv->lock); 3719217b27bSMichael S. Tsirkin spin_unlock_irq(&priv->tx_lock); 3721da177e4SLinus Torvalds wait_for_completion(&path->done); 3731da177e4SLinus Torvalds path_free(dev, path); 3749217b27bSMichael S. Tsirkin spin_lock_irq(&priv->tx_lock); 3759217b27bSMichael S. Tsirkin spin_lock(&priv->lock); 3761da177e4SLinus Torvalds } 3779217b27bSMichael S. Tsirkin spin_unlock(&priv->lock); 3789217b27bSMichael S. Tsirkin spin_unlock_irq(&priv->tx_lock); 3791da177e4SLinus Torvalds } 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds static void path_rec_completion(int status, 3821da177e4SLinus Torvalds struct ib_sa_path_rec *pathrec, 3831da177e4SLinus Torvalds void *path_ptr) 3841da177e4SLinus Torvalds { 3851da177e4SLinus Torvalds struct ipoib_path *path = path_ptr; 3861da177e4SLinus Torvalds struct net_device *dev = path->dev; 3871da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 3881da177e4SLinus Torvalds struct ipoib_ah *ah = NULL; 389d04d01b1SMichael S. Tsirkin struct ipoib_neigh *neigh, *tn; 3901da177e4SLinus Torvalds struct sk_buff_head skqueue; 3911da177e4SLinus Torvalds struct sk_buff *skb; 3921da177e4SLinus Torvalds unsigned long flags; 3931da177e4SLinus Torvalds 394843613b0SRoland Dreier if (!status) 3951da177e4SLinus Torvalds ipoib_dbg(priv, "PathRec LID 0x%04x for GID " IPOIB_GID_FMT "\n", 3961da177e4SLinus Torvalds be16_to_cpu(pathrec->dlid), IPOIB_GID_ARG(pathrec->dgid)); 3971da177e4SLinus Torvalds else 3981da177e4SLinus Torvalds ipoib_dbg(priv, "PathRec status %d for GID " IPOIB_GID_FMT "\n", 3991da177e4SLinus Torvalds status, IPOIB_GID_ARG(path->pathrec.dgid)); 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds skb_queue_head_init(&skqueue); 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds if (!status) { 40446f1b3d7SSean Hefty struct ib_ah_attr av; 4051da177e4SLinus Torvalds 40646f1b3d7SSean Hefty if (!ib_init_ah_from_path(priv->ca, priv->port, pathrec, &av)) 4071da177e4SLinus Torvalds ah = ipoib_create_ah(dev, priv->pd, &av); 4081da177e4SLinus Torvalds } 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds path->ah = ah; 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds if (ah) { 4151da177e4SLinus Torvalds path->pathrec = *pathrec; 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds ipoib_dbg(priv, "created address handle %p for LID 0x%04x, SL %d\n", 4181da177e4SLinus Torvalds ah, be16_to_cpu(pathrec->dlid), pathrec->sl); 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds while ((skb = __skb_dequeue(&path->queue))) 4211da177e4SLinus Torvalds __skb_queue_tail(&skqueue, skb); 4221da177e4SLinus Torvalds 423d04d01b1SMichael S. Tsirkin list_for_each_entry_safe(neigh, tn, &path->neigh_list, list) { 4241da177e4SLinus Torvalds kref_get(&path->ah->ref); 4251da177e4SLinus Torvalds neigh->ah = path->ah; 4268a7f7521SMichael S. Tsirkin memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw, 4278a7f7521SMichael S. Tsirkin sizeof(union ib_gid)); 4281da177e4SLinus Torvalds 429839fcabaSMichael S. Tsirkin if (ipoib_cm_enabled(dev, neigh->neighbour)) { 430839fcabaSMichael S. Tsirkin if (!ipoib_cm_get(neigh)) 431839fcabaSMichael S. Tsirkin ipoib_cm_set(neigh, ipoib_cm_create_tx(dev, 432839fcabaSMichael S. Tsirkin path, 433839fcabaSMichael S. Tsirkin neigh)); 434839fcabaSMichael S. Tsirkin if (!ipoib_cm_get(neigh)) { 435839fcabaSMichael S. Tsirkin list_del(&neigh->list); 436839fcabaSMichael S. Tsirkin if (neigh->ah) 437839fcabaSMichael S. Tsirkin ipoib_put_ah(neigh->ah); 438839fcabaSMichael S. Tsirkin ipoib_neigh_free(dev, neigh); 439839fcabaSMichael S. Tsirkin continue; 440839fcabaSMichael S. Tsirkin } 441839fcabaSMichael S. Tsirkin } 442839fcabaSMichael S. Tsirkin 4431da177e4SLinus Torvalds while ((skb = __skb_dequeue(&neigh->queue))) 4441da177e4SLinus Torvalds __skb_queue_tail(&skqueue, skb); 4451da177e4SLinus Torvalds } 4465872a9fcSRoland Dreier } 4471da177e4SLinus Torvalds 4485872a9fcSRoland Dreier path->query = NULL; 4491da177e4SLinus Torvalds complete(&path->done); 4501da177e4SLinus Torvalds 4511da177e4SLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds while ((skb = __skb_dequeue(&skqueue))) { 4541da177e4SLinus Torvalds skb->dev = dev; 4551da177e4SLinus Torvalds if (dev_queue_xmit(skb)) 4561da177e4SLinus Torvalds ipoib_warn(priv, "dev_queue_xmit failed " 4571da177e4SLinus Torvalds "to requeue packet\n"); 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds } 4601da177e4SLinus Torvalds 46137c22a77SJack Morgenstein static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid) 4621da177e4SLinus Torvalds { 4631da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 4641da177e4SLinus Torvalds struct ipoib_path *path; 4651da177e4SLinus Torvalds 4661401b53aSJack Morgenstein if (!priv->broadcast) 4671401b53aSJack Morgenstein return NULL; 4681401b53aSJack Morgenstein 46921a38489SRoland Dreier path = kzalloc(sizeof *path, GFP_ATOMIC); 4701da177e4SLinus Torvalds if (!path) 4711da177e4SLinus Torvalds return NULL; 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds path->dev = dev; 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds skb_queue_head_init(&path->queue); 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds INIT_LIST_HEAD(&path->neigh_list); 4781da177e4SLinus Torvalds 47937c22a77SJack Morgenstein memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid)); 4801da177e4SLinus Torvalds path->pathrec.sgid = priv->local_gid; 4811da177e4SLinus Torvalds path->pathrec.pkey = cpu_to_be16(priv->pkey); 4821da177e4SLinus Torvalds path->pathrec.numb_path = 1; 48381668838SSean Hefty path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class; 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds return path; 4861da177e4SLinus Torvalds } 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds static int path_rec_start(struct net_device *dev, 4891da177e4SLinus Torvalds struct ipoib_path *path) 4901da177e4SLinus Torvalds { 4911da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds ipoib_dbg(priv, "Start path record lookup for " IPOIB_GID_FMT "\n", 4941da177e4SLinus Torvalds IPOIB_GID_ARG(path->pathrec.dgid)); 4951da177e4SLinus Torvalds 49665c7eddaSRoland Dreier init_completion(&path->done); 49765c7eddaSRoland Dreier 4981da177e4SLinus Torvalds path->query_id = 499c1a0b23bSMichael S. Tsirkin ib_sa_path_rec_get(&ipoib_sa_client, priv->ca, priv->port, 5001da177e4SLinus Torvalds &path->pathrec, 5011da177e4SLinus Torvalds IB_SA_PATH_REC_DGID | 5021da177e4SLinus Torvalds IB_SA_PATH_REC_SGID | 5031da177e4SLinus Torvalds IB_SA_PATH_REC_NUMB_PATH | 50481668838SSean Hefty IB_SA_PATH_REC_TRAFFIC_CLASS | 5051da177e4SLinus Torvalds IB_SA_PATH_REC_PKEY, 5061da177e4SLinus Torvalds 1000, GFP_ATOMIC, 5071da177e4SLinus Torvalds path_rec_completion, 5081da177e4SLinus Torvalds path, &path->query); 5091da177e4SLinus Torvalds if (path->query_id < 0) { 5101da177e4SLinus Torvalds ipoib_warn(priv, "ib_sa_path_rec_get failed\n"); 5111da177e4SLinus Torvalds path->query = NULL; 5121da177e4SLinus Torvalds return path->query_id; 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds return 0; 5161da177e4SLinus Torvalds } 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) 5191da177e4SLinus Torvalds { 5201da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 5211da177e4SLinus Torvalds struct ipoib_path *path; 5221da177e4SLinus Torvalds struct ipoib_neigh *neigh; 5231da177e4SLinus Torvalds 524732a2170SMoni Shoua neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev); 5251da177e4SLinus Torvalds if (!neigh) { 526de903512SRoland Dreier ++dev->stats.tx_dropped; 5271da177e4SLinus Torvalds dev_kfree_skb_any(skb); 5281da177e4SLinus Torvalds return; 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds /* 5321da177e4SLinus Torvalds * We can only be called from ipoib_start_xmit, so we're 5331da177e4SLinus Torvalds * inside tx_lock -- no need to save/restore flags. 5341da177e4SLinus Torvalds */ 5351da177e4SLinus Torvalds spin_lock(&priv->lock); 5361da177e4SLinus Torvalds 53737c22a77SJack Morgenstein path = __path_find(dev, skb->dst->neighbour->ha + 4); 5381da177e4SLinus Torvalds if (!path) { 53937c22a77SJack Morgenstein path = path_rec_create(dev, skb->dst->neighbour->ha + 4); 5401da177e4SLinus Torvalds if (!path) 541d2e0655eSMichael S. Tsirkin goto err_path; 5421da177e4SLinus Torvalds 5431da177e4SLinus Torvalds __path_add(dev, path); 5441da177e4SLinus Torvalds } 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds list_add_tail(&neigh->list, &path->neigh_list); 5471da177e4SLinus Torvalds 54847f7a071SMichael S. Tsirkin if (path->ah) { 5491da177e4SLinus Torvalds kref_get(&path->ah->ref); 5501da177e4SLinus Torvalds neigh->ah = path->ah; 5518a7f7521SMichael S. Tsirkin memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw, 5528a7f7521SMichael S. Tsirkin sizeof(union ib_gid)); 5531da177e4SLinus Torvalds 554839fcabaSMichael S. Tsirkin if (ipoib_cm_enabled(dev, neigh->neighbour)) { 555839fcabaSMichael S. Tsirkin if (!ipoib_cm_get(neigh)) 556839fcabaSMichael S. Tsirkin ipoib_cm_set(neigh, ipoib_cm_create_tx(dev, path, neigh)); 557839fcabaSMichael S. Tsirkin if (!ipoib_cm_get(neigh)) { 558839fcabaSMichael S. Tsirkin list_del(&neigh->list); 559839fcabaSMichael S. Tsirkin if (neigh->ah) 560839fcabaSMichael S. Tsirkin ipoib_put_ah(neigh->ah); 561839fcabaSMichael S. Tsirkin ipoib_neigh_free(dev, neigh); 562839fcabaSMichael S. Tsirkin goto err_drop; 563839fcabaSMichael S. Tsirkin } 564839fcabaSMichael S. Tsirkin if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) 565839fcabaSMichael S. Tsirkin __skb_queue_tail(&neigh->queue, skb); 566839fcabaSMichael S. Tsirkin else { 567839fcabaSMichael S. Tsirkin ipoib_warn(priv, "queue length limit %d. Packet drop.\n", 568839fcabaSMichael S. Tsirkin skb_queue_len(&neigh->queue)); 569839fcabaSMichael S. Tsirkin goto err_drop; 570839fcabaSMichael S. Tsirkin } 571839fcabaSMichael S. Tsirkin } else 572073ae841SMichael S. Tsirkin ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha)); 5731da177e4SLinus Torvalds } else { 5741da177e4SLinus Torvalds neigh->ah = NULL; 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds if (!path->query && path_rec_start(dev, path)) 577d2e0655eSMichael S. Tsirkin goto err_list; 5782745b5b7SMichael S. Tsirkin 5792745b5b7SMichael S. Tsirkin __skb_queue_tail(&neigh->queue, skb); 5801da177e4SLinus Torvalds } 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds spin_unlock(&priv->lock); 5831da177e4SLinus Torvalds return; 5841da177e4SLinus Torvalds 585d2e0655eSMichael S. Tsirkin err_list: 5861da177e4SLinus Torvalds list_del(&neigh->list); 5871da177e4SLinus Torvalds 588d2e0655eSMichael S. Tsirkin err_path: 5892745b5b7SMichael S. Tsirkin ipoib_neigh_free(dev, neigh); 590839fcabaSMichael S. Tsirkin err_drop: 591de903512SRoland Dreier ++dev->stats.tx_dropped; 5921da177e4SLinus Torvalds dev_kfree_skb_any(skb); 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds spin_unlock(&priv->lock); 5951da177e4SLinus Torvalds } 5961da177e4SLinus Torvalds 597d70ed607SRoland Dreier static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev) 5981da177e4SLinus Torvalds { 5991da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(skb->dev); 6001da177e4SLinus Torvalds 6011da177e4SLinus Torvalds /* Look up path record for unicasts */ 6021da177e4SLinus Torvalds if (skb->dst->neighbour->ha[4] != 0xff) { 6031da177e4SLinus Torvalds neigh_add_path(skb, dev); 6041da177e4SLinus Torvalds return; 6051da177e4SLinus Torvalds } 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds /* Add in the P_Key for multicasts */ 6081da177e4SLinus Torvalds skb->dst->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; 6091da177e4SLinus Torvalds skb->dst->neighbour->ha[9] = priv->pkey & 0xff; 61037c22a77SJack Morgenstein ipoib_mcast_send(dev, skb->dst->neighbour->ha + 4, skb); 6111da177e4SLinus Torvalds } 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, 6141da177e4SLinus Torvalds struct ipoib_pseudoheader *phdr) 6151da177e4SLinus Torvalds { 6161da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 6171da177e4SLinus Torvalds struct ipoib_path *path; 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds /* 6201da177e4SLinus Torvalds * We can only be called from ipoib_start_xmit, so we're 6211da177e4SLinus Torvalds * inside tx_lock -- no need to save/restore flags. 6221da177e4SLinus Torvalds */ 6231da177e4SLinus Torvalds spin_lock(&priv->lock); 6241da177e4SLinus Torvalds 62537c22a77SJack Morgenstein path = __path_find(dev, phdr->hwaddr + 4); 6261da177e4SLinus Torvalds if (!path) { 62737c22a77SJack Morgenstein path = path_rec_create(dev, phdr->hwaddr + 4); 6281da177e4SLinus Torvalds if (path) { 6291da177e4SLinus Torvalds /* put pseudoheader back on for next time */ 6301da177e4SLinus Torvalds skb_push(skb, sizeof *phdr); 6311da177e4SLinus Torvalds __skb_queue_tail(&path->queue, skb); 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds if (path_rec_start(dev, path)) { 6341da177e4SLinus Torvalds spin_unlock(&priv->lock); 6351da177e4SLinus Torvalds path_free(dev, path); 6361da177e4SLinus Torvalds return; 6371da177e4SLinus Torvalds } else 6381da177e4SLinus Torvalds __path_add(dev, path); 6391da177e4SLinus Torvalds } else { 640de903512SRoland Dreier ++dev->stats.tx_dropped; 6411da177e4SLinus Torvalds dev_kfree_skb_any(skb); 6421da177e4SLinus Torvalds } 6431da177e4SLinus Torvalds 6441da177e4SLinus Torvalds spin_unlock(&priv->lock); 6451da177e4SLinus Torvalds return; 6461da177e4SLinus Torvalds } 6471da177e4SLinus Torvalds 64847f7a071SMichael S. Tsirkin if (path->ah) { 6491da177e4SLinus Torvalds ipoib_dbg(priv, "Send unicast ARP to %04x\n", 6501da177e4SLinus Torvalds be16_to_cpu(path->pathrec.dlid)); 6511da177e4SLinus Torvalds 652073ae841SMichael S. Tsirkin ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr)); 6531da177e4SLinus Torvalds } else if ((path->query || !path_rec_start(dev, path)) && 6541da177e4SLinus Torvalds skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { 6551da177e4SLinus Torvalds /* put pseudoheader back on for next time */ 6561da177e4SLinus Torvalds skb_push(skb, sizeof *phdr); 6571da177e4SLinus Torvalds __skb_queue_tail(&path->queue, skb); 6581da177e4SLinus Torvalds } else { 659de903512SRoland Dreier ++dev->stats.tx_dropped; 6601da177e4SLinus Torvalds dev_kfree_skb_any(skb); 6611da177e4SLinus Torvalds } 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds spin_unlock(&priv->lock); 6641da177e4SLinus Torvalds } 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) 6671da177e4SLinus Torvalds { 6681da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 6691da177e4SLinus Torvalds struct ipoib_neigh *neigh; 6701da177e4SLinus Torvalds unsigned long flags; 6711da177e4SLinus Torvalds 672a8bfca02SEli Cohen if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags))) 6731da177e4SLinus Torvalds return NETDEV_TX_LOCKED; 6741da177e4SLinus Torvalds 675a8bfca02SEli Cohen if (likely(skb->dst && skb->dst->neighbour)) { 6761da177e4SLinus Torvalds if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) { 677d70ed607SRoland Dreier ipoib_path_lookup(skb, dev); 6781da177e4SLinus Torvalds goto out; 6791da177e4SLinus Torvalds } 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds neigh = *to_ipoib_neigh(skb->dst->neighbour); 6821da177e4SLinus Torvalds 683bafff974SOr Gerlitz if (neigh->ah) 684200d1713SMoni Shoua if (unlikely((memcmp(&neigh->dgid.raw, 6858a7f7521SMichael S. Tsirkin skb->dst->neighbour->ha + 4, 686200d1713SMoni Shoua sizeof(union ib_gid))) || 687200d1713SMoni Shoua (neigh->dev != dev))) { 6888a7f7521SMichael S. Tsirkin spin_lock(&priv->lock); 6898a7f7521SMichael S. Tsirkin /* 6908a7f7521SMichael S. Tsirkin * It's safe to call ipoib_put_ah() inside 6918a7f7521SMichael S. Tsirkin * priv->lock here, because we know that 6928a7f7521SMichael S. Tsirkin * path->ah will always hold one more reference, 6938a7f7521SMichael S. Tsirkin * so ipoib_put_ah() will never do more than 6948a7f7521SMichael S. Tsirkin * decrement the ref count. 6958a7f7521SMichael S. Tsirkin */ 6968a7f7521SMichael S. Tsirkin ipoib_put_ah(neigh->ah); 6978a7f7521SMichael S. Tsirkin list_del(&neigh->list); 6982745b5b7SMichael S. Tsirkin ipoib_neigh_free(dev, neigh); 6998a7f7521SMichael S. Tsirkin spin_unlock(&priv->lock); 7008a7f7521SMichael S. Tsirkin ipoib_path_lookup(skb, dev); 7018a7f7521SMichael S. Tsirkin goto out; 7028a7f7521SMichael S. Tsirkin } 7038a7f7521SMichael S. Tsirkin 704bafff974SOr Gerlitz if (ipoib_cm_get(neigh)) { 705bafff974SOr Gerlitz if (ipoib_cm_up(neigh)) { 706bafff974SOr Gerlitz ipoib_cm_send(dev, skb, ipoib_cm_get(neigh)); 707bafff974SOr Gerlitz goto out; 708bafff974SOr Gerlitz } 709bafff974SOr Gerlitz } else if (neigh->ah) { 710073ae841SMichael S. Tsirkin ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha)); 7111da177e4SLinus Torvalds goto out; 7121da177e4SLinus Torvalds } 7131da177e4SLinus Torvalds 7141da177e4SLinus Torvalds if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { 7151da177e4SLinus Torvalds spin_lock(&priv->lock); 7161da177e4SLinus Torvalds __skb_queue_tail(&neigh->queue, skb); 7171da177e4SLinus Torvalds spin_unlock(&priv->lock); 7181da177e4SLinus Torvalds } else { 719de903512SRoland Dreier ++dev->stats.tx_dropped; 7201da177e4SLinus Torvalds dev_kfree_skb_any(skb); 7211da177e4SLinus Torvalds } 7221da177e4SLinus Torvalds } else { 7231da177e4SLinus Torvalds struct ipoib_pseudoheader *phdr = 7241da177e4SLinus Torvalds (struct ipoib_pseudoheader *) skb->data; 7251da177e4SLinus Torvalds skb_pull(skb, sizeof *phdr); 7261da177e4SLinus Torvalds 7271da177e4SLinus Torvalds if (phdr->hwaddr[4] == 0xff) { 7281da177e4SLinus Torvalds /* Add in the P_Key for multicast*/ 7291da177e4SLinus Torvalds phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff; 7301da177e4SLinus Torvalds phdr->hwaddr[9] = priv->pkey & 0xff; 7311da177e4SLinus Torvalds 73237c22a77SJack Morgenstein ipoib_mcast_send(dev, phdr->hwaddr + 4, skb); 7331da177e4SLinus Torvalds } else { 7340dca0f7bSHal Rosenstock /* unicast GID -- should be ARP or RARP reply */ 7351da177e4SLinus Torvalds 7360dca0f7bSHal Rosenstock if ((be16_to_cpup((__be16 *) skb->data) != ETH_P_ARP) && 7370dca0f7bSHal Rosenstock (be16_to_cpup((__be16 *) skb->data) != ETH_P_RARP)) { 7381da177e4SLinus Torvalds ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x " 7391da177e4SLinus Torvalds IPOIB_GID_FMT "\n", 7401da177e4SLinus Torvalds skb->dst ? "neigh" : "dst", 74197f52eb4SSean Hefty be16_to_cpup((__be16 *) skb->data), 742073ae841SMichael S. Tsirkin IPOIB_QPN(phdr->hwaddr), 74337c22a77SJack Morgenstein IPOIB_GID_RAW_ARG(phdr->hwaddr + 4)); 7441da177e4SLinus Torvalds dev_kfree_skb_any(skb); 745de903512SRoland Dreier ++dev->stats.tx_dropped; 7461da177e4SLinus Torvalds goto out; 7471da177e4SLinus Torvalds } 7481da177e4SLinus Torvalds 7491da177e4SLinus Torvalds unicast_arp_send(skb, dev, phdr); 7501da177e4SLinus Torvalds } 7511da177e4SLinus Torvalds } 7521da177e4SLinus Torvalds 7531da177e4SLinus Torvalds out: 7541da177e4SLinus Torvalds spin_unlock_irqrestore(&priv->tx_lock, flags); 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds return NETDEV_TX_OK; 7571da177e4SLinus Torvalds } 7581da177e4SLinus Torvalds 7591da177e4SLinus Torvalds static void ipoib_timeout(struct net_device *dev) 7601da177e4SLinus Torvalds { 7611da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 7621da177e4SLinus Torvalds 7634b2d319bSRoland Dreier ipoib_warn(priv, "transmit timeout: latency %d msecs\n", 7644b2d319bSRoland Dreier jiffies_to_msecs(jiffies - dev->trans_start)); 7654b2d319bSRoland Dreier ipoib_warn(priv, "queue stopped %d, tx_head %u, tx_tail %u\n", 7664b2d319bSRoland Dreier netif_queue_stopped(dev), 7674b2d319bSRoland Dreier priv->tx_head, priv->tx_tail); 7681da177e4SLinus Torvalds /* XXX reset QP, etc. */ 7691da177e4SLinus Torvalds } 7701da177e4SLinus Torvalds 7711da177e4SLinus Torvalds static int ipoib_hard_header(struct sk_buff *skb, 7721da177e4SLinus Torvalds struct net_device *dev, 7731da177e4SLinus Torvalds unsigned short type, 7743b04dddeSStephen Hemminger const void *daddr, const void *saddr, unsigned len) 7751da177e4SLinus Torvalds { 7761da177e4SLinus Torvalds struct ipoib_header *header; 7771da177e4SLinus Torvalds 7781da177e4SLinus Torvalds header = (struct ipoib_header *) skb_push(skb, sizeof *header); 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds header->proto = htons(type); 7811da177e4SLinus Torvalds header->reserved = 0; 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds /* 7841da177e4SLinus Torvalds * If we don't have a neighbour structure, stuff the 7851da177e4SLinus Torvalds * destination address onto the front of the skb so we can 7861da177e4SLinus Torvalds * figure out where to send the packet later. 7871da177e4SLinus Torvalds */ 788ef12d456SRoland Dreier if ((!skb->dst || !skb->dst->neighbour) && daddr) { 7891da177e4SLinus Torvalds struct ipoib_pseudoheader *phdr = 7901da177e4SLinus Torvalds (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr); 7911da177e4SLinus Torvalds memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); 7921da177e4SLinus Torvalds } 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds return 0; 7951da177e4SLinus Torvalds } 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds static void ipoib_set_mcast_list(struct net_device *dev) 7981da177e4SLinus Torvalds { 7991da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 8001da177e4SLinus Torvalds 8017a343d4cSLeonid Arsh if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) { 8027a343d4cSLeonid Arsh ipoib_dbg(priv, "IPOIB_FLAG_OPER_UP not set"); 8037a343d4cSLeonid Arsh return; 8047a343d4cSLeonid Arsh } 8057a343d4cSLeonid Arsh 8061ad62a19SMichael S. Tsirkin queue_work(ipoib_workqueue, &priv->restart_task); 8071da177e4SLinus Torvalds } 8081da177e4SLinus Torvalds 809ecbb4169SAlexey Kuznetsov static void ipoib_neigh_cleanup(struct neighbour *n) 8101da177e4SLinus Torvalds { 8111da177e4SLinus Torvalds struct ipoib_neigh *neigh; 8121da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(n->dev); 8131da177e4SLinus Torvalds unsigned long flags; 8141da177e4SLinus Torvalds struct ipoib_ah *ah = NULL; 8151da177e4SLinus Torvalds 816732a2170SMoni Shoua neigh = *to_ipoib_neigh(n); 8177bc531ddSOr Gerlitz if (neigh) 818732a2170SMoni Shoua priv = netdev_priv(neigh->dev); 8197bc531ddSOr Gerlitz else 820732a2170SMoni Shoua return; 8211da177e4SLinus Torvalds ipoib_dbg(priv, 822ecbb4169SAlexey Kuznetsov "neigh_cleanup for %06x " IPOIB_GID_FMT "\n", 823073ae841SMichael S. Tsirkin IPOIB_QPN(n->ha), 82437c22a77SJack Morgenstein IPOIB_GID_RAW_ARG(n->ha + 4)); 8251da177e4SLinus Torvalds 8261da177e4SLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds if (neigh->ah) 8291da177e4SLinus Torvalds ah = neigh->ah; 8301da177e4SLinus Torvalds list_del(&neigh->list); 8312745b5b7SMichael S. Tsirkin ipoib_neigh_free(n->dev, neigh); 8321da177e4SLinus Torvalds 8331da177e4SLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 8341da177e4SLinus Torvalds 8351da177e4SLinus Torvalds if (ah) 8361da177e4SLinus Torvalds ipoib_put_ah(ah); 8371da177e4SLinus Torvalds } 8381da177e4SLinus Torvalds 839732a2170SMoni Shoua struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour, 840732a2170SMoni Shoua struct net_device *dev) 841d2e0655eSMichael S. Tsirkin { 842d2e0655eSMichael S. Tsirkin struct ipoib_neigh *neigh; 843d2e0655eSMichael S. Tsirkin 844d2e0655eSMichael S. Tsirkin neigh = kmalloc(sizeof *neigh, GFP_ATOMIC); 845d2e0655eSMichael S. Tsirkin if (!neigh) 846d2e0655eSMichael S. Tsirkin return NULL; 847d2e0655eSMichael S. Tsirkin 848d2e0655eSMichael S. Tsirkin neigh->neighbour = neighbour; 849732a2170SMoni Shoua neigh->dev = dev; 850d2e0655eSMichael S. Tsirkin *to_ipoib_neigh(neighbour) = neigh; 85182b39913SRoland Dreier skb_queue_head_init(&neigh->queue); 852839fcabaSMichael S. Tsirkin ipoib_cm_set(neigh, NULL); 853d2e0655eSMichael S. Tsirkin 854d2e0655eSMichael S. Tsirkin return neigh; 855d2e0655eSMichael S. Tsirkin } 856d2e0655eSMichael S. Tsirkin 8572745b5b7SMichael S. Tsirkin void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh) 858d2e0655eSMichael S. Tsirkin { 8592745b5b7SMichael S. Tsirkin struct sk_buff *skb; 860d2e0655eSMichael S. Tsirkin *to_ipoib_neigh(neigh->neighbour) = NULL; 8612745b5b7SMichael S. Tsirkin while ((skb = __skb_dequeue(&neigh->queue))) { 862de903512SRoland Dreier ++dev->stats.tx_dropped; 8632745b5b7SMichael S. Tsirkin dev_kfree_skb_any(skb); 8642745b5b7SMichael S. Tsirkin } 865839fcabaSMichael S. Tsirkin if (ipoib_cm_get(neigh)) 866839fcabaSMichael S. Tsirkin ipoib_cm_destroy_tx(ipoib_cm_get(neigh)); 867d2e0655eSMichael S. Tsirkin kfree(neigh); 868d2e0655eSMichael S. Tsirkin } 869d2e0655eSMichael S. Tsirkin 8701da177e4SLinus Torvalds static int ipoib_neigh_setup_dev(struct net_device *dev, struct neigh_parms *parms) 8711da177e4SLinus Torvalds { 872ecbb4169SAlexey Kuznetsov parms->neigh_cleanup = ipoib_neigh_cleanup; 8731da177e4SLinus Torvalds 8741da177e4SLinus Torvalds return 0; 8751da177e4SLinus Torvalds } 8761da177e4SLinus Torvalds 8771da177e4SLinus Torvalds int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) 8781da177e4SLinus Torvalds { 8791da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 8801da177e4SLinus Torvalds 8811da177e4SLinus Torvalds /* Allocate RX/TX "rings" to hold queued skbs */ 8820f485251SShirley Ma priv->rx_ring = kzalloc(ipoib_recvq_size * sizeof *priv->rx_ring, 8831da177e4SLinus Torvalds GFP_KERNEL); 8841da177e4SLinus Torvalds if (!priv->rx_ring) { 8851da177e4SLinus Torvalds printk(KERN_WARNING "%s: failed to allocate RX ring (%d entries)\n", 8860f485251SShirley Ma ca->name, ipoib_recvq_size); 8871da177e4SLinus Torvalds goto out; 8881da177e4SLinus Torvalds } 8891da177e4SLinus Torvalds 89010313cbbSRoland Dreier priv->tx_ring = vmalloc(ipoib_sendq_size * sizeof *priv->tx_ring); 8911da177e4SLinus Torvalds if (!priv->tx_ring) { 8921da177e4SLinus Torvalds printk(KERN_WARNING "%s: failed to allocate TX ring (%d entries)\n", 8930f485251SShirley Ma ca->name, ipoib_sendq_size); 8941da177e4SLinus Torvalds goto out_rx_ring_cleanup; 8951da177e4SLinus Torvalds } 89610313cbbSRoland Dreier memset(priv->tx_ring, 0, ipoib_sendq_size * sizeof *priv->tx_ring); 8971da177e4SLinus Torvalds 8981b524963SMichael S. Tsirkin /* priv->tx_head, tx_tail & tx_outstanding are already 0 */ 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds if (ipoib_ib_dev_init(dev, ca, port)) 9011da177e4SLinus Torvalds goto out_tx_ring_cleanup; 9021da177e4SLinus Torvalds 9031da177e4SLinus Torvalds return 0; 9041da177e4SLinus Torvalds 9051da177e4SLinus Torvalds out_tx_ring_cleanup: 90610313cbbSRoland Dreier vfree(priv->tx_ring); 9071da177e4SLinus Torvalds 9081da177e4SLinus Torvalds out_rx_ring_cleanup: 9091da177e4SLinus Torvalds kfree(priv->rx_ring); 9101da177e4SLinus Torvalds 9111da177e4SLinus Torvalds out: 9121da177e4SLinus Torvalds return -ENOMEM; 9131da177e4SLinus Torvalds } 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds void ipoib_dev_cleanup(struct net_device *dev) 9161da177e4SLinus Torvalds { 9171da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev), *cpriv, *tcpriv; 9181da177e4SLinus Torvalds 9191732b0efSRoland Dreier ipoib_delete_debug_files(dev); 9201da177e4SLinus Torvalds 9211da177e4SLinus Torvalds /* Delete any child interfaces first */ 9221da177e4SLinus Torvalds list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) { 9231da177e4SLinus Torvalds unregister_netdev(cpriv->dev); 9241da177e4SLinus Torvalds ipoib_dev_cleanup(cpriv->dev); 9251da177e4SLinus Torvalds free_netdev(cpriv->dev); 9261da177e4SLinus Torvalds } 9271da177e4SLinus Torvalds 9281da177e4SLinus Torvalds ipoib_ib_dev_cleanup(dev); 9291da177e4SLinus Torvalds 9301da177e4SLinus Torvalds kfree(priv->rx_ring); 93110313cbbSRoland Dreier vfree(priv->tx_ring); 93292a6b34bSHal Rosenstock 93392a6b34bSHal Rosenstock priv->rx_ring = NULL; 9341da177e4SLinus Torvalds priv->tx_ring = NULL; 9351da177e4SLinus Torvalds } 9361da177e4SLinus Torvalds 9373b04dddeSStephen Hemminger static const struct header_ops ipoib_header_ops = { 9383b04dddeSStephen Hemminger .create = ipoib_hard_header, 9393b04dddeSStephen Hemminger }; 9403b04dddeSStephen Hemminger 9411da177e4SLinus Torvalds static void ipoib_setup(struct net_device *dev) 9421da177e4SLinus Torvalds { 9431da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 9441da177e4SLinus Torvalds 9451da177e4SLinus Torvalds dev->open = ipoib_open; 9461da177e4SLinus Torvalds dev->stop = ipoib_stop; 9471da177e4SLinus Torvalds dev->change_mtu = ipoib_change_mtu; 9481da177e4SLinus Torvalds dev->hard_start_xmit = ipoib_start_xmit; 9491da177e4SLinus Torvalds dev->tx_timeout = ipoib_timeout; 9503b04dddeSStephen Hemminger dev->header_ops = &ipoib_header_ops; 9511da177e4SLinus Torvalds dev->set_multicast_list = ipoib_set_mcast_list; 9521da177e4SLinus Torvalds dev->neigh_setup = ipoib_neigh_setup_dev; 953bea3348eSStephen Hemminger 95482c24c18SEli Cohen ipoib_set_ethtool_ops(dev); 95582c24c18SEli Cohen 956bea3348eSStephen Hemminger netif_napi_add(dev, &priv->napi, ipoib_poll, 100); 9571da177e4SLinus Torvalds 9581da177e4SLinus Torvalds dev->watchdog_timeo = HZ; 9591da177e4SLinus Torvalds 9601da177e4SLinus Torvalds dev->flags |= IFF_BROADCAST | IFF_MULTICAST; 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds /* 9631da177e4SLinus Torvalds * We add in INFINIBAND_ALEN to allow for the destination 9641da177e4SLinus Torvalds * address "pseudoheader" for skbs without neighbour struct. 9651da177e4SLinus Torvalds */ 9661da177e4SLinus Torvalds dev->hard_header_len = IPOIB_ENCAP_LEN + INFINIBAND_ALEN; 9671da177e4SLinus Torvalds dev->addr_len = INFINIBAND_ALEN; 9681da177e4SLinus Torvalds dev->type = ARPHRD_INFINIBAND; 9690f485251SShirley Ma dev->tx_queue_len = ipoib_sendq_size * 2; 970eb14032fSEli Cohen dev->features = (NETIF_F_VLAN_CHALLENGED | 971eb14032fSEli Cohen NETIF_F_LLTX | 972eb14032fSEli Cohen NETIF_F_HIGHDMA); 9731da177e4SLinus Torvalds 9741da177e4SLinus Torvalds memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN); 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds netif_carrier_off(dev); 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds priv->dev = dev; 9791da177e4SLinus Torvalds 9801da177e4SLinus Torvalds spin_lock_init(&priv->lock); 9811da177e4SLinus Torvalds spin_lock_init(&priv->tx_lock); 9821da177e4SLinus Torvalds 98395ed644fSIngo Molnar mutex_init(&priv->mcast_mutex); 98495ed644fSIngo Molnar mutex_init(&priv->vlan_mutex); 9851da177e4SLinus Torvalds 9861da177e4SLinus Torvalds INIT_LIST_HEAD(&priv->path_list); 9871da177e4SLinus Torvalds INIT_LIST_HEAD(&priv->child_intfs); 9881da177e4SLinus Torvalds INIT_LIST_HEAD(&priv->dead_ahs); 9891da177e4SLinus Torvalds INIT_LIST_HEAD(&priv->multicast_list); 9901da177e4SLinus Torvalds 99126bbf13cSYosef Etigin INIT_DELAYED_WORK(&priv->pkey_poll_task, ipoib_pkey_poll); 99226bbf13cSYosef Etigin INIT_WORK(&priv->pkey_event_task, ipoib_pkey_event); 993c4028958SDavid Howells INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task); 994c4028958SDavid Howells INIT_WORK(&priv->flush_task, ipoib_ib_dev_flush); 995c4028958SDavid Howells INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task); 996c4028958SDavid Howells INIT_DELAYED_WORK(&priv->ah_reap_task, ipoib_reap_ah); 9971da177e4SLinus Torvalds } 9981da177e4SLinus Torvalds 9991da177e4SLinus Torvalds struct ipoib_dev_priv *ipoib_intf_alloc(const char *name) 10001da177e4SLinus Torvalds { 10011da177e4SLinus Torvalds struct net_device *dev; 10021da177e4SLinus Torvalds 10031da177e4SLinus Torvalds dev = alloc_netdev((int) sizeof (struct ipoib_dev_priv), name, 10041da177e4SLinus Torvalds ipoib_setup); 10051da177e4SLinus Torvalds if (!dev) 10061da177e4SLinus Torvalds return NULL; 10071da177e4SLinus Torvalds 10081da177e4SLinus Torvalds return netdev_priv(dev); 10091da177e4SLinus Torvalds } 10101da177e4SLinus Torvalds 101143cb76d9SGreg Kroah-Hartman static ssize_t show_pkey(struct device *dev, 101243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 10131da177e4SLinus Torvalds { 101443cb76d9SGreg Kroah-Hartman struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds return sprintf(buf, "0x%04x\n", priv->pkey); 10171da177e4SLinus Torvalds } 101843cb76d9SGreg Kroah-Hartman static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); 10191da177e4SLinus Torvalds 1020335a64a5SOr Gerlitz static ssize_t show_umcast(struct device *dev, 1021335a64a5SOr Gerlitz struct device_attribute *attr, char *buf) 1022335a64a5SOr Gerlitz { 1023335a64a5SOr Gerlitz struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); 1024335a64a5SOr Gerlitz 1025335a64a5SOr Gerlitz return sprintf(buf, "%d\n", test_bit(IPOIB_FLAG_UMCAST, &priv->flags)); 1026335a64a5SOr Gerlitz } 1027335a64a5SOr Gerlitz 1028335a64a5SOr Gerlitz static ssize_t set_umcast(struct device *dev, 1029335a64a5SOr Gerlitz struct device_attribute *attr, 1030335a64a5SOr Gerlitz const char *buf, size_t count) 1031335a64a5SOr Gerlitz { 1032335a64a5SOr Gerlitz struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); 1033335a64a5SOr Gerlitz unsigned long umcast_val = simple_strtoul(buf, NULL, 0); 1034335a64a5SOr Gerlitz 1035335a64a5SOr Gerlitz if (umcast_val > 0) { 1036335a64a5SOr Gerlitz set_bit(IPOIB_FLAG_UMCAST, &priv->flags); 1037335a64a5SOr Gerlitz ipoib_warn(priv, "ignoring multicast groups joined directly " 1038335a64a5SOr Gerlitz "by userspace\n"); 1039335a64a5SOr Gerlitz } else 1040335a64a5SOr Gerlitz clear_bit(IPOIB_FLAG_UMCAST, &priv->flags); 1041335a64a5SOr Gerlitz 1042335a64a5SOr Gerlitz return count; 1043335a64a5SOr Gerlitz } 1044335a64a5SOr Gerlitz static DEVICE_ATTR(umcast, S_IWUSR | S_IRUGO, show_umcast, set_umcast); 1045335a64a5SOr Gerlitz 1046335a64a5SOr Gerlitz int ipoib_add_umcast_attr(struct net_device *dev) 1047335a64a5SOr Gerlitz { 1048335a64a5SOr Gerlitz return device_create_file(&dev->dev, &dev_attr_umcast); 1049335a64a5SOr Gerlitz } 1050335a64a5SOr Gerlitz 105143cb76d9SGreg Kroah-Hartman static ssize_t create_child(struct device *dev, 105243cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 10531da177e4SLinus Torvalds const char *buf, size_t count) 10541da177e4SLinus Torvalds { 10551da177e4SLinus Torvalds int pkey; 10561da177e4SLinus Torvalds int ret; 10571da177e4SLinus Torvalds 10581da177e4SLinus Torvalds if (sscanf(buf, "%i", &pkey) != 1) 10591da177e4SLinus Torvalds return -EINVAL; 10601da177e4SLinus Torvalds 10611da177e4SLinus Torvalds if (pkey < 0 || pkey > 0xffff) 10621da177e4SLinus Torvalds return -EINVAL; 10631da177e4SLinus Torvalds 10644ce05937SRoland Dreier /* 10654ce05937SRoland Dreier * Set the full membership bit, so that we join the right 10664ce05937SRoland Dreier * broadcast group, etc. 10674ce05937SRoland Dreier */ 10684ce05937SRoland Dreier pkey |= 0x8000; 10694ce05937SRoland Dreier 107043cb76d9SGreg Kroah-Hartman ret = ipoib_vlan_add(to_net_dev(dev), pkey); 10711da177e4SLinus Torvalds 10721da177e4SLinus Torvalds return ret ? ret : count; 10731da177e4SLinus Torvalds } 107443cb76d9SGreg Kroah-Hartman static DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child); 10751da177e4SLinus Torvalds 107643cb76d9SGreg Kroah-Hartman static ssize_t delete_child(struct device *dev, 107743cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 10781da177e4SLinus Torvalds const char *buf, size_t count) 10791da177e4SLinus Torvalds { 10801da177e4SLinus Torvalds int pkey; 10811da177e4SLinus Torvalds int ret; 10821da177e4SLinus Torvalds 10831da177e4SLinus Torvalds if (sscanf(buf, "%i", &pkey) != 1) 10841da177e4SLinus Torvalds return -EINVAL; 10851da177e4SLinus Torvalds 10861da177e4SLinus Torvalds if (pkey < 0 || pkey > 0xffff) 10871da177e4SLinus Torvalds return -EINVAL; 10881da177e4SLinus Torvalds 108943cb76d9SGreg Kroah-Hartman ret = ipoib_vlan_delete(to_net_dev(dev), pkey); 10901da177e4SLinus Torvalds 10911da177e4SLinus Torvalds return ret ? ret : count; 10921da177e4SLinus Torvalds 10931da177e4SLinus Torvalds } 109443cb76d9SGreg Kroah-Hartman static DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child); 10951da177e4SLinus Torvalds 10961da177e4SLinus Torvalds int ipoib_add_pkey_attr(struct net_device *dev) 10971da177e4SLinus Torvalds { 109843cb76d9SGreg Kroah-Hartman return device_create_file(&dev->dev, &dev_attr_pkey); 10991da177e4SLinus Torvalds } 11001da177e4SLinus Torvalds 11011da177e4SLinus Torvalds static struct net_device *ipoib_add_port(const char *format, 11021da177e4SLinus Torvalds struct ib_device *hca, u8 port) 11031da177e4SLinus Torvalds { 11041da177e4SLinus Torvalds struct ipoib_dev_priv *priv; 11056046136cSEli Cohen struct ib_device_attr *device_attr; 1106bc7b3a36SShirley Ma struct ib_port_attr attr; 11071da177e4SLinus Torvalds int result = -ENOMEM; 11081da177e4SLinus Torvalds 11091da177e4SLinus Torvalds priv = ipoib_intf_alloc(format); 11101da177e4SLinus Torvalds if (!priv) 11111da177e4SLinus Torvalds goto alloc_mem_failed; 11121da177e4SLinus Torvalds 11131da177e4SLinus Torvalds SET_NETDEV_DEV(priv->dev, hca->dma_device); 11141da177e4SLinus Torvalds 1115bc7b3a36SShirley Ma if (!ib_query_port(hca, port, &attr)) 1116bc7b3a36SShirley Ma priv->max_ib_mtu = ib_mtu_enum_to_int(attr.max_mtu); 1117bc7b3a36SShirley Ma else { 1118bc7b3a36SShirley Ma printk(KERN_WARNING "%s: ib_query_port %d failed\n", 1119bc7b3a36SShirley Ma hca->name, port); 1120bc7b3a36SShirley Ma goto device_init_failed; 1121bc7b3a36SShirley Ma } 1122bc7b3a36SShirley Ma 1123bc7b3a36SShirley Ma /* MTU will be reset when mcast join happens */ 1124bc7b3a36SShirley Ma priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu); 1125bc7b3a36SShirley Ma priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu; 1126bc7b3a36SShirley Ma 11271da177e4SLinus Torvalds result = ib_query_pkey(hca, port, 0, &priv->pkey); 11281da177e4SLinus Torvalds if (result) { 11291da177e4SLinus Torvalds printk(KERN_WARNING "%s: ib_query_pkey port %d failed (ret = %d)\n", 11301da177e4SLinus Torvalds hca->name, port, result); 1131ca6de177SEli Cohen goto device_init_failed; 11321da177e4SLinus Torvalds } 11331da177e4SLinus Torvalds 11346046136cSEli Cohen device_attr = kmalloc(sizeof *device_attr, GFP_KERNEL); 11356046136cSEli Cohen if (!device_attr) { 11366046136cSEli Cohen printk(KERN_WARNING "%s: allocation of %zu bytes failed\n", 11376046136cSEli Cohen hca->name, sizeof *device_attr); 11386046136cSEli Cohen goto device_init_failed; 11396046136cSEli Cohen } 11406046136cSEli Cohen 11416046136cSEli Cohen result = ib_query_device(hca, device_attr); 11426046136cSEli Cohen if (result) { 11436046136cSEli Cohen printk(KERN_WARNING "%s: ib_query_device failed (ret = %d)\n", 11446046136cSEli Cohen hca->name, result); 11456046136cSEli Cohen kfree(device_attr); 11466046136cSEli Cohen goto device_init_failed; 11476046136cSEli Cohen } 114840ca1988SEli Cohen priv->hca_caps = device_attr->device_cap_flags; 11496046136cSEli Cohen 115040ca1988SEli Cohen kfree(device_attr); 115140ca1988SEli Cohen 115240ca1988SEli Cohen if (priv->hca_caps & IB_DEVICE_UD_IP_CSUM) { 11536046136cSEli Cohen set_bit(IPOIB_FLAG_CSUM, &priv->flags); 11546046136cSEli Cohen priv->dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; 11556046136cSEli Cohen } 11566046136cSEli Cohen 11574ce05937SRoland Dreier /* 11584ce05937SRoland Dreier * Set the full membership bit, so that we join the right 11594ce05937SRoland Dreier * broadcast group, etc. 11604ce05937SRoland Dreier */ 11614ce05937SRoland Dreier priv->pkey |= 0x8000; 11624ce05937SRoland Dreier 11631da177e4SLinus Torvalds priv->dev->broadcast[8] = priv->pkey >> 8; 11641da177e4SLinus Torvalds priv->dev->broadcast[9] = priv->pkey & 0xff; 11651da177e4SLinus Torvalds 11661da177e4SLinus Torvalds result = ib_query_gid(hca, port, 0, &priv->local_gid); 11671da177e4SLinus Torvalds if (result) { 11681da177e4SLinus Torvalds printk(KERN_WARNING "%s: ib_query_gid port %d failed (ret = %d)\n", 11691da177e4SLinus Torvalds hca->name, port, result); 1170ca6de177SEli Cohen goto device_init_failed; 11711da177e4SLinus Torvalds } else 11721da177e4SLinus Torvalds memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid)); 11731da177e4SLinus Torvalds 11741da177e4SLinus Torvalds result = ipoib_dev_init(priv->dev, hca, port); 11751da177e4SLinus Torvalds if (result < 0) { 11761da177e4SLinus Torvalds printk(KERN_WARNING "%s: failed to initialize port %d (ret = %d)\n", 11771da177e4SLinus Torvalds hca->name, port, result); 11781da177e4SLinus Torvalds goto device_init_failed; 11791da177e4SLinus Torvalds } 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds INIT_IB_EVENT_HANDLER(&priv->event_handler, 11821da177e4SLinus Torvalds priv->ca, ipoib_event); 11831da177e4SLinus Torvalds result = ib_register_event_handler(&priv->event_handler); 11841da177e4SLinus Torvalds if (result < 0) { 11851da177e4SLinus Torvalds printk(KERN_WARNING "%s: ib_register_event_handler failed for " 11861da177e4SLinus Torvalds "port %d (ret = %d)\n", 11871da177e4SLinus Torvalds hca->name, port, result); 11881da177e4SLinus Torvalds goto event_failed; 11891da177e4SLinus Torvalds } 11901da177e4SLinus Torvalds 119140ca1988SEli Cohen if (priv->dev->features & NETIF_F_SG && priv->hca_caps & IB_DEVICE_UD_TSO) 119240ca1988SEli Cohen priv->dev->features |= NETIF_F_TSO; 119340ca1988SEli Cohen 11941da177e4SLinus Torvalds result = register_netdev(priv->dev); 11951da177e4SLinus Torvalds if (result) { 11961da177e4SLinus Torvalds printk(KERN_WARNING "%s: couldn't register ipoib port %d; error %d\n", 11971da177e4SLinus Torvalds hca->name, port, result); 11981da177e4SLinus Torvalds goto register_failed; 11991da177e4SLinus Torvalds } 12001da177e4SLinus Torvalds 12011732b0efSRoland Dreier ipoib_create_debug_files(priv->dev); 12021da177e4SLinus Torvalds 1203839fcabaSMichael S. Tsirkin if (ipoib_cm_add_mode_attr(priv->dev)) 1204839fcabaSMichael S. Tsirkin goto sysfs_failed; 12051da177e4SLinus Torvalds if (ipoib_add_pkey_attr(priv->dev)) 12061da177e4SLinus Torvalds goto sysfs_failed; 1207335a64a5SOr Gerlitz if (ipoib_add_umcast_attr(priv->dev)) 1208335a64a5SOr Gerlitz goto sysfs_failed; 120943cb76d9SGreg Kroah-Hartman if (device_create_file(&priv->dev->dev, &dev_attr_create_child)) 12101da177e4SLinus Torvalds goto sysfs_failed; 121143cb76d9SGreg Kroah-Hartman if (device_create_file(&priv->dev->dev, &dev_attr_delete_child)) 12121da177e4SLinus Torvalds goto sysfs_failed; 12131da177e4SLinus Torvalds 12141da177e4SLinus Torvalds return priv->dev; 12151da177e4SLinus Torvalds 12161da177e4SLinus Torvalds sysfs_failed: 12171732b0efSRoland Dreier ipoib_delete_debug_files(priv->dev); 12181da177e4SLinus Torvalds unregister_netdev(priv->dev); 12191da177e4SLinus Torvalds 12201da177e4SLinus Torvalds register_failed: 12211da177e4SLinus Torvalds ib_unregister_event_handler(&priv->event_handler); 122251574e03SMichael S. Tsirkin flush_scheduled_work(); 12231da177e4SLinus Torvalds 12241da177e4SLinus Torvalds event_failed: 12251da177e4SLinus Torvalds ipoib_dev_cleanup(priv->dev); 12261da177e4SLinus Torvalds 12271da177e4SLinus Torvalds device_init_failed: 12281da177e4SLinus Torvalds free_netdev(priv->dev); 12291da177e4SLinus Torvalds 12301da177e4SLinus Torvalds alloc_mem_failed: 12311da177e4SLinus Torvalds return ERR_PTR(result); 12321da177e4SLinus Torvalds } 12331da177e4SLinus Torvalds 12341da177e4SLinus Torvalds static void ipoib_add_one(struct ib_device *device) 12351da177e4SLinus Torvalds { 12361da177e4SLinus Torvalds struct list_head *dev_list; 12371da177e4SLinus Torvalds struct net_device *dev; 12381da177e4SLinus Torvalds struct ipoib_dev_priv *priv; 12391da177e4SLinus Torvalds int s, e, p; 12401da177e4SLinus Torvalds 124107ebafbaSTom Tucker if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) 124207ebafbaSTom Tucker return; 124307ebafbaSTom Tucker 12441da177e4SLinus Torvalds dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL); 12451da177e4SLinus Torvalds if (!dev_list) 12461da177e4SLinus Torvalds return; 12471da177e4SLinus Torvalds 12481da177e4SLinus Torvalds INIT_LIST_HEAD(dev_list); 12491da177e4SLinus Torvalds 125007ebafbaSTom Tucker if (device->node_type == RDMA_NODE_IB_SWITCH) { 12511da177e4SLinus Torvalds s = 0; 12521da177e4SLinus Torvalds e = 0; 12531da177e4SLinus Torvalds } else { 12541da177e4SLinus Torvalds s = 1; 12551da177e4SLinus Torvalds e = device->phys_port_cnt; 12561da177e4SLinus Torvalds } 12571da177e4SLinus Torvalds 12581da177e4SLinus Torvalds for (p = s; p <= e; ++p) { 12591da177e4SLinus Torvalds dev = ipoib_add_port("ib%d", device, p); 12601da177e4SLinus Torvalds if (!IS_ERR(dev)) { 12611da177e4SLinus Torvalds priv = netdev_priv(dev); 12621da177e4SLinus Torvalds list_add_tail(&priv->list, dev_list); 12631da177e4SLinus Torvalds } 12641da177e4SLinus Torvalds } 12651da177e4SLinus Torvalds 12661da177e4SLinus Torvalds ib_set_client_data(device, &ipoib_client, dev_list); 12671da177e4SLinus Torvalds } 12681da177e4SLinus Torvalds 12691da177e4SLinus Torvalds static void ipoib_remove_one(struct ib_device *device) 12701da177e4SLinus Torvalds { 12711da177e4SLinus Torvalds struct ipoib_dev_priv *priv, *tmp; 12721da177e4SLinus Torvalds struct list_head *dev_list; 12731da177e4SLinus Torvalds 127407ebafbaSTom Tucker if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) 127507ebafbaSTom Tucker return; 127607ebafbaSTom Tucker 12771da177e4SLinus Torvalds dev_list = ib_get_client_data(device, &ipoib_client); 12781da177e4SLinus Torvalds 12791da177e4SLinus Torvalds list_for_each_entry_safe(priv, tmp, dev_list, list) { 12801da177e4SLinus Torvalds ib_unregister_event_handler(&priv->event_handler); 128151574e03SMichael S. Tsirkin flush_scheduled_work(); 12821da177e4SLinus Torvalds 12831da177e4SLinus Torvalds unregister_netdev(priv->dev); 12841da177e4SLinus Torvalds ipoib_dev_cleanup(priv->dev); 12851da177e4SLinus Torvalds free_netdev(priv->dev); 12861da177e4SLinus Torvalds } 128706c56e44SMichael S. Tsirkin 128806c56e44SMichael S. Tsirkin kfree(dev_list); 12891da177e4SLinus Torvalds } 12901da177e4SLinus Torvalds 12911da177e4SLinus Torvalds static int __init ipoib_init_module(void) 12921da177e4SLinus Torvalds { 12931da177e4SLinus Torvalds int ret; 12941da177e4SLinus Torvalds 12950f485251SShirley Ma ipoib_recvq_size = roundup_pow_of_two(ipoib_recvq_size); 12960f485251SShirley Ma ipoib_recvq_size = min(ipoib_recvq_size, IPOIB_MAX_QUEUE_SIZE); 12970f485251SShirley Ma ipoib_recvq_size = max(ipoib_recvq_size, IPOIB_MIN_QUEUE_SIZE); 12980f485251SShirley Ma 12990f485251SShirley Ma ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size); 13000f485251SShirley Ma ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE); 1301f56bcd80SEli Cohen ipoib_sendq_size = max(ipoib_sendq_size, max(2 * MAX_SEND_CQE, 1302f56bcd80SEli Cohen IPOIB_MIN_QUEUE_SIZE)); 130368e995a2SPradeep Satyanarayana #ifdef CONFIG_INFINIBAND_IPOIB_CM 130468e995a2SPradeep Satyanarayana ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP); 130568e995a2SPradeep Satyanarayana #endif 13060f485251SShirley Ma 13071da177e4SLinus Torvalds ret = ipoib_register_debugfs(); 13081da177e4SLinus Torvalds if (ret) 13091da177e4SLinus Torvalds return ret; 13101da177e4SLinus Torvalds 13111da177e4SLinus Torvalds /* 13121da177e4SLinus Torvalds * We create our own workqueue mainly because we want to be 13131da177e4SLinus Torvalds * able to flush it when devices are being removed. We can't 13141da177e4SLinus Torvalds * use schedule_work()/flush_scheduled_work() because both 13151da177e4SLinus Torvalds * unregister_netdev() and linkwatch_event take the rtnl lock, 13161da177e4SLinus Torvalds * so flush_scheduled_work() can deadlock during device 13171da177e4SLinus Torvalds * removal. 13181da177e4SLinus Torvalds */ 13191da177e4SLinus Torvalds ipoib_workqueue = create_singlethread_workqueue("ipoib"); 13201da177e4SLinus Torvalds if (!ipoib_workqueue) { 13211da177e4SLinus Torvalds ret = -ENOMEM; 13221da177e4SLinus Torvalds goto err_fs; 13231da177e4SLinus Torvalds } 13241da177e4SLinus Torvalds 1325c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&ipoib_sa_client); 1326c1a0b23bSMichael S. Tsirkin 13271da177e4SLinus Torvalds ret = ib_register_client(&ipoib_client); 13281da177e4SLinus Torvalds if (ret) 1329c1a0b23bSMichael S. Tsirkin goto err_sa; 13301da177e4SLinus Torvalds 13311da177e4SLinus Torvalds return 0; 13321da177e4SLinus Torvalds 1333c1a0b23bSMichael S. Tsirkin err_sa: 1334c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&ipoib_sa_client); 13351da177e4SLinus Torvalds destroy_workqueue(ipoib_workqueue); 13361da177e4SLinus Torvalds 13379adec1a8SRoland Dreier err_fs: 13389adec1a8SRoland Dreier ipoib_unregister_debugfs(); 13399adec1a8SRoland Dreier 13401da177e4SLinus Torvalds return ret; 13411da177e4SLinus Torvalds } 13421da177e4SLinus Torvalds 13431da177e4SLinus Torvalds static void __exit ipoib_cleanup_module(void) 13441da177e4SLinus Torvalds { 13451da177e4SLinus Torvalds ib_unregister_client(&ipoib_client); 1346c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&ipoib_sa_client); 13479adec1a8SRoland Dreier ipoib_unregister_debugfs(); 13481da177e4SLinus Torvalds destroy_workqueue(ipoib_workqueue); 13491da177e4SLinus Torvalds } 13501da177e4SLinus Torvalds 13511da177e4SLinus Torvalds module_init(ipoib_init_module); 13521da177e4SLinus Torvalds module_exit(ipoib_cleanup_module); 1353