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 351da177e4SLinus Torvalds #include "ipoib.h" 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds #include <linux/module.h> 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds #include <linux/init.h> 401da177e4SLinus Torvalds #include <linux/slab.h> 410f485251SShirley Ma #include <linux/kernel.h> 4210313cbbSRoland Dreier #include <linux/vmalloc.h> 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds #include <linux/if_arp.h> /* For ARPHRD_xxx */ 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds #include <linux/ip.h> 471da177e4SLinus Torvalds #include <linux/in.h> 481da177e4SLinus Torvalds 49b63b70d8SShlomo Pongratz #include <linux/jhash.h> 50b63b70d8SShlomo Pongratz #include <net/arp.h> 51ddde896eSGuy Shapiro #include <net/addrconf.h> 52ddde896eSGuy Shapiro #include <linux/inetdevice.h> 53ddde896eSGuy Shapiro #include <rdma/ib_cache.h> 549c3c5f8eSEli Cohen #include <linux/pci.h> 5514c85021SArnaldo Carvalho de Melo 564b48680bSYan Burman #define DRV_VERSION "1.0.0" 574b48680bSYan Burman 584b48680bSYan Burman const char ipoib_driver_version[] = DRV_VERSION; 594b48680bSYan Burman 601da177e4SLinus Torvalds MODULE_AUTHOR("Roland Dreier"); 611da177e4SLinus Torvalds MODULE_DESCRIPTION("IP-over-InfiniBand net driver"); 621da177e4SLinus Torvalds MODULE_LICENSE("Dual BSD/GPL"); 634b48680bSYan Burman MODULE_VERSION(DRV_VERSION); 641da177e4SLinus Torvalds 650f485251SShirley Ma int ipoib_sendq_size __read_mostly = IPOIB_TX_RING_SIZE; 660f485251SShirley Ma int ipoib_recvq_size __read_mostly = IPOIB_RX_RING_SIZE; 670f485251SShirley Ma 680f485251SShirley Ma module_param_named(send_queue_size, ipoib_sendq_size, int, 0444); 690f485251SShirley Ma MODULE_PARM_DESC(send_queue_size, "Number of descriptors in send queue"); 700f485251SShirley Ma module_param_named(recv_queue_size, ipoib_recvq_size, int, 0444); 710f485251SShirley Ma MODULE_PARM_DESC(recv_queue_size, "Number of descriptors in receive queue"); 720f485251SShirley Ma 731da177e4SLinus Torvalds #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 741da177e4SLinus Torvalds int ipoib_debug_level; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds module_param_named(debug_level, ipoib_debug_level, int, 0644); 771da177e4SLinus Torvalds MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); 781da177e4SLinus Torvalds #endif 791da177e4SLinus Torvalds 801732b0efSRoland Dreier struct ipoib_path_iter { 811732b0efSRoland Dreier struct net_device *dev; 821732b0efSRoland Dreier struct ipoib_path path; 831732b0efSRoland Dreier }; 841732b0efSRoland Dreier 851da177e4SLinus Torvalds static const u8 ipv4_bcast_addr[] = { 861da177e4SLinus Torvalds 0x00, 0xff, 0xff, 0xff, 871da177e4SLinus Torvalds 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, 881da177e4SLinus Torvalds 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff 891da177e4SLinus Torvalds }; 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds struct workqueue_struct *ipoib_workqueue; 921da177e4SLinus Torvalds 93c1a0b23bSMichael S. Tsirkin struct ib_sa_client ipoib_sa_client; 94c1a0b23bSMichael S. Tsirkin 951da177e4SLinus Torvalds static void ipoib_add_one(struct ib_device *device); 967c1eb45aSHaggai Eran static void ipoib_remove_one(struct ib_device *device, void *client_data); 97b63b70d8SShlomo Pongratz static void ipoib_neigh_reclaim(struct rcu_head *rp); 98ddde896eSGuy Shapiro static struct net_device *ipoib_get_net_dev_by_params( 99ddde896eSGuy Shapiro struct ib_device *dev, u8 port, u16 pkey, 100ddde896eSGuy Shapiro const union ib_gid *gid, const struct sockaddr *addr, 101ddde896eSGuy Shapiro void *client_data); 102492a7e67SMark Bloch static int ipoib_set_mac(struct net_device *dev, void *addr); 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds static struct ib_client ipoib_client = { 1051da177e4SLinus Torvalds .name = "ipoib", 1061da177e4SLinus Torvalds .add = ipoib_add_one, 107ddde896eSGuy Shapiro .remove = ipoib_remove_one, 108ddde896eSGuy Shapiro .get_net_dev_by_params = ipoib_get_net_dev_by_params, 1091da177e4SLinus Torvalds }; 1101da177e4SLinus Torvalds 111771a5258SShamir Rabinovitch #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 112771a5258SShamir Rabinovitch static int ipoib_netdev_event(struct notifier_block *this, 113771a5258SShamir Rabinovitch unsigned long event, void *ptr) 114771a5258SShamir Rabinovitch { 115771a5258SShamir Rabinovitch struct netdev_notifier_info *ni = ptr; 116771a5258SShamir Rabinovitch struct net_device *dev = ni->dev; 117771a5258SShamir Rabinovitch 118771a5258SShamir Rabinovitch if (dev->netdev_ops->ndo_open != ipoib_open) 119771a5258SShamir Rabinovitch return NOTIFY_DONE; 120771a5258SShamir Rabinovitch 121771a5258SShamir Rabinovitch switch (event) { 122771a5258SShamir Rabinovitch case NETDEV_REGISTER: 123771a5258SShamir Rabinovitch ipoib_create_debug_files(dev); 124771a5258SShamir Rabinovitch break; 125771a5258SShamir Rabinovitch case NETDEV_CHANGENAME: 126771a5258SShamir Rabinovitch ipoib_delete_debug_files(dev); 127771a5258SShamir Rabinovitch ipoib_create_debug_files(dev); 128771a5258SShamir Rabinovitch break; 129771a5258SShamir Rabinovitch case NETDEV_UNREGISTER: 130771a5258SShamir Rabinovitch ipoib_delete_debug_files(dev); 131771a5258SShamir Rabinovitch break; 132771a5258SShamir Rabinovitch } 133771a5258SShamir Rabinovitch 134771a5258SShamir Rabinovitch return NOTIFY_DONE; 135771a5258SShamir Rabinovitch } 136771a5258SShamir Rabinovitch #endif 137771a5258SShamir Rabinovitch 1381da177e4SLinus Torvalds int ipoib_open(struct net_device *dev) 1391da177e4SLinus Torvalds { 1401da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds ipoib_dbg(priv, "bringing up interface\n"); 1431da177e4SLinus Torvalds 144437708c4SMichal Schmidt netif_carrier_off(dev); 145437708c4SMichal Schmidt 146e028cc55SYossi Etigin set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); 1471da177e4SLinus Torvalds 1483b561130SErez Shitrit priv->sm_fullmember_sendonly_support = false; 1493b561130SErez Shitrit 150efc82eeeSDoug Ledford if (ipoib_ib_dev_open(dev)) { 151db84f880SErez Shitrit if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) 1521da177e4SLinus Torvalds return 0; 153b8a1b1ceSRoland Dreier goto err_disable; 154dd57c930SAlex Estrin } 155fe25c561SYossi Etigin 1565c37077fSZhu Yanjun ipoib_ib_dev_up(dev); 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { 1591da177e4SLinus Torvalds struct ipoib_dev_priv *cpriv; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds /* Bring up any child interfaces too */ 162f47944ccSErez Shitrit down_read(&priv->vlan_rwsem); 1631da177e4SLinus Torvalds list_for_each_entry(cpriv, &priv->child_intfs, list) { 1641da177e4SLinus Torvalds int flags; 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds flags = cpriv->dev->flags; 1671da177e4SLinus Torvalds if (flags & IFF_UP) 1681da177e4SLinus Torvalds continue; 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds dev_change_flags(cpriv->dev, flags | IFF_UP); 1711da177e4SLinus Torvalds } 172f47944ccSErez Shitrit up_read(&priv->vlan_rwsem); 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds netif_start_queue(dev); 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds return 0; 178b8a1b1ceSRoland Dreier 179b8a1b1ceSRoland Dreier err_disable: 180b8a1b1ceSRoland Dreier clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); 181b8a1b1ceSRoland Dreier 182b8a1b1ceSRoland Dreier return -EINVAL; 1831da177e4SLinus Torvalds } 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds static int ipoib_stop(struct net_device *dev) 1861da177e4SLinus Torvalds { 1871da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds ipoib_dbg(priv, "stopping interface\n"); 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds netif_stop_queue(dev); 1941da177e4SLinus Torvalds 195efc82eeeSDoug Ledford ipoib_ib_dev_down(dev); 196efc82eeeSDoug Ledford ipoib_ib_dev_stop(dev); 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { 1991da177e4SLinus Torvalds struct ipoib_dev_priv *cpriv; 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds /* Bring down any child interfaces too */ 202f47944ccSErez Shitrit down_read(&priv->vlan_rwsem); 2031da177e4SLinus Torvalds list_for_each_entry(cpriv, &priv->child_intfs, list) { 2041da177e4SLinus Torvalds int flags; 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds flags = cpriv->dev->flags; 2071da177e4SLinus Torvalds if (!(flags & IFF_UP)) 2081da177e4SLinus Torvalds continue; 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds dev_change_flags(cpriv->dev, flags & ~IFF_UP); 2111da177e4SLinus Torvalds } 212f47944ccSErez Shitrit up_read(&priv->vlan_rwsem); 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds return 0; 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds 2189baa0b03SOr Gerlitz static void ipoib_uninit(struct net_device *dev) 2199baa0b03SOr Gerlitz { 2209baa0b03SOr Gerlitz ipoib_dev_cleanup(dev); 2219baa0b03SOr Gerlitz } 2229baa0b03SOr Gerlitz 2239ca36f7dSDavid S. Miller static netdev_features_t ipoib_fix_features(struct net_device *dev, netdev_features_t features) 2243d96c74dSMichał Mirosław { 2253d96c74dSMichał Mirosław struct ipoib_dev_priv *priv = netdev_priv(dev); 2263d96c74dSMichał Mirosław 2273d96c74dSMichał Mirosław if (test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags)) 228c4268778SYuval Shaia features &= ~(NETIF_F_IP_CSUM | NETIF_F_TSO); 2293d96c74dSMichał Mirosław 2303d96c74dSMichał Mirosław return features; 2313d96c74dSMichał Mirosław } 2323d96c74dSMichał Mirosław 2331da177e4SLinus Torvalds static int ipoib_change_mtu(struct net_device *dev, int new_mtu) 2341da177e4SLinus Torvalds { 2351da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 2361da177e4SLinus Torvalds 237839fcabaSMichael S. Tsirkin /* dev->mtu > 2K ==> connected mode */ 238586a6934SPradeep Satyanarayana if (ipoib_cm_admin_enabled(dev)) { 239586a6934SPradeep Satyanarayana if (new_mtu > ipoib_cm_max_mtu(dev)) 240586a6934SPradeep Satyanarayana return -EINVAL; 241586a6934SPradeep Satyanarayana 242839fcabaSMichael S. Tsirkin if (new_mtu > priv->mcast_mtu) 243839fcabaSMichael S. Tsirkin ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n", 244839fcabaSMichael S. Tsirkin priv->mcast_mtu); 245586a6934SPradeep Satyanarayana 246839fcabaSMichael S. Tsirkin dev->mtu = new_mtu; 247839fcabaSMichael S. Tsirkin return 0; 248839fcabaSMichael S. Tsirkin } 249839fcabaSMichael S. Tsirkin 250bc7b3a36SShirley Ma if (new_mtu > IPOIB_UD_MTU(priv->max_ib_mtu)) 2511da177e4SLinus Torvalds return -EINVAL; 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds priv->admin_mtu = new_mtu; 2541da177e4SLinus Torvalds 25529da686dSFeras Daoud if (priv->mcast_mtu < priv->admin_mtu) 25629da686dSFeras Daoud ipoib_dbg(priv, "MTU must be smaller than the underlying " 25729da686dSFeras Daoud "link layer MTU - 4 (%u)\n", priv->mcast_mtu); 25829da686dSFeras Daoud 2591da177e4SLinus Torvalds dev->mtu = min(priv->mcast_mtu, priv->admin_mtu); 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds return 0; 2621da177e4SLinus Torvalds } 2631da177e4SLinus Torvalds 264ddde896eSGuy Shapiro /* Called with an RCU read lock taken */ 265ddde896eSGuy Shapiro static bool ipoib_is_dev_match_addr_rcu(const struct sockaddr *addr, 266ddde896eSGuy Shapiro struct net_device *dev) 267ddde896eSGuy Shapiro { 268ddde896eSGuy Shapiro struct net *net = dev_net(dev); 269ddde896eSGuy Shapiro struct in_device *in_dev; 270ddde896eSGuy Shapiro struct sockaddr_in *addr_in = (struct sockaddr_in *)addr; 271ddde896eSGuy Shapiro struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr; 272ddde896eSGuy Shapiro __be32 ret_addr; 273ddde896eSGuy Shapiro 274ddde896eSGuy Shapiro switch (addr->sa_family) { 275ddde896eSGuy Shapiro case AF_INET: 276ddde896eSGuy Shapiro in_dev = in_dev_get(dev); 277ddde896eSGuy Shapiro if (!in_dev) 278ddde896eSGuy Shapiro return false; 279ddde896eSGuy Shapiro 280ddde896eSGuy Shapiro ret_addr = inet_confirm_addr(net, in_dev, 0, 281ddde896eSGuy Shapiro addr_in->sin_addr.s_addr, 282ddde896eSGuy Shapiro RT_SCOPE_HOST); 283ddde896eSGuy Shapiro in_dev_put(in_dev); 284ddde896eSGuy Shapiro if (ret_addr) 285ddde896eSGuy Shapiro return true; 286ddde896eSGuy Shapiro 287ddde896eSGuy Shapiro break; 288ddde896eSGuy Shapiro case AF_INET6: 289ddde896eSGuy Shapiro if (IS_ENABLED(CONFIG_IPV6) && 290ddde896eSGuy Shapiro ipv6_chk_addr(net, &addr_in6->sin6_addr, dev, 1)) 291ddde896eSGuy Shapiro return true; 292ddde896eSGuy Shapiro 293ddde896eSGuy Shapiro break; 294ddde896eSGuy Shapiro } 295ddde896eSGuy Shapiro return false; 296ddde896eSGuy Shapiro } 297ddde896eSGuy Shapiro 298ddde896eSGuy Shapiro /** 299ddde896eSGuy Shapiro * Find the master net_device on top of the given net_device. 300ddde896eSGuy Shapiro * @dev: base IPoIB net_device 301ddde896eSGuy Shapiro * 302ddde896eSGuy Shapiro * Returns the master net_device with a reference held, or the same net_device 303ddde896eSGuy Shapiro * if no master exists. 304ddde896eSGuy Shapiro */ 305ddde896eSGuy Shapiro static struct net_device *ipoib_get_master_net_dev(struct net_device *dev) 306ddde896eSGuy Shapiro { 307ddde896eSGuy Shapiro struct net_device *master; 308ddde896eSGuy Shapiro 309ddde896eSGuy Shapiro rcu_read_lock(); 310ddde896eSGuy Shapiro master = netdev_master_upper_dev_get_rcu(dev); 311ddde896eSGuy Shapiro if (master) 312ddde896eSGuy Shapiro dev_hold(master); 313ddde896eSGuy Shapiro rcu_read_unlock(); 314ddde896eSGuy Shapiro 315ddde896eSGuy Shapiro if (master) 316ddde896eSGuy Shapiro return master; 317ddde896eSGuy Shapiro 318ddde896eSGuy Shapiro dev_hold(dev); 319ddde896eSGuy Shapiro return dev; 320ddde896eSGuy Shapiro } 321ddde896eSGuy Shapiro 322e0e79c8eSDavid Ahern struct ipoib_walk_data { 323e0e79c8eSDavid Ahern const struct sockaddr *addr; 324e0e79c8eSDavid Ahern struct net_device *result; 325e0e79c8eSDavid Ahern }; 326e0e79c8eSDavid Ahern 327e0e79c8eSDavid Ahern static int ipoib_upper_walk(struct net_device *upper, void *_data) 328e0e79c8eSDavid Ahern { 329e0e79c8eSDavid Ahern struct ipoib_walk_data *data = _data; 330e0e79c8eSDavid Ahern int ret = 0; 331e0e79c8eSDavid Ahern 332e0e79c8eSDavid Ahern if (ipoib_is_dev_match_addr_rcu(data->addr, upper)) { 333e0e79c8eSDavid Ahern dev_hold(upper); 334e0e79c8eSDavid Ahern data->result = upper; 335e0e79c8eSDavid Ahern ret = 1; 336e0e79c8eSDavid Ahern } 337e0e79c8eSDavid Ahern 338e0e79c8eSDavid Ahern return ret; 339e0e79c8eSDavid Ahern } 340e0e79c8eSDavid Ahern 341ddde896eSGuy Shapiro /** 342ddde896eSGuy Shapiro * Find a net_device matching the given address, which is an upper device of 343ddde896eSGuy Shapiro * the given net_device. 344ddde896eSGuy Shapiro * @addr: IP address to look for. 345ddde896eSGuy Shapiro * @dev: base IPoIB net_device 346ddde896eSGuy Shapiro * 347ddde896eSGuy Shapiro * If found, returns the net_device with a reference held. Otherwise return 348ddde896eSGuy Shapiro * NULL. 349ddde896eSGuy Shapiro */ 350ddde896eSGuy Shapiro static struct net_device *ipoib_get_net_dev_match_addr( 351ddde896eSGuy Shapiro const struct sockaddr *addr, struct net_device *dev) 352ddde896eSGuy Shapiro { 353e0e79c8eSDavid Ahern struct ipoib_walk_data data = { 354e0e79c8eSDavid Ahern .addr = addr, 355e0e79c8eSDavid Ahern }; 356ddde896eSGuy Shapiro 357ddde896eSGuy Shapiro rcu_read_lock(); 358ddde896eSGuy Shapiro if (ipoib_is_dev_match_addr_rcu(addr, dev)) { 359ddde896eSGuy Shapiro dev_hold(dev); 360e0e79c8eSDavid Ahern data.result = dev; 361ddde896eSGuy Shapiro goto out; 362ddde896eSGuy Shapiro } 363ddde896eSGuy Shapiro 364e0e79c8eSDavid Ahern netdev_walk_all_upper_dev_rcu(dev, ipoib_upper_walk, &data); 365ddde896eSGuy Shapiro out: 366ddde896eSGuy Shapiro rcu_read_unlock(); 367e0e79c8eSDavid Ahern return data.result; 368ddde896eSGuy Shapiro } 369ddde896eSGuy Shapiro 370ddde896eSGuy Shapiro /* returns the number of IPoIB netdevs on top a given ipoib device matching a 371ddde896eSGuy Shapiro * pkey_index and address, if one exists. 372ddde896eSGuy Shapiro * 373ddde896eSGuy Shapiro * @found_net_dev: contains a matching net_device if the return value >= 1, 374ddde896eSGuy Shapiro * with a reference held. */ 375ddde896eSGuy Shapiro static int ipoib_match_gid_pkey_addr(struct ipoib_dev_priv *priv, 376ddde896eSGuy Shapiro const union ib_gid *gid, 377ddde896eSGuy Shapiro u16 pkey_index, 378ddde896eSGuy Shapiro const struct sockaddr *addr, 379ddde896eSGuy Shapiro int nesting, 380ddde896eSGuy Shapiro struct net_device **found_net_dev) 381ddde896eSGuy Shapiro { 382ddde896eSGuy Shapiro struct ipoib_dev_priv *child_priv; 383ddde896eSGuy Shapiro struct net_device *net_dev = NULL; 384ddde896eSGuy Shapiro int matches = 0; 385ddde896eSGuy Shapiro 386ddde896eSGuy Shapiro if (priv->pkey_index == pkey_index && 387ddde896eSGuy Shapiro (!gid || !memcmp(gid, &priv->local_gid, sizeof(*gid)))) { 388ddde896eSGuy Shapiro if (!addr) { 389ddde896eSGuy Shapiro net_dev = ipoib_get_master_net_dev(priv->dev); 390ddde896eSGuy Shapiro } else { 391ddde896eSGuy Shapiro /* Verify the net_device matches the IP address, as 392ddde896eSGuy Shapiro * IPoIB child devices currently share a GID. */ 393ddde896eSGuy Shapiro net_dev = ipoib_get_net_dev_match_addr(addr, priv->dev); 394ddde896eSGuy Shapiro } 395ddde896eSGuy Shapiro if (net_dev) { 396ddde896eSGuy Shapiro if (!*found_net_dev) 397ddde896eSGuy Shapiro *found_net_dev = net_dev; 398ddde896eSGuy Shapiro else 399ddde896eSGuy Shapiro dev_put(net_dev); 400ddde896eSGuy Shapiro ++matches; 401ddde896eSGuy Shapiro } 402ddde896eSGuy Shapiro } 403ddde896eSGuy Shapiro 404ddde896eSGuy Shapiro /* Check child interfaces */ 405ddde896eSGuy Shapiro down_read_nested(&priv->vlan_rwsem, nesting); 406ddde896eSGuy Shapiro list_for_each_entry(child_priv, &priv->child_intfs, list) { 407ddde896eSGuy Shapiro matches += ipoib_match_gid_pkey_addr(child_priv, gid, 408ddde896eSGuy Shapiro pkey_index, addr, 409ddde896eSGuy Shapiro nesting + 1, 410ddde896eSGuy Shapiro found_net_dev); 411ddde896eSGuy Shapiro if (matches > 1) 412ddde896eSGuy Shapiro break; 413ddde896eSGuy Shapiro } 414ddde896eSGuy Shapiro up_read(&priv->vlan_rwsem); 415ddde896eSGuy Shapiro 416ddde896eSGuy Shapiro return matches; 417ddde896eSGuy Shapiro } 418ddde896eSGuy Shapiro 419ddde896eSGuy Shapiro /* Returns the number of matching net_devs found (between 0 and 2). Also 420ddde896eSGuy Shapiro * return the matching net_device in the @net_dev parameter, holding a 421ddde896eSGuy Shapiro * reference to the net_device, if the number of matches >= 1 */ 422ddde896eSGuy Shapiro static int __ipoib_get_net_dev_by_params(struct list_head *dev_list, u8 port, 423ddde896eSGuy Shapiro u16 pkey_index, 424ddde896eSGuy Shapiro const union ib_gid *gid, 425ddde896eSGuy Shapiro const struct sockaddr *addr, 426ddde896eSGuy Shapiro struct net_device **net_dev) 427ddde896eSGuy Shapiro { 428ddde896eSGuy Shapiro struct ipoib_dev_priv *priv; 429ddde896eSGuy Shapiro int matches = 0; 430ddde896eSGuy Shapiro 431ddde896eSGuy Shapiro *net_dev = NULL; 432ddde896eSGuy Shapiro 433ddde896eSGuy Shapiro list_for_each_entry(priv, dev_list, list) { 434ddde896eSGuy Shapiro if (priv->port != port) 435ddde896eSGuy Shapiro continue; 436ddde896eSGuy Shapiro 437ddde896eSGuy Shapiro matches += ipoib_match_gid_pkey_addr(priv, gid, pkey_index, 438ddde896eSGuy Shapiro addr, 0, net_dev); 439ddde896eSGuy Shapiro if (matches > 1) 440ddde896eSGuy Shapiro break; 441ddde896eSGuy Shapiro } 442ddde896eSGuy Shapiro 443ddde896eSGuy Shapiro return matches; 444ddde896eSGuy Shapiro } 445ddde896eSGuy Shapiro 446ddde896eSGuy Shapiro static struct net_device *ipoib_get_net_dev_by_params( 447ddde896eSGuy Shapiro struct ib_device *dev, u8 port, u16 pkey, 448ddde896eSGuy Shapiro const union ib_gid *gid, const struct sockaddr *addr, 449ddde896eSGuy Shapiro void *client_data) 450ddde896eSGuy Shapiro { 451ddde896eSGuy Shapiro struct net_device *net_dev; 452ddde896eSGuy Shapiro struct list_head *dev_list = client_data; 453ddde896eSGuy Shapiro u16 pkey_index; 454ddde896eSGuy Shapiro int matches; 455ddde896eSGuy Shapiro int ret; 456ddde896eSGuy Shapiro 457ddde896eSGuy Shapiro if (!rdma_protocol_ib(dev, port)) 458ddde896eSGuy Shapiro return NULL; 459ddde896eSGuy Shapiro 460ddde896eSGuy Shapiro ret = ib_find_cached_pkey(dev, port, pkey, &pkey_index); 461ddde896eSGuy Shapiro if (ret) 462ddde896eSGuy Shapiro return NULL; 463ddde896eSGuy Shapiro 464ddde896eSGuy Shapiro if (!dev_list) 465ddde896eSGuy Shapiro return NULL; 466ddde896eSGuy Shapiro 467ddde896eSGuy Shapiro /* See if we can find a unique device matching the L2 parameters */ 468ddde896eSGuy Shapiro matches = __ipoib_get_net_dev_by_params(dev_list, port, pkey_index, 469ddde896eSGuy Shapiro gid, NULL, &net_dev); 470ddde896eSGuy Shapiro 471ddde896eSGuy Shapiro switch (matches) { 472ddde896eSGuy Shapiro case 0: 473ddde896eSGuy Shapiro return NULL; 474ddde896eSGuy Shapiro case 1: 475ddde896eSGuy Shapiro return net_dev; 476ddde896eSGuy Shapiro } 477ddde896eSGuy Shapiro 478ddde896eSGuy Shapiro dev_put(net_dev); 479ddde896eSGuy Shapiro 480ddde896eSGuy Shapiro /* Couldn't find a unique device with L2 parameters only. Use L3 481ddde896eSGuy Shapiro * address to uniquely match the net device */ 482ddde896eSGuy Shapiro matches = __ipoib_get_net_dev_by_params(dev_list, port, pkey_index, 483ddde896eSGuy Shapiro gid, addr, &net_dev); 484ddde896eSGuy Shapiro switch (matches) { 485ddde896eSGuy Shapiro case 0: 486ddde896eSGuy Shapiro return NULL; 487ddde896eSGuy Shapiro default: 488ddde896eSGuy Shapiro dev_warn_ratelimited(&dev->dev, 489ddde896eSGuy Shapiro "duplicate IP address detected\n"); 490ddde896eSGuy Shapiro /* Fall through */ 491ddde896eSGuy Shapiro case 1: 492ddde896eSGuy Shapiro return net_dev; 493ddde896eSGuy Shapiro } 494ddde896eSGuy Shapiro } 495ddde896eSGuy Shapiro 49671d9c5f9SRoland Dreier int ipoib_set_mode(struct net_device *dev, const char *buf) 49771d9c5f9SRoland Dreier { 49871d9c5f9SRoland Dreier struct ipoib_dev_priv *priv = netdev_priv(dev); 49971d9c5f9SRoland Dreier 50080b5b35aSFeras Daoud if ((test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags) && 50180b5b35aSFeras Daoud !strcmp(buf, "connected\n")) || 50280b5b35aSFeras Daoud (!test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags) && 50380b5b35aSFeras Daoud !strcmp(buf, "datagram\n"))) { 50480b5b35aSFeras Daoud return 0; 50580b5b35aSFeras Daoud } 50680b5b35aSFeras Daoud 50771d9c5f9SRoland Dreier /* flush paths if we switch modes so that connections are restarted */ 50871d9c5f9SRoland Dreier if (IPOIB_CM_SUPPORTED(dev->dev_addr) && !strcmp(buf, "connected\n")) { 50971d9c5f9SRoland Dreier set_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); 51071d9c5f9SRoland Dreier ipoib_warn(priv, "enabling connected mode " 51171d9c5f9SRoland Dreier "will cause multicast packet drops\n"); 51271d9c5f9SRoland Dreier netdev_update_features(dev); 513edcd2a74SErez Shitrit dev_set_mtu(dev, ipoib_cm_max_mtu(dev)); 51471d9c5f9SRoland Dreier rtnl_unlock(); 515e622f2f4SChristoph Hellwig priv->tx_wr.wr.send_flags &= ~IB_SEND_IP_CSUM; 51671d9c5f9SRoland Dreier 51771d9c5f9SRoland Dreier ipoib_flush_paths(dev); 5180a0007f2SFeras Daoud return (!rtnl_trylock()) ? -EBUSY : 0; 51971d9c5f9SRoland Dreier } 52071d9c5f9SRoland Dreier 52171d9c5f9SRoland Dreier if (!strcmp(buf, "datagram\n")) { 52271d9c5f9SRoland Dreier clear_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); 52371d9c5f9SRoland Dreier netdev_update_features(dev); 52471d9c5f9SRoland Dreier dev_set_mtu(dev, min(priv->mcast_mtu, dev->mtu)); 52571d9c5f9SRoland Dreier rtnl_unlock(); 52671d9c5f9SRoland Dreier ipoib_flush_paths(dev); 5270a0007f2SFeras Daoud return (!rtnl_trylock()) ? -EBUSY : 0; 52871d9c5f9SRoland Dreier } 52971d9c5f9SRoland Dreier 53071d9c5f9SRoland Dreier return -EINVAL; 53171d9c5f9SRoland Dreier } 53271d9c5f9SRoland Dreier 533546481c2SErez Shitrit struct ipoib_path *__path_find(struct net_device *dev, void *gid) 5341da177e4SLinus Torvalds { 5351da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 5361da177e4SLinus Torvalds struct rb_node *n = priv->path_tree.rb_node; 5371da177e4SLinus Torvalds struct ipoib_path *path; 5381da177e4SLinus Torvalds int ret; 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds while (n) { 5411da177e4SLinus Torvalds path = rb_entry(n, struct ipoib_path, rb_node); 5421da177e4SLinus Torvalds 54337c22a77SJack Morgenstein ret = memcmp(gid, path->pathrec.dgid.raw, 5441da177e4SLinus Torvalds sizeof (union ib_gid)); 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds if (ret < 0) 5471da177e4SLinus Torvalds n = n->rb_left; 5481da177e4SLinus Torvalds else if (ret > 0) 5491da177e4SLinus Torvalds n = n->rb_right; 5501da177e4SLinus Torvalds else 5511da177e4SLinus Torvalds return path; 5521da177e4SLinus Torvalds } 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds return NULL; 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds static int __path_add(struct net_device *dev, struct ipoib_path *path) 5581da177e4SLinus Torvalds { 5591da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 5601da177e4SLinus Torvalds struct rb_node **n = &priv->path_tree.rb_node; 5611da177e4SLinus Torvalds struct rb_node *pn = NULL; 5621da177e4SLinus Torvalds struct ipoib_path *tpath; 5631da177e4SLinus Torvalds int ret; 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds while (*n) { 5661da177e4SLinus Torvalds pn = *n; 5671da177e4SLinus Torvalds tpath = rb_entry(pn, struct ipoib_path, rb_node); 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds ret = memcmp(path->pathrec.dgid.raw, tpath->pathrec.dgid.raw, 5701da177e4SLinus Torvalds sizeof (union ib_gid)); 5711da177e4SLinus Torvalds if (ret < 0) 5721da177e4SLinus Torvalds n = &pn->rb_left; 5731da177e4SLinus Torvalds else if (ret > 0) 5741da177e4SLinus Torvalds n = &pn->rb_right; 5751da177e4SLinus Torvalds else 5761da177e4SLinus Torvalds return -EEXIST; 5771da177e4SLinus Torvalds } 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds rb_link_node(&path->rb_node, pn, n); 5801da177e4SLinus Torvalds rb_insert_color(&path->rb_node, &priv->path_tree); 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds list_add_tail(&path->list, &priv->path_list); 5831da177e4SLinus Torvalds 5841da177e4SLinus Torvalds return 0; 5851da177e4SLinus Torvalds } 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds static void path_free(struct net_device *dev, struct ipoib_path *path) 5881da177e4SLinus Torvalds { 5891da177e4SLinus Torvalds struct sk_buff *skb; 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds while ((skb = __skb_dequeue(&path->queue))) 5921da177e4SLinus Torvalds dev_kfree_skb_irq(skb); 5931da177e4SLinus Torvalds 594b63b70d8SShlomo Pongratz ipoib_dbg(netdev_priv(dev), "path_free\n"); 5951da177e4SLinus Torvalds 596b63b70d8SShlomo Pongratz /* remove all neigh connected to this path */ 597b63b70d8SShlomo Pongratz ipoib_del_neighs_by_gid(dev, path->pathrec.dgid.raw); 5981da177e4SLinus Torvalds 5991da177e4SLinus Torvalds if (path->ah) 6001da177e4SLinus Torvalds ipoib_put_ah(path->ah); 6011da177e4SLinus Torvalds 6021da177e4SLinus Torvalds kfree(path); 6031da177e4SLinus Torvalds } 6041da177e4SLinus Torvalds 6051732b0efSRoland Dreier #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 6061732b0efSRoland Dreier 6071732b0efSRoland Dreier struct ipoib_path_iter *ipoib_path_iter_init(struct net_device *dev) 6081732b0efSRoland Dreier { 6091732b0efSRoland Dreier struct ipoib_path_iter *iter; 6101732b0efSRoland Dreier 6111732b0efSRoland Dreier iter = kmalloc(sizeof *iter, GFP_KERNEL); 6121732b0efSRoland Dreier if (!iter) 6131732b0efSRoland Dreier return NULL; 6141732b0efSRoland Dreier 6151732b0efSRoland Dreier iter->dev = dev; 6161732b0efSRoland Dreier memset(iter->path.pathrec.dgid.raw, 0, 16); 6171732b0efSRoland Dreier 6181732b0efSRoland Dreier if (ipoib_path_iter_next(iter)) { 6191732b0efSRoland Dreier kfree(iter); 6201732b0efSRoland Dreier return NULL; 6211732b0efSRoland Dreier } 6221732b0efSRoland Dreier 6231732b0efSRoland Dreier return iter; 6241732b0efSRoland Dreier } 6251732b0efSRoland Dreier 6261732b0efSRoland Dreier int ipoib_path_iter_next(struct ipoib_path_iter *iter) 6271732b0efSRoland Dreier { 6281732b0efSRoland Dreier struct ipoib_dev_priv *priv = netdev_priv(iter->dev); 6291732b0efSRoland Dreier struct rb_node *n; 6301732b0efSRoland Dreier struct ipoib_path *path; 6311732b0efSRoland Dreier int ret = 1; 6321732b0efSRoland Dreier 6331732b0efSRoland Dreier spin_lock_irq(&priv->lock); 6341732b0efSRoland Dreier 6351732b0efSRoland Dreier n = rb_first(&priv->path_tree); 6361732b0efSRoland Dreier 6371732b0efSRoland Dreier while (n) { 6381732b0efSRoland Dreier path = rb_entry(n, struct ipoib_path, rb_node); 6391732b0efSRoland Dreier 6401732b0efSRoland Dreier if (memcmp(iter->path.pathrec.dgid.raw, path->pathrec.dgid.raw, 6411732b0efSRoland Dreier sizeof (union ib_gid)) < 0) { 6421732b0efSRoland Dreier iter->path = *path; 6431732b0efSRoland Dreier ret = 0; 6441732b0efSRoland Dreier break; 6451732b0efSRoland Dreier } 6461732b0efSRoland Dreier 6471732b0efSRoland Dreier n = rb_next(n); 6481732b0efSRoland Dreier } 6491732b0efSRoland Dreier 6501732b0efSRoland Dreier spin_unlock_irq(&priv->lock); 6511732b0efSRoland Dreier 6521732b0efSRoland Dreier return ret; 6531732b0efSRoland Dreier } 6541732b0efSRoland Dreier 6551732b0efSRoland Dreier void ipoib_path_iter_read(struct ipoib_path_iter *iter, 6561732b0efSRoland Dreier struct ipoib_path *path) 6571732b0efSRoland Dreier { 6581732b0efSRoland Dreier *path = iter->path; 6591732b0efSRoland Dreier } 6601732b0efSRoland Dreier 6611732b0efSRoland Dreier #endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */ 6621732b0efSRoland Dreier 663ee1e2c82SMoni Shoua void ipoib_mark_paths_invalid(struct net_device *dev) 664ee1e2c82SMoni Shoua { 665ee1e2c82SMoni Shoua struct ipoib_dev_priv *priv = netdev_priv(dev); 666ee1e2c82SMoni Shoua struct ipoib_path *path, *tp; 667ee1e2c82SMoni Shoua 668ee1e2c82SMoni Shoua spin_lock_irq(&priv->lock); 669ee1e2c82SMoni Shoua 670ee1e2c82SMoni Shoua list_for_each_entry_safe(path, tp, &priv->path_list, list) { 6715b095d98SHarvey Harrison ipoib_dbg(priv, "mark path LID 0x%04x GID %pI6 invalid\n", 672ee1e2c82SMoni Shoua be16_to_cpu(path->pathrec.dlid), 673fcace2feSHarvey Harrison path->pathrec.dgid.raw); 674ee1e2c82SMoni Shoua path->valid = 0; 675ee1e2c82SMoni Shoua } 676ee1e2c82SMoni Shoua 677ee1e2c82SMoni Shoua spin_unlock_irq(&priv->lock); 678ee1e2c82SMoni Shoua } 679ee1e2c82SMoni Shoua 6803b561130SErez Shitrit struct classport_info_context { 6813b561130SErez Shitrit struct ipoib_dev_priv *priv; 6823b561130SErez Shitrit struct completion done; 6833b561130SErez Shitrit struct ib_sa_query *sa_query; 6843b561130SErez Shitrit }; 6853b561130SErez Shitrit 6863b561130SErez Shitrit static void classport_info_query_cb(int status, struct ib_class_port_info *rec, 6873b561130SErez Shitrit void *context) 6883b561130SErez Shitrit { 6893b561130SErez Shitrit struct classport_info_context *cb_ctx = context; 6903b561130SErez Shitrit struct ipoib_dev_priv *priv; 6913b561130SErez Shitrit 6923b561130SErez Shitrit WARN_ON(!context); 6933b561130SErez Shitrit 6943b561130SErez Shitrit priv = cb_ctx->priv; 6953b561130SErez Shitrit 6963b561130SErez Shitrit if (status || !rec) { 6973b561130SErez Shitrit pr_debug("device: %s failed query classport_info status: %d\n", 6983b561130SErez Shitrit priv->dev->name, status); 6993b561130SErez Shitrit /* keeps the default, will try next mcast_restart */ 7003b561130SErez Shitrit priv->sm_fullmember_sendonly_support = false; 7013b561130SErez Shitrit goto out; 7023b561130SErez Shitrit } 7033b561130SErez Shitrit 7043b561130SErez Shitrit if (ib_get_cpi_capmask2(rec) & 7053b561130SErez Shitrit IB_SA_CAP_MASK2_SENDONLY_FULL_MEM_SUPPORT) { 7063b561130SErez Shitrit pr_debug("device: %s enabled fullmember-sendonly for sendonly MCG\n", 7073b561130SErez Shitrit priv->dev->name); 7083b561130SErez Shitrit priv->sm_fullmember_sendonly_support = true; 7093b561130SErez Shitrit } else { 7103b561130SErez Shitrit pr_debug("device: %s disabled fullmember-sendonly for sendonly MCG\n", 7113b561130SErez Shitrit priv->dev->name); 7123b561130SErez Shitrit priv->sm_fullmember_sendonly_support = false; 7133b561130SErez Shitrit } 7143b561130SErez Shitrit 7153b561130SErez Shitrit out: 7163b561130SErez Shitrit complete(&cb_ctx->done); 7173b561130SErez Shitrit } 7183b561130SErez Shitrit 7193b561130SErez Shitrit int ipoib_check_sm_sendonly_fullmember_support(struct ipoib_dev_priv *priv) 7203b561130SErez Shitrit { 7213b561130SErez Shitrit struct classport_info_context *callback_context; 7223b561130SErez Shitrit int ret; 7233b561130SErez Shitrit 7243b561130SErez Shitrit callback_context = kmalloc(sizeof(*callback_context), GFP_KERNEL); 7253b561130SErez Shitrit if (!callback_context) 7263b561130SErez Shitrit return -ENOMEM; 7273b561130SErez Shitrit 7283b561130SErez Shitrit callback_context->priv = priv; 7293b561130SErez Shitrit init_completion(&callback_context->done); 7303b561130SErez Shitrit 7313b561130SErez Shitrit ret = ib_sa_classport_info_rec_query(&ipoib_sa_client, 7323b561130SErez Shitrit priv->ca, priv->port, 3000, 7333b561130SErez Shitrit GFP_KERNEL, 7343b561130SErez Shitrit classport_info_query_cb, 7353b561130SErez Shitrit callback_context, 7363b561130SErez Shitrit &callback_context->sa_query); 7373b561130SErez Shitrit if (ret < 0) { 7383b561130SErez Shitrit pr_info("%s failed to send ib_sa_classport_info query, ret: %d\n", 7393b561130SErez Shitrit priv->dev->name, ret); 7403b561130SErez Shitrit kfree(callback_context); 7413b561130SErez Shitrit return ret; 7423b561130SErez Shitrit } 7433b561130SErez Shitrit 7443b561130SErez Shitrit /* waiting for the callback to finish before returnning */ 7453b561130SErez Shitrit wait_for_completion(&callback_context->done); 7463b561130SErez Shitrit kfree(callback_context); 7473b561130SErez Shitrit 7483b561130SErez Shitrit return ret; 7493b561130SErez Shitrit } 7503b561130SErez Shitrit 7512b084176SErez Shitrit static void push_pseudo_header(struct sk_buff *skb, const char *daddr) 7522b084176SErez Shitrit { 7532b084176SErez Shitrit struct ipoib_pseudo_header *phdr; 7542b084176SErez Shitrit 7552b084176SErez Shitrit phdr = (struct ipoib_pseudo_header *)skb_push(skb, sizeof(*phdr)); 7562b084176SErez Shitrit memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); 7572b084176SErez Shitrit } 7582b084176SErez Shitrit 7591da177e4SLinus Torvalds void ipoib_flush_paths(struct net_device *dev) 7601da177e4SLinus Torvalds { 7611da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 7621da177e4SLinus Torvalds struct ipoib_path *path, *tp; 7631da177e4SLinus Torvalds LIST_HEAD(remove_list); 764943c246eSRoland Dreier unsigned long flags; 7651da177e4SLinus Torvalds 766943c246eSRoland Dreier netif_tx_lock_bh(dev); 767943c246eSRoland Dreier spin_lock_irqsave(&priv->lock, flags); 7681da177e4SLinus Torvalds 769157de229SRobert P. J. Day list_splice_init(&priv->path_list, &remove_list); 7701da177e4SLinus Torvalds 7711da177e4SLinus Torvalds list_for_each_entry(path, &remove_list, list) 7721da177e4SLinus Torvalds rb_erase(&path->rb_node, &priv->path_tree); 7731da177e4SLinus Torvalds 7741da177e4SLinus Torvalds list_for_each_entry_safe(path, tp, &remove_list, list) { 7751da177e4SLinus Torvalds if (path->query) 7761da177e4SLinus Torvalds ib_sa_cancel_query(path->query_id, path->query); 777943c246eSRoland Dreier spin_unlock_irqrestore(&priv->lock, flags); 778943c246eSRoland Dreier netif_tx_unlock_bh(dev); 7791da177e4SLinus Torvalds wait_for_completion(&path->done); 7801da177e4SLinus Torvalds path_free(dev, path); 781943c246eSRoland Dreier netif_tx_lock_bh(dev); 782943c246eSRoland Dreier spin_lock_irqsave(&priv->lock, flags); 7831da177e4SLinus Torvalds } 784943c246eSRoland Dreier 785943c246eSRoland Dreier spin_unlock_irqrestore(&priv->lock, flags); 786943c246eSRoland Dreier netif_tx_unlock_bh(dev); 7871da177e4SLinus Torvalds } 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds static void path_rec_completion(int status, 7901da177e4SLinus Torvalds struct ib_sa_path_rec *pathrec, 7911da177e4SLinus Torvalds void *path_ptr) 7921da177e4SLinus Torvalds { 7931da177e4SLinus Torvalds struct ipoib_path *path = path_ptr; 7941da177e4SLinus Torvalds struct net_device *dev = path->dev; 7951da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 7961da177e4SLinus Torvalds struct ipoib_ah *ah = NULL; 797c9da4badSRoland Dreier struct ipoib_ah *old_ah = NULL; 798d04d01b1SMichael S. Tsirkin struct ipoib_neigh *neigh, *tn; 7991da177e4SLinus Torvalds struct sk_buff_head skqueue; 8001da177e4SLinus Torvalds struct sk_buff *skb; 8011da177e4SLinus Torvalds unsigned long flags; 8021da177e4SLinus Torvalds 803843613b0SRoland Dreier if (!status) 8045b095d98SHarvey Harrison ipoib_dbg(priv, "PathRec LID 0x%04x for GID %pI6\n", 805fcace2feSHarvey Harrison be16_to_cpu(pathrec->dlid), pathrec->dgid.raw); 8061da177e4SLinus Torvalds else 8075b095d98SHarvey Harrison ipoib_dbg(priv, "PathRec status %d for GID %pI6\n", 808fcace2feSHarvey Harrison status, path->pathrec.dgid.raw); 8091da177e4SLinus Torvalds 8101da177e4SLinus Torvalds skb_queue_head_init(&skqueue); 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds if (!status) { 81346f1b3d7SSean Hefty struct ib_ah_attr av; 8141da177e4SLinus Torvalds 81546f1b3d7SSean Hefty if (!ib_init_ah_from_path(priv->ca, priv->port, pathrec, &av)) 8161da177e4SLinus Torvalds ah = ipoib_create_ah(dev, priv->pd, &av); 8171da177e4SLinus Torvalds } 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds spin_lock_irqsave(&priv->lock, flags); 8201da177e4SLinus Torvalds 8213874397cSMike Marciniszyn if (!IS_ERR_OR_NULL(ah)) { 8221da177e4SLinus Torvalds path->pathrec = *pathrec; 8231da177e4SLinus Torvalds 824c9da4badSRoland Dreier old_ah = path->ah; 825c9da4badSRoland Dreier path->ah = ah; 826c9da4badSRoland Dreier 8271da177e4SLinus Torvalds ipoib_dbg(priv, "created address handle %p for LID 0x%04x, SL %d\n", 8281da177e4SLinus Torvalds ah, be16_to_cpu(pathrec->dlid), pathrec->sl); 8291da177e4SLinus Torvalds 8301da177e4SLinus Torvalds while ((skb = __skb_dequeue(&path->queue))) 8311da177e4SLinus Torvalds __skb_queue_tail(&skqueue, skb); 8321da177e4SLinus Torvalds 833d04d01b1SMichael S. Tsirkin list_for_each_entry_safe(neigh, tn, &path->neigh_list, list) { 834ee1e2c82SMoni Shoua if (neigh->ah) { 835ee1e2c82SMoni Shoua WARN_ON(neigh->ah != old_ah); 836ee1e2c82SMoni Shoua /* 837ee1e2c82SMoni Shoua * Dropping the ah reference inside 838ee1e2c82SMoni Shoua * priv->lock is safe here, because we 839ee1e2c82SMoni Shoua * will hold one more reference from 840ee1e2c82SMoni Shoua * the original value of path->ah (ie 841ee1e2c82SMoni Shoua * old_ah). 842ee1e2c82SMoni Shoua */ 843ee1e2c82SMoni Shoua ipoib_put_ah(neigh->ah); 844ee1e2c82SMoni Shoua } 8451da177e4SLinus Torvalds kref_get(&path->ah->ref); 8461da177e4SLinus Torvalds neigh->ah = path->ah; 8471da177e4SLinus Torvalds 848b63b70d8SShlomo Pongratz if (ipoib_cm_enabled(dev, neigh->daddr)) { 849839fcabaSMichael S. Tsirkin if (!ipoib_cm_get(neigh)) 850839fcabaSMichael S. Tsirkin ipoib_cm_set(neigh, ipoib_cm_create_tx(dev, 851839fcabaSMichael S. Tsirkin path, 852839fcabaSMichael S. Tsirkin neigh)); 853839fcabaSMichael S. Tsirkin if (!ipoib_cm_get(neigh)) { 854b63b70d8SShlomo Pongratz ipoib_neigh_free(neigh); 855839fcabaSMichael S. Tsirkin continue; 856839fcabaSMichael S. Tsirkin } 857839fcabaSMichael S. Tsirkin } 858839fcabaSMichael S. Tsirkin 8591da177e4SLinus Torvalds while ((skb = __skb_dequeue(&neigh->queue))) 8601da177e4SLinus Torvalds __skb_queue_tail(&skqueue, skb); 8611da177e4SLinus Torvalds } 862ee1e2c82SMoni Shoua path->valid = 1; 8635872a9fcSRoland Dreier } 8641da177e4SLinus Torvalds 8655872a9fcSRoland Dreier path->query = NULL; 8661da177e4SLinus Torvalds complete(&path->done); 8671da177e4SLinus Torvalds 8681da177e4SLinus Torvalds spin_unlock_irqrestore(&priv->lock, flags); 8691da177e4SLinus Torvalds 870f72dd566SRoland Dreier if (IS_ERR_OR_NULL(ah)) 871f72dd566SRoland Dreier ipoib_del_neighs_by_gid(dev, path->pathrec.dgid.raw); 872f72dd566SRoland Dreier 873ee1e2c82SMoni Shoua if (old_ah) 874ee1e2c82SMoni Shoua ipoib_put_ah(old_ah); 875ee1e2c82SMoni Shoua 8761da177e4SLinus Torvalds while ((skb = __skb_dequeue(&skqueue))) { 877d32b9a81SFeras Daoud int ret; 8781da177e4SLinus Torvalds skb->dev = dev; 879d32b9a81SFeras Daoud ret = dev_queue_xmit(skb); 880d32b9a81SFeras Daoud if (ret) 881d32b9a81SFeras Daoud ipoib_warn(priv, "%s: dev_queue_xmit failed to re-queue packet, ret:%d\n", 882d32b9a81SFeras Daoud __func__, ret); 8831da177e4SLinus Torvalds } 8841da177e4SLinus Torvalds } 8851da177e4SLinus Torvalds 88637c22a77SJack Morgenstein static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid) 8871da177e4SLinus Torvalds { 8881da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 8891da177e4SLinus Torvalds struct ipoib_path *path; 8901da177e4SLinus Torvalds 8911401b53aSJack Morgenstein if (!priv->broadcast) 8921401b53aSJack Morgenstein return NULL; 8931401b53aSJack Morgenstein 89421a38489SRoland Dreier path = kzalloc(sizeof *path, GFP_ATOMIC); 8951da177e4SLinus Torvalds if (!path) 8961da177e4SLinus Torvalds return NULL; 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds path->dev = dev; 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds skb_queue_head_init(&path->queue); 9011da177e4SLinus Torvalds 9021da177e4SLinus Torvalds INIT_LIST_HEAD(&path->neigh_list); 9031da177e4SLinus Torvalds 90437c22a77SJack Morgenstein memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid)); 9051da177e4SLinus Torvalds path->pathrec.sgid = priv->local_gid; 9061da177e4SLinus Torvalds path->pathrec.pkey = cpu_to_be16(priv->pkey); 9071da177e4SLinus Torvalds path->pathrec.numb_path = 1; 90881668838SSean Hefty path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class; 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds return path; 9111da177e4SLinus Torvalds } 9121da177e4SLinus Torvalds 9131da177e4SLinus Torvalds static int path_rec_start(struct net_device *dev, 9141da177e4SLinus Torvalds struct ipoib_path *path) 9151da177e4SLinus Torvalds { 9161da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 9171da177e4SLinus Torvalds 9185b095d98SHarvey Harrison ipoib_dbg(priv, "Start path record lookup for %pI6\n", 919fcace2feSHarvey Harrison path->pathrec.dgid.raw); 9201da177e4SLinus Torvalds 92165c7eddaSRoland Dreier init_completion(&path->done); 92265c7eddaSRoland Dreier 9231da177e4SLinus Torvalds path->query_id = 924c1a0b23bSMichael S. Tsirkin ib_sa_path_rec_get(&ipoib_sa_client, priv->ca, priv->port, 9251da177e4SLinus Torvalds &path->pathrec, 9261da177e4SLinus Torvalds IB_SA_PATH_REC_DGID | 9271da177e4SLinus Torvalds IB_SA_PATH_REC_SGID | 9281da177e4SLinus Torvalds IB_SA_PATH_REC_NUMB_PATH | 92981668838SSean Hefty IB_SA_PATH_REC_TRAFFIC_CLASS | 9301da177e4SLinus Torvalds IB_SA_PATH_REC_PKEY, 9311da177e4SLinus Torvalds 1000, GFP_ATOMIC, 9321da177e4SLinus Torvalds path_rec_completion, 9331da177e4SLinus Torvalds path, &path->query); 9341da177e4SLinus Torvalds if (path->query_id < 0) { 93501b3fc8bSOr Gerlitz ipoib_warn(priv, "ib_sa_path_rec_get failed: %d\n", path->query_id); 9361da177e4SLinus Torvalds path->query = NULL; 93793a3ab93SYossi Etigin complete(&path->done); 9381da177e4SLinus Torvalds return path->query_id; 9391da177e4SLinus Torvalds } 9401da177e4SLinus Torvalds 9411da177e4SLinus Torvalds return 0; 9421da177e4SLinus Torvalds } 9431da177e4SLinus Torvalds 944b63b70d8SShlomo Pongratz static void neigh_add_path(struct sk_buff *skb, u8 *daddr, 945b63b70d8SShlomo Pongratz struct net_device *dev) 9461da177e4SLinus Torvalds { 9471da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 9481da177e4SLinus Torvalds struct ipoib_path *path; 9491da177e4SLinus Torvalds struct ipoib_neigh *neigh; 950943c246eSRoland Dreier unsigned long flags; 9511da177e4SLinus Torvalds 952b5120a6eSShlomo Pongratz spin_lock_irqsave(&priv->lock, flags); 953b63b70d8SShlomo Pongratz neigh = ipoib_neigh_alloc(daddr, dev); 9541da177e4SLinus Torvalds if (!neigh) { 955b5120a6eSShlomo Pongratz spin_unlock_irqrestore(&priv->lock, flags); 956de903512SRoland Dreier ++dev->stats.tx_dropped; 9571da177e4SLinus Torvalds dev_kfree_skb_any(skb); 9581da177e4SLinus Torvalds return; 9591da177e4SLinus Torvalds } 9601da177e4SLinus Torvalds 961b63b70d8SShlomo Pongratz path = __path_find(dev, daddr + 4); 9621da177e4SLinus Torvalds if (!path) { 963b63b70d8SShlomo Pongratz path = path_rec_create(dev, daddr + 4); 9641da177e4SLinus Torvalds if (!path) 965d2e0655eSMichael S. Tsirkin goto err_path; 9661da177e4SLinus Torvalds 9671da177e4SLinus Torvalds __path_add(dev, path); 9681da177e4SLinus Torvalds } 9691da177e4SLinus Torvalds 9701da177e4SLinus Torvalds list_add_tail(&neigh->list, &path->neigh_list); 9711da177e4SLinus Torvalds 97247f7a071SMichael S. Tsirkin if (path->ah) { 9731da177e4SLinus Torvalds kref_get(&path->ah->ref); 9741da177e4SLinus Torvalds neigh->ah = path->ah; 9751da177e4SLinus Torvalds 976b63b70d8SShlomo Pongratz if (ipoib_cm_enabled(dev, neigh->daddr)) { 977839fcabaSMichael S. Tsirkin if (!ipoib_cm_get(neigh)) 978839fcabaSMichael S. Tsirkin ipoib_cm_set(neigh, ipoib_cm_create_tx(dev, path, neigh)); 979839fcabaSMichael S. Tsirkin if (!ipoib_cm_get(neigh)) { 980b63b70d8SShlomo Pongratz ipoib_neigh_free(neigh); 981839fcabaSMichael S. Tsirkin goto err_drop; 982839fcabaSMichael S. Tsirkin } 983fc791b63SPaolo Abeni if (skb_queue_len(&neigh->queue) < 984fc791b63SPaolo Abeni IPOIB_MAX_PATH_REC_QUEUE) { 9852b084176SErez Shitrit push_pseudo_header(skb, neigh->daddr); 986839fcabaSMichael S. Tsirkin __skb_queue_tail(&neigh->queue, skb); 987fc791b63SPaolo Abeni } else { 988839fcabaSMichael S. Tsirkin ipoib_warn(priv, "queue length limit %d. Packet drop.\n", 989839fcabaSMichael S. Tsirkin skb_queue_len(&neigh->queue)); 990839fcabaSMichael S. Tsirkin goto err_drop; 991839fcabaSMichael S. Tsirkin } 992721d67cdSRoland Dreier } else { 993721d67cdSRoland Dreier spin_unlock_irqrestore(&priv->lock, flags); 994b63b70d8SShlomo Pongratz ipoib_send(dev, skb, path->ah, IPOIB_QPN(daddr)); 995b63b70d8SShlomo Pongratz ipoib_neigh_put(neigh); 996721d67cdSRoland Dreier return; 997721d67cdSRoland Dreier } 9981da177e4SLinus Torvalds } else { 9991da177e4SLinus Torvalds neigh->ah = NULL; 10001da177e4SLinus Torvalds 10011da177e4SLinus Torvalds if (!path->query && path_rec_start(dev, path)) 100249b8e744SJim Foraker goto err_path; 10032b084176SErez Shitrit if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { 10042b084176SErez Shitrit push_pseudo_header(skb, neigh->daddr); 10052745b5b7SMichael S. Tsirkin __skb_queue_tail(&neigh->queue, skb); 10062b084176SErez Shitrit } else { 10071e85b806SErez Shitrit goto err_drop; 10081da177e4SLinus Torvalds } 10092b084176SErez Shitrit } 10101da177e4SLinus Torvalds 1011943c246eSRoland Dreier spin_unlock_irqrestore(&priv->lock, flags); 1012b63b70d8SShlomo Pongratz ipoib_neigh_put(neigh); 10131da177e4SLinus Torvalds return; 10141da177e4SLinus Torvalds 1015d2e0655eSMichael S. Tsirkin err_path: 1016b63b70d8SShlomo Pongratz ipoib_neigh_free(neigh); 1017839fcabaSMichael S. Tsirkin err_drop: 1018de903512SRoland Dreier ++dev->stats.tx_dropped; 10191da177e4SLinus Torvalds dev_kfree_skb_any(skb); 10201da177e4SLinus Torvalds 1021943c246eSRoland Dreier spin_unlock_irqrestore(&priv->lock, flags); 1022b63b70d8SShlomo Pongratz ipoib_neigh_put(neigh); 10231da177e4SLinus Torvalds } 10241da177e4SLinus Torvalds 10251da177e4SLinus Torvalds static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, 1026fc791b63SPaolo Abeni struct ipoib_pseudo_header *phdr) 10271da177e4SLinus Torvalds { 10281da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 10291da177e4SLinus Torvalds struct ipoib_path *path; 1030943c246eSRoland Dreier unsigned long flags; 10311da177e4SLinus Torvalds 1032943c246eSRoland Dreier spin_lock_irqsave(&priv->lock, flags); 10331da177e4SLinus Torvalds 1034fc791b63SPaolo Abeni path = __path_find(dev, phdr->hwaddr + 4); 1035ee1e2c82SMoni Shoua if (!path || !path->valid) { 103671d98b46SJack Morgenstein int new_path = 0; 103771d98b46SJack Morgenstein 103871d98b46SJack Morgenstein if (!path) { 1039fc791b63SPaolo Abeni path = path_rec_create(dev, phdr->hwaddr + 4); 104071d98b46SJack Morgenstein new_path = 1; 104171d98b46SJack Morgenstein } 10421da177e4SLinus Torvalds if (path) { 10431e85b806SErez Shitrit if (skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { 10442b084176SErez Shitrit push_pseudo_header(skb, phdr->hwaddr); 10451da177e4SLinus Torvalds __skb_queue_tail(&path->queue, skb); 10461e85b806SErez Shitrit } else { 10471e85b806SErez Shitrit ++dev->stats.tx_dropped; 10481e85b806SErez Shitrit dev_kfree_skb_any(skb); 10491e85b806SErez Shitrit } 10501da177e4SLinus Torvalds 1051ff79ae80SYossi Etigin if (!path->query && path_rec_start(dev, path)) { 1052943c246eSRoland Dreier spin_unlock_irqrestore(&priv->lock, flags); 105371d98b46SJack Morgenstein if (new_path) 10541da177e4SLinus Torvalds path_free(dev, path); 10551da177e4SLinus Torvalds return; 10561da177e4SLinus Torvalds } else 10571da177e4SLinus Torvalds __path_add(dev, path); 10581da177e4SLinus Torvalds } else { 1059de903512SRoland Dreier ++dev->stats.tx_dropped; 10601da177e4SLinus Torvalds dev_kfree_skb_any(skb); 10611da177e4SLinus Torvalds } 10621da177e4SLinus Torvalds 1063943c246eSRoland Dreier spin_unlock_irqrestore(&priv->lock, flags); 10641da177e4SLinus Torvalds return; 10651da177e4SLinus Torvalds } 10661da177e4SLinus Torvalds 106747f7a071SMichael S. Tsirkin if (path->ah) { 10681da177e4SLinus Torvalds ipoib_dbg(priv, "Send unicast ARP to %04x\n", 10691da177e4SLinus Torvalds be16_to_cpu(path->pathrec.dlid)); 10701da177e4SLinus Torvalds 1071721d67cdSRoland Dreier spin_unlock_irqrestore(&priv->lock, flags); 1072fc791b63SPaolo Abeni ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr)); 1073721d67cdSRoland Dreier return; 10741da177e4SLinus Torvalds } else if ((path->query || !path_rec_start(dev, path)) && 10751da177e4SLinus Torvalds skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { 10762b084176SErez Shitrit push_pseudo_header(skb, phdr->hwaddr); 10771da177e4SLinus Torvalds __skb_queue_tail(&path->queue, skb); 10781da177e4SLinus Torvalds } else { 1079de903512SRoland Dreier ++dev->stats.tx_dropped; 10801da177e4SLinus Torvalds dev_kfree_skb_any(skb); 10811da177e4SLinus Torvalds } 10821da177e4SLinus Torvalds 1083943c246eSRoland Dreier spin_unlock_irqrestore(&priv->lock, flags); 10841da177e4SLinus Torvalds } 10851da177e4SLinus Torvalds 10861da177e4SLinus Torvalds static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) 10871da177e4SLinus Torvalds { 10881da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 10891da177e4SLinus Torvalds struct ipoib_neigh *neigh; 1090fc791b63SPaolo Abeni struct ipoib_pseudo_header *phdr; 1091b63b70d8SShlomo Pongratz struct ipoib_header *header; 10921da177e4SLinus Torvalds unsigned long flags; 10931da177e4SLinus Torvalds 1094fc791b63SPaolo Abeni phdr = (struct ipoib_pseudo_header *) skb->data; 1095fc791b63SPaolo Abeni skb_pull(skb, sizeof(*phdr)); 1096b63b70d8SShlomo Pongratz header = (struct ipoib_header *) skb->data; 1097b63b70d8SShlomo Pongratz 1098fc791b63SPaolo Abeni if (unlikely(phdr->hwaddr[4] == 0xff)) { 1099b63b70d8SShlomo Pongratz /* multicast, arrange "if" according to probability */ 1100b63b70d8SShlomo Pongratz if ((header->proto != htons(ETH_P_IP)) && 1101b63b70d8SShlomo Pongratz (header->proto != htons(ETH_P_IPV6)) && 1102b63b70d8SShlomo Pongratz (header->proto != htons(ETH_P_ARP)) && 1103dc850b0eSPatrick McHardy (header->proto != htons(ETH_P_RARP)) && 1104dc850b0eSPatrick McHardy (header->proto != htons(ETH_P_TIPC))) { 1105b63b70d8SShlomo Pongratz /* ethertype not supported by IPoIB */ 110617e6abeeSDavid Miller ++dev->stats.tx_dropped; 110717e6abeeSDavid Miller dev_kfree_skb_any(skb); 1108b63b70d8SShlomo Pongratz return NETDEV_TX_OK; 110917e6abeeSDavid Miller } 1110b63b70d8SShlomo Pongratz /* Add in the P_Key for multicast*/ 1111fc791b63SPaolo Abeni phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff; 1112fc791b63SPaolo Abeni phdr->hwaddr[9] = priv->pkey & 0xff; 1113b63b70d8SShlomo Pongratz 1114fc791b63SPaolo Abeni neigh = ipoib_neigh_get(dev, phdr->hwaddr); 1115b63b70d8SShlomo Pongratz if (likely(neigh)) 1116b63b70d8SShlomo Pongratz goto send_using_neigh; 1117fc791b63SPaolo Abeni ipoib_mcast_send(dev, phdr->hwaddr, skb); 1118b63b70d8SShlomo Pongratz return NETDEV_TX_OK; 11191da177e4SLinus Torvalds } 11201da177e4SLinus Torvalds 1121b63b70d8SShlomo Pongratz /* unicast, arrange "switch" according to probability */ 1122b63b70d8SShlomo Pongratz switch (header->proto) { 1123b63b70d8SShlomo Pongratz case htons(ETH_P_IP): 1124b63b70d8SShlomo Pongratz case htons(ETH_P_IPV6): 1125dc850b0eSPatrick McHardy case htons(ETH_P_TIPC): 1126fc791b63SPaolo Abeni neigh = ipoib_neigh_get(dev, phdr->hwaddr); 1127b63b70d8SShlomo Pongratz if (unlikely(!neigh)) { 1128fc791b63SPaolo Abeni neigh_add_path(skb, phdr->hwaddr, dev); 1129b63b70d8SShlomo Pongratz return NETDEV_TX_OK; 1130b63b70d8SShlomo Pongratz } 1131b63b70d8SShlomo Pongratz break; 1132b63b70d8SShlomo Pongratz case htons(ETH_P_ARP): 1133b63b70d8SShlomo Pongratz case htons(ETH_P_RARP): 1134b63b70d8SShlomo Pongratz /* for unicast ARP and RARP should always perform path find */ 1135fc791b63SPaolo Abeni unicast_arp_send(skb, dev, phdr); 1136b63b70d8SShlomo Pongratz return NETDEV_TX_OK; 1137b63b70d8SShlomo Pongratz default: 1138b63b70d8SShlomo Pongratz /* ethertype not supported by IPoIB */ 1139b63b70d8SShlomo Pongratz ++dev->stats.tx_dropped; 1140b63b70d8SShlomo Pongratz dev_kfree_skb_any(skb); 1141b63b70d8SShlomo Pongratz return NETDEV_TX_OK; 11428a7f7521SMichael S. Tsirkin } 11438a7f7521SMichael S. Tsirkin 1144b63b70d8SShlomo Pongratz send_using_neigh: 1145b63b70d8SShlomo Pongratz /* note we now hold a ref to neigh */ 1146bafff974SOr Gerlitz if (ipoib_cm_get(neigh)) { 1147bafff974SOr Gerlitz if (ipoib_cm_up(neigh)) { 1148bafff974SOr Gerlitz ipoib_cm_send(dev, skb, ipoib_cm_get(neigh)); 1149b63b70d8SShlomo Pongratz goto unref; 1150bafff974SOr Gerlitz } 1151bafff974SOr Gerlitz } else if (neigh->ah) { 1152fc791b63SPaolo Abeni ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(phdr->hwaddr)); 1153b63b70d8SShlomo Pongratz goto unref; 11541da177e4SLinus Torvalds } 11551da177e4SLinus Torvalds 11561da177e4SLinus Torvalds if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { 11572b084176SErez Shitrit push_pseudo_header(skb, phdr->hwaddr); 1158943c246eSRoland Dreier spin_lock_irqsave(&priv->lock, flags); 11591da177e4SLinus Torvalds __skb_queue_tail(&neigh->queue, skb); 1160943c246eSRoland Dreier spin_unlock_irqrestore(&priv->lock, flags); 11611da177e4SLinus Torvalds } else { 1162de903512SRoland Dreier ++dev->stats.tx_dropped; 11631da177e4SLinus Torvalds dev_kfree_skb_any(skb); 11641da177e4SLinus Torvalds } 11651da177e4SLinus Torvalds 1166b63b70d8SShlomo Pongratz unref: 1167b63b70d8SShlomo Pongratz ipoib_neigh_put(neigh); 11681da177e4SLinus Torvalds 11691da177e4SLinus Torvalds return NETDEV_TX_OK; 11701da177e4SLinus Torvalds } 11711da177e4SLinus Torvalds 11721da177e4SLinus Torvalds static void ipoib_timeout(struct net_device *dev) 11731da177e4SLinus Torvalds { 11741da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 11751da177e4SLinus Torvalds 11764b2d319bSRoland Dreier ipoib_warn(priv, "transmit timeout: latency %d msecs\n", 11774d0e9657SFlorian Westphal jiffies_to_msecs(jiffies - dev_trans_start(dev))); 11784b2d319bSRoland Dreier ipoib_warn(priv, "queue stopped %d, tx_head %u, tx_tail %u\n", 11794b2d319bSRoland Dreier netif_queue_stopped(dev), 11804b2d319bSRoland Dreier priv->tx_head, priv->tx_tail); 11811da177e4SLinus Torvalds /* XXX reset QP, etc. */ 11821da177e4SLinus Torvalds } 11831da177e4SLinus Torvalds 11841da177e4SLinus Torvalds static int ipoib_hard_header(struct sk_buff *skb, 11851da177e4SLinus Torvalds struct net_device *dev, 11861da177e4SLinus Torvalds unsigned short type, 11873b04dddeSStephen Hemminger const void *daddr, const void *saddr, unsigned len) 11881da177e4SLinus Torvalds { 11891da177e4SLinus Torvalds struct ipoib_header *header; 11901da177e4SLinus Torvalds 11911da177e4SLinus Torvalds header = (struct ipoib_header *) skb_push(skb, sizeof *header); 11921da177e4SLinus Torvalds 11931da177e4SLinus Torvalds header->proto = htons(type); 11941da177e4SLinus Torvalds header->reserved = 0; 11951da177e4SLinus Torvalds 11961da177e4SLinus Torvalds /* 1197b63b70d8SShlomo Pongratz * we don't rely on dst_entry structure, always stuff the 1198fc791b63SPaolo Abeni * destination address into skb hard header so we can figure out where 1199936d7de3SRoland Dreier * to send the packet later. 12001da177e4SLinus Torvalds */ 12012b084176SErez Shitrit push_pseudo_header(skb, daddr); 12021da177e4SLinus Torvalds 1203fc791b63SPaolo Abeni return IPOIB_HARD_LEN; 12041da177e4SLinus Torvalds } 12051da177e4SLinus Torvalds 12061da177e4SLinus Torvalds static void ipoib_set_mcast_list(struct net_device *dev) 12071da177e4SLinus Torvalds { 12081da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 12091da177e4SLinus Torvalds 12107a343d4cSLeonid Arsh if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) { 12117a343d4cSLeonid Arsh ipoib_dbg(priv, "IPOIB_FLAG_OPER_UP not set"); 12127a343d4cSLeonid Arsh return; 12137a343d4cSLeonid Arsh } 12147a343d4cSLeonid Arsh 12150b39578bSDoug Ledford queue_work(priv->wq, &priv->restart_task); 12161da177e4SLinus Torvalds } 12171da177e4SLinus Torvalds 12185aa7add8SNicolas Dichtel static int ipoib_get_iflink(const struct net_device *dev) 12195aa7add8SNicolas Dichtel { 12205aa7add8SNicolas Dichtel struct ipoib_dev_priv *priv = netdev_priv(dev); 12215aa7add8SNicolas Dichtel 12222c153959SErez Shitrit /* parent interface */ 12232c153959SErez Shitrit if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) 12242c153959SErez Shitrit return dev->ifindex; 12252c153959SErez Shitrit 12262c153959SErez Shitrit /* child/vlan interface */ 12275aa7add8SNicolas Dichtel return priv->parent->ifindex; 12285aa7add8SNicolas Dichtel } 12295aa7add8SNicolas Dichtel 1230b63b70d8SShlomo Pongratz static u32 ipoib_addr_hash(struct ipoib_neigh_hash *htbl, u8 *daddr) 12311da177e4SLinus Torvalds { 1232b63b70d8SShlomo Pongratz /* 1233b63b70d8SShlomo Pongratz * Use only the address parts that contributes to spreading 1234b63b70d8SShlomo Pongratz * The subnet prefix is not used as one can not connect to 1235b63b70d8SShlomo Pongratz * same remote port (GUID) using the same remote QPN via two 1236b63b70d8SShlomo Pongratz * different subnets. 1237b63b70d8SShlomo Pongratz */ 1238b63b70d8SShlomo Pongratz /* qpn octets[1:4) & port GUID octets[12:20) */ 12399d1ad66eSShlomo Pongratz u32 *d32 = (u32 *) daddr; 1240b63b70d8SShlomo Pongratz u32 hv; 12411da177e4SLinus Torvalds 12429d1ad66eSShlomo Pongratz hv = jhash_3words(d32[3], d32[4], IPOIB_QPN_MASK & d32[0], 0); 1243b63b70d8SShlomo Pongratz return hv & htbl->mask; 12441da177e4SLinus Torvalds } 12451da177e4SLinus Torvalds 1246b63b70d8SShlomo Pongratz struct ipoib_neigh *ipoib_neigh_get(struct net_device *dev, u8 *daddr) 1247b63b70d8SShlomo Pongratz { 1248b63b70d8SShlomo Pongratz struct ipoib_dev_priv *priv = netdev_priv(dev); 1249b63b70d8SShlomo Pongratz struct ipoib_neigh_table *ntbl = &priv->ntbl; 1250b63b70d8SShlomo Pongratz struct ipoib_neigh_hash *htbl; 1251b63b70d8SShlomo Pongratz struct ipoib_neigh *neigh = NULL; 1252b63b70d8SShlomo Pongratz u32 hash_val; 1253b63b70d8SShlomo Pongratz 1254b63b70d8SShlomo Pongratz rcu_read_lock_bh(); 1255b63b70d8SShlomo Pongratz 1256b63b70d8SShlomo Pongratz htbl = rcu_dereference_bh(ntbl->htbl); 1257b63b70d8SShlomo Pongratz 1258b63b70d8SShlomo Pongratz if (!htbl) 1259b63b70d8SShlomo Pongratz goto out_unlock; 1260b63b70d8SShlomo Pongratz 1261b63b70d8SShlomo Pongratz hash_val = ipoib_addr_hash(htbl, daddr); 1262b63b70d8SShlomo Pongratz for (neigh = rcu_dereference_bh(htbl->buckets[hash_val]); 1263b63b70d8SShlomo Pongratz neigh != NULL; 1264b63b70d8SShlomo Pongratz neigh = rcu_dereference_bh(neigh->hnext)) { 1265b63b70d8SShlomo Pongratz if (memcmp(daddr, neigh->daddr, INFINIBAND_ALEN) == 0) { 1266b63b70d8SShlomo Pongratz /* found, take one ref on behalf of the caller */ 1267b63b70d8SShlomo Pongratz if (!atomic_inc_not_zero(&neigh->refcnt)) { 1268b63b70d8SShlomo Pongratz /* deleted */ 1269b63b70d8SShlomo Pongratz neigh = NULL; 1270b63b70d8SShlomo Pongratz goto out_unlock; 1271b63b70d8SShlomo Pongratz } 127261c78eeaSErez Shitrit 127361c78eeaSErez Shitrit if (likely(skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE)) 1274b63b70d8SShlomo Pongratz neigh->alive = jiffies; 1275b63b70d8SShlomo Pongratz goto out_unlock; 1276b63b70d8SShlomo Pongratz } 1277b63b70d8SShlomo Pongratz } 1278b63b70d8SShlomo Pongratz 1279b63b70d8SShlomo Pongratz out_unlock: 1280b63b70d8SShlomo Pongratz rcu_read_unlock_bh(); 1281b63b70d8SShlomo Pongratz return neigh; 1282b63b70d8SShlomo Pongratz } 1283b63b70d8SShlomo Pongratz 1284b63b70d8SShlomo Pongratz static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv) 1285b63b70d8SShlomo Pongratz { 1286b63b70d8SShlomo Pongratz struct ipoib_neigh_table *ntbl = &priv->ntbl; 1287b63b70d8SShlomo Pongratz struct ipoib_neigh_hash *htbl; 1288b63b70d8SShlomo Pongratz unsigned long neigh_obsolete; 1289b63b70d8SShlomo Pongratz unsigned long dt; 1290b63b70d8SShlomo Pongratz unsigned long flags; 1291b63b70d8SShlomo Pongratz int i; 1292bd99b2e0SChristoph Lameter LIST_HEAD(remove_list); 1293b63b70d8SShlomo Pongratz 1294b63b70d8SShlomo Pongratz if (test_bit(IPOIB_STOP_NEIGH_GC, &priv->flags)) 1295b63b70d8SShlomo Pongratz return; 1296b63b70d8SShlomo Pongratz 1297b5120a6eSShlomo Pongratz spin_lock_irqsave(&priv->lock, flags); 1298b63b70d8SShlomo Pongratz 1299b63b70d8SShlomo Pongratz htbl = rcu_dereference_protected(ntbl->htbl, 1300b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock)); 1301b63b70d8SShlomo Pongratz 1302b63b70d8SShlomo Pongratz if (!htbl) 1303b63b70d8SShlomo Pongratz goto out_unlock; 1304b63b70d8SShlomo Pongratz 1305b63b70d8SShlomo Pongratz /* neigh is obsolete if it was idle for two GC periods */ 1306b63b70d8SShlomo Pongratz dt = 2 * arp_tbl.gc_interval; 1307b63b70d8SShlomo Pongratz neigh_obsolete = jiffies - dt; 1308b63b70d8SShlomo Pongratz /* handle possible race condition */ 1309b63b70d8SShlomo Pongratz if (test_bit(IPOIB_STOP_NEIGH_GC, &priv->flags)) 1310b63b70d8SShlomo Pongratz goto out_unlock; 1311b63b70d8SShlomo Pongratz 1312b63b70d8SShlomo Pongratz for (i = 0; i < htbl->size; i++) { 1313b63b70d8SShlomo Pongratz struct ipoib_neigh *neigh; 1314b63b70d8SShlomo Pongratz struct ipoib_neigh __rcu **np = &htbl->buckets[i]; 1315b63b70d8SShlomo Pongratz 1316b63b70d8SShlomo Pongratz while ((neigh = rcu_dereference_protected(*np, 1317b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock))) != NULL) { 1318b63b70d8SShlomo Pongratz /* was the neigh idle for two GC periods */ 1319b63b70d8SShlomo Pongratz if (time_after(neigh_obsolete, neigh->alive)) { 1320bd99b2e0SChristoph Lameter 1321432c55ffSChristoph Lameter ipoib_check_and_add_mcast_sendonly(priv, neigh->daddr + 4, &remove_list); 1322bd99b2e0SChristoph Lameter 1323b63b70d8SShlomo Pongratz rcu_assign_pointer(*np, 1324b63b70d8SShlomo Pongratz rcu_dereference_protected(neigh->hnext, 1325b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock))); 1326b63b70d8SShlomo Pongratz /* remove from path/mc list */ 1327c586071dSFeras Daoud list_del_init(&neigh->list); 1328b63b70d8SShlomo Pongratz call_rcu(&neigh->rcu, ipoib_neigh_reclaim); 1329b63b70d8SShlomo Pongratz } else { 1330b63b70d8SShlomo Pongratz np = &neigh->hnext; 1331b63b70d8SShlomo Pongratz } 1332b63b70d8SShlomo Pongratz 1333b63b70d8SShlomo Pongratz } 1334b63b70d8SShlomo Pongratz } 1335b63b70d8SShlomo Pongratz 1336b63b70d8SShlomo Pongratz out_unlock: 1337b5120a6eSShlomo Pongratz spin_unlock_irqrestore(&priv->lock, flags); 133850be28deSErez Shitrit ipoib_mcast_remove_list(&remove_list); 1339b63b70d8SShlomo Pongratz } 1340b63b70d8SShlomo Pongratz 1341b63b70d8SShlomo Pongratz static void ipoib_reap_neigh(struct work_struct *work) 1342b63b70d8SShlomo Pongratz { 1343b63b70d8SShlomo Pongratz struct ipoib_dev_priv *priv = 1344b63b70d8SShlomo Pongratz container_of(work, struct ipoib_dev_priv, neigh_reap_task.work); 1345b63b70d8SShlomo Pongratz 1346b63b70d8SShlomo Pongratz __ipoib_reap_neigh(priv); 1347b63b70d8SShlomo Pongratz 1348b63b70d8SShlomo Pongratz if (!test_bit(IPOIB_STOP_NEIGH_GC, &priv->flags)) 13490b39578bSDoug Ledford queue_delayed_work(priv->wq, &priv->neigh_reap_task, 1350b63b70d8SShlomo Pongratz arp_tbl.gc_interval); 1351b63b70d8SShlomo Pongratz } 1352b63b70d8SShlomo Pongratz 1353b63b70d8SShlomo Pongratz 1354b63b70d8SShlomo Pongratz static struct ipoib_neigh *ipoib_neigh_ctor(u8 *daddr, 1355732a2170SMoni Shoua struct net_device *dev) 1356d2e0655eSMichael S. Tsirkin { 1357d2e0655eSMichael S. Tsirkin struct ipoib_neigh *neigh; 1358d2e0655eSMichael S. Tsirkin 1359b63b70d8SShlomo Pongratz neigh = kzalloc(sizeof *neigh, GFP_ATOMIC); 1360d2e0655eSMichael S. Tsirkin if (!neigh) 1361d2e0655eSMichael S. Tsirkin return NULL; 1362d2e0655eSMichael S. Tsirkin 1363732a2170SMoni Shoua neigh->dev = dev; 1364b63b70d8SShlomo Pongratz memcpy(&neigh->daddr, daddr, sizeof(neigh->daddr)); 136582b39913SRoland Dreier skb_queue_head_init(&neigh->queue); 1366b63b70d8SShlomo Pongratz INIT_LIST_HEAD(&neigh->list); 1367839fcabaSMichael S. Tsirkin ipoib_cm_set(neigh, NULL); 1368b63b70d8SShlomo Pongratz /* one ref on behalf of the caller */ 1369b63b70d8SShlomo Pongratz atomic_set(&neigh->refcnt, 1); 1370d2e0655eSMichael S. Tsirkin 1371d2e0655eSMichael S. Tsirkin return neigh; 1372d2e0655eSMichael S. Tsirkin } 1373d2e0655eSMichael S. Tsirkin 1374b63b70d8SShlomo Pongratz struct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr, 1375b63b70d8SShlomo Pongratz struct net_device *dev) 1376d2e0655eSMichael S. Tsirkin { 1377b63b70d8SShlomo Pongratz struct ipoib_dev_priv *priv = netdev_priv(dev); 1378b63b70d8SShlomo Pongratz struct ipoib_neigh_table *ntbl = &priv->ntbl; 1379b63b70d8SShlomo Pongratz struct ipoib_neigh_hash *htbl; 1380b63b70d8SShlomo Pongratz struct ipoib_neigh *neigh; 1381b63b70d8SShlomo Pongratz u32 hash_val; 1382b63b70d8SShlomo Pongratz 1383b63b70d8SShlomo Pongratz htbl = rcu_dereference_protected(ntbl->htbl, 1384b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock)); 1385b63b70d8SShlomo Pongratz if (!htbl) { 1386b63b70d8SShlomo Pongratz neigh = NULL; 1387b63b70d8SShlomo Pongratz goto out_unlock; 1388b63b70d8SShlomo Pongratz } 1389b63b70d8SShlomo Pongratz 1390b63b70d8SShlomo Pongratz /* need to add a new neigh, but maybe some other thread succeeded? 1391b63b70d8SShlomo Pongratz * recalc hash, maybe hash resize took place so we do a search 1392b63b70d8SShlomo Pongratz */ 1393b63b70d8SShlomo Pongratz hash_val = ipoib_addr_hash(htbl, daddr); 1394b63b70d8SShlomo Pongratz for (neigh = rcu_dereference_protected(htbl->buckets[hash_val], 1395b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock)); 1396b63b70d8SShlomo Pongratz neigh != NULL; 1397b63b70d8SShlomo Pongratz neigh = rcu_dereference_protected(neigh->hnext, 1398b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock))) { 1399b63b70d8SShlomo Pongratz if (memcmp(daddr, neigh->daddr, INFINIBAND_ALEN) == 0) { 1400b63b70d8SShlomo Pongratz /* found, take one ref on behalf of the caller */ 1401b63b70d8SShlomo Pongratz if (!atomic_inc_not_zero(&neigh->refcnt)) { 1402b63b70d8SShlomo Pongratz /* deleted */ 1403b63b70d8SShlomo Pongratz neigh = NULL; 1404b63b70d8SShlomo Pongratz break; 1405b63b70d8SShlomo Pongratz } 1406b63b70d8SShlomo Pongratz neigh->alive = jiffies; 1407b63b70d8SShlomo Pongratz goto out_unlock; 1408b63b70d8SShlomo Pongratz } 1409b63b70d8SShlomo Pongratz } 1410b63b70d8SShlomo Pongratz 1411b63b70d8SShlomo Pongratz neigh = ipoib_neigh_ctor(daddr, dev); 1412b63b70d8SShlomo Pongratz if (!neigh) 1413b63b70d8SShlomo Pongratz goto out_unlock; 1414b63b70d8SShlomo Pongratz 1415b63b70d8SShlomo Pongratz /* one ref on behalf of the hash table */ 1416b63b70d8SShlomo Pongratz atomic_inc(&neigh->refcnt); 1417b63b70d8SShlomo Pongratz neigh->alive = jiffies; 1418b63b70d8SShlomo Pongratz /* put in hash */ 1419b63b70d8SShlomo Pongratz rcu_assign_pointer(neigh->hnext, 1420b63b70d8SShlomo Pongratz rcu_dereference_protected(htbl->buckets[hash_val], 1421b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock))); 1422b63b70d8SShlomo Pongratz rcu_assign_pointer(htbl->buckets[hash_val], neigh); 1423b63b70d8SShlomo Pongratz atomic_inc(&ntbl->entries); 1424b63b70d8SShlomo Pongratz 1425b63b70d8SShlomo Pongratz out_unlock: 1426b63b70d8SShlomo Pongratz 1427b63b70d8SShlomo Pongratz return neigh; 1428b63b70d8SShlomo Pongratz } 1429b63b70d8SShlomo Pongratz 1430b63b70d8SShlomo Pongratz void ipoib_neigh_dtor(struct ipoib_neigh *neigh) 1431b63b70d8SShlomo Pongratz { 1432b63b70d8SShlomo Pongratz /* neigh reference count was dropprd to zero */ 1433b63b70d8SShlomo Pongratz struct net_device *dev = neigh->dev; 1434b63b70d8SShlomo Pongratz struct ipoib_dev_priv *priv = netdev_priv(dev); 14352745b5b7SMichael S. Tsirkin struct sk_buff *skb; 1436b63b70d8SShlomo Pongratz if (neigh->ah) 1437b63b70d8SShlomo Pongratz ipoib_put_ah(neigh->ah); 14382745b5b7SMichael S. Tsirkin while ((skb = __skb_dequeue(&neigh->queue))) { 1439de903512SRoland Dreier ++dev->stats.tx_dropped; 14402745b5b7SMichael S. Tsirkin dev_kfree_skb_any(skb); 14412745b5b7SMichael S. Tsirkin } 1442839fcabaSMichael S. Tsirkin if (ipoib_cm_get(neigh)) 1443839fcabaSMichael S. Tsirkin ipoib_cm_destroy_tx(ipoib_cm_get(neigh)); 1444b63b70d8SShlomo Pongratz ipoib_dbg(netdev_priv(dev), 1445b63b70d8SShlomo Pongratz "neigh free for %06x %pI6\n", 1446b63b70d8SShlomo Pongratz IPOIB_QPN(neigh->daddr), 1447b63b70d8SShlomo Pongratz neigh->daddr + 4); 1448d2e0655eSMichael S. Tsirkin kfree(neigh); 1449b63b70d8SShlomo Pongratz if (atomic_dec_and_test(&priv->ntbl.entries)) { 1450b63b70d8SShlomo Pongratz if (test_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags)) 1451b63b70d8SShlomo Pongratz complete(&priv->ntbl.flushed); 1452b63b70d8SShlomo Pongratz } 1453d2e0655eSMichael S. Tsirkin } 1454d2e0655eSMichael S. Tsirkin 1455b63b70d8SShlomo Pongratz static void ipoib_neigh_reclaim(struct rcu_head *rp) 14561da177e4SLinus Torvalds { 1457b63b70d8SShlomo Pongratz /* Called as a result of removal from hash table */ 1458b63b70d8SShlomo Pongratz struct ipoib_neigh *neigh = container_of(rp, struct ipoib_neigh, rcu); 1459b63b70d8SShlomo Pongratz /* note TX context may hold another ref */ 1460b63b70d8SShlomo Pongratz ipoib_neigh_put(neigh); 1461b63b70d8SShlomo Pongratz } 1462b63b70d8SShlomo Pongratz 1463b63b70d8SShlomo Pongratz void ipoib_neigh_free(struct ipoib_neigh *neigh) 1464b63b70d8SShlomo Pongratz { 1465b63b70d8SShlomo Pongratz struct net_device *dev = neigh->dev; 1466b63b70d8SShlomo Pongratz struct ipoib_dev_priv *priv = netdev_priv(dev); 1467b63b70d8SShlomo Pongratz struct ipoib_neigh_table *ntbl = &priv->ntbl; 1468b63b70d8SShlomo Pongratz struct ipoib_neigh_hash *htbl; 1469b63b70d8SShlomo Pongratz struct ipoib_neigh __rcu **np; 1470b63b70d8SShlomo Pongratz struct ipoib_neigh *n; 1471b63b70d8SShlomo Pongratz u32 hash_val; 1472b63b70d8SShlomo Pongratz 1473b63b70d8SShlomo Pongratz htbl = rcu_dereference_protected(ntbl->htbl, 1474b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock)); 1475b63b70d8SShlomo Pongratz if (!htbl) 1476b5120a6eSShlomo Pongratz return; 1477b63b70d8SShlomo Pongratz 1478b63b70d8SShlomo Pongratz hash_val = ipoib_addr_hash(htbl, neigh->daddr); 1479b63b70d8SShlomo Pongratz np = &htbl->buckets[hash_val]; 1480b63b70d8SShlomo Pongratz for (n = rcu_dereference_protected(*np, 1481b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock)); 1482b63b70d8SShlomo Pongratz n != NULL; 14836c723a68SShlomo Pongratz n = rcu_dereference_protected(*np, 1484b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock))) { 1485b63b70d8SShlomo Pongratz if (n == neigh) { 1486b63b70d8SShlomo Pongratz /* found */ 1487b63b70d8SShlomo Pongratz rcu_assign_pointer(*np, 1488b63b70d8SShlomo Pongratz rcu_dereference_protected(neigh->hnext, 1489b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock))); 149049b8e744SJim Foraker /* remove from parent list */ 1491c586071dSFeras Daoud list_del_init(&neigh->list); 1492b63b70d8SShlomo Pongratz call_rcu(&neigh->rcu, ipoib_neigh_reclaim); 1493b5120a6eSShlomo Pongratz return; 1494b63b70d8SShlomo Pongratz } else { 1495b63b70d8SShlomo Pongratz np = &n->hnext; 1496b63b70d8SShlomo Pongratz } 1497b63b70d8SShlomo Pongratz } 1498b63b70d8SShlomo Pongratz } 1499b63b70d8SShlomo Pongratz 1500b63b70d8SShlomo Pongratz static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv) 1501b63b70d8SShlomo Pongratz { 1502b63b70d8SShlomo Pongratz struct ipoib_neigh_table *ntbl = &priv->ntbl; 1503b63b70d8SShlomo Pongratz struct ipoib_neigh_hash *htbl; 150452374967SBart Van Assche struct ipoib_neigh __rcu **buckets; 1505b63b70d8SShlomo Pongratz u32 size; 1506b63b70d8SShlomo Pongratz 1507b63b70d8SShlomo Pongratz clear_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags); 1508b63b70d8SShlomo Pongratz ntbl->htbl = NULL; 1509b63b70d8SShlomo Pongratz htbl = kzalloc(sizeof(*htbl), GFP_KERNEL); 1510b63b70d8SShlomo Pongratz if (!htbl) 1511b63b70d8SShlomo Pongratz return -ENOMEM; 1512b63b70d8SShlomo Pongratz set_bit(IPOIB_STOP_NEIGH_GC, &priv->flags); 1513b63b70d8SShlomo Pongratz size = roundup_pow_of_two(arp_tbl.gc_thresh3); 1514b63b70d8SShlomo Pongratz buckets = kzalloc(size * sizeof(*buckets), GFP_KERNEL); 1515b63b70d8SShlomo Pongratz if (!buckets) { 1516b63b70d8SShlomo Pongratz kfree(htbl); 1517b63b70d8SShlomo Pongratz return -ENOMEM; 1518b63b70d8SShlomo Pongratz } 1519b63b70d8SShlomo Pongratz htbl->size = size; 1520b63b70d8SShlomo Pongratz htbl->mask = (size - 1); 1521b63b70d8SShlomo Pongratz htbl->buckets = buckets; 152252374967SBart Van Assche RCU_INIT_POINTER(ntbl->htbl, htbl); 152366172c09SShlomo Pongratz htbl->ntbl = ntbl; 1524b63b70d8SShlomo Pongratz atomic_set(&ntbl->entries, 0); 1525b63b70d8SShlomo Pongratz 1526b63b70d8SShlomo Pongratz /* start garbage collection */ 1527b63b70d8SShlomo Pongratz clear_bit(IPOIB_STOP_NEIGH_GC, &priv->flags); 15280b39578bSDoug Ledford queue_delayed_work(priv->wq, &priv->neigh_reap_task, 1529b63b70d8SShlomo Pongratz arp_tbl.gc_interval); 15301da177e4SLinus Torvalds 15311da177e4SLinus Torvalds return 0; 15321da177e4SLinus Torvalds } 15331da177e4SLinus Torvalds 1534b63b70d8SShlomo Pongratz static void neigh_hash_free_rcu(struct rcu_head *head) 1535b63b70d8SShlomo Pongratz { 1536b63b70d8SShlomo Pongratz struct ipoib_neigh_hash *htbl = container_of(head, 1537b63b70d8SShlomo Pongratz struct ipoib_neigh_hash, 1538b63b70d8SShlomo Pongratz rcu); 1539b63b70d8SShlomo Pongratz struct ipoib_neigh __rcu **buckets = htbl->buckets; 154066172c09SShlomo Pongratz struct ipoib_neigh_table *ntbl = htbl->ntbl; 1541b63b70d8SShlomo Pongratz 1542b63b70d8SShlomo Pongratz kfree(buckets); 1543b63b70d8SShlomo Pongratz kfree(htbl); 154466172c09SShlomo Pongratz complete(&ntbl->deleted); 1545b63b70d8SShlomo Pongratz } 1546b63b70d8SShlomo Pongratz 1547b63b70d8SShlomo Pongratz void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid) 1548b63b70d8SShlomo Pongratz { 1549b63b70d8SShlomo Pongratz struct ipoib_dev_priv *priv = netdev_priv(dev); 1550b63b70d8SShlomo Pongratz struct ipoib_neigh_table *ntbl = &priv->ntbl; 1551b63b70d8SShlomo Pongratz struct ipoib_neigh_hash *htbl; 1552b63b70d8SShlomo Pongratz unsigned long flags; 1553b63b70d8SShlomo Pongratz int i; 1554b63b70d8SShlomo Pongratz 1555b63b70d8SShlomo Pongratz /* remove all neigh connected to a given path or mcast */ 1556b5120a6eSShlomo Pongratz spin_lock_irqsave(&priv->lock, flags); 1557b63b70d8SShlomo Pongratz 1558b63b70d8SShlomo Pongratz htbl = rcu_dereference_protected(ntbl->htbl, 1559b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock)); 1560b63b70d8SShlomo Pongratz 1561b63b70d8SShlomo Pongratz if (!htbl) 1562b63b70d8SShlomo Pongratz goto out_unlock; 1563b63b70d8SShlomo Pongratz 1564b63b70d8SShlomo Pongratz for (i = 0; i < htbl->size; i++) { 1565b63b70d8SShlomo Pongratz struct ipoib_neigh *neigh; 1566b63b70d8SShlomo Pongratz struct ipoib_neigh __rcu **np = &htbl->buckets[i]; 1567b63b70d8SShlomo Pongratz 1568b63b70d8SShlomo Pongratz while ((neigh = rcu_dereference_protected(*np, 1569b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock))) != NULL) { 1570b63b70d8SShlomo Pongratz /* delete neighs belong to this parent */ 1571b63b70d8SShlomo Pongratz if (!memcmp(gid, neigh->daddr + 4, sizeof (union ib_gid))) { 1572b63b70d8SShlomo Pongratz rcu_assign_pointer(*np, 1573b63b70d8SShlomo Pongratz rcu_dereference_protected(neigh->hnext, 1574b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock))); 1575b63b70d8SShlomo Pongratz /* remove from parent list */ 1576c586071dSFeras Daoud list_del_init(&neigh->list); 1577b63b70d8SShlomo Pongratz call_rcu(&neigh->rcu, ipoib_neigh_reclaim); 1578b63b70d8SShlomo Pongratz } else { 1579b63b70d8SShlomo Pongratz np = &neigh->hnext; 1580b63b70d8SShlomo Pongratz } 1581b63b70d8SShlomo Pongratz 1582b63b70d8SShlomo Pongratz } 1583b63b70d8SShlomo Pongratz } 1584b63b70d8SShlomo Pongratz out_unlock: 1585b5120a6eSShlomo Pongratz spin_unlock_irqrestore(&priv->lock, flags); 1586b63b70d8SShlomo Pongratz } 1587b63b70d8SShlomo Pongratz 1588b63b70d8SShlomo Pongratz static void ipoib_flush_neighs(struct ipoib_dev_priv *priv) 1589b63b70d8SShlomo Pongratz { 1590b63b70d8SShlomo Pongratz struct ipoib_neigh_table *ntbl = &priv->ntbl; 1591b63b70d8SShlomo Pongratz struct ipoib_neigh_hash *htbl; 1592b63b70d8SShlomo Pongratz unsigned long flags; 159366172c09SShlomo Pongratz int i, wait_flushed = 0; 1594b63b70d8SShlomo Pongratz 159566172c09SShlomo Pongratz init_completion(&priv->ntbl.flushed); 1596b63b70d8SShlomo Pongratz 1597b5120a6eSShlomo Pongratz spin_lock_irqsave(&priv->lock, flags); 1598b63b70d8SShlomo Pongratz 1599b63b70d8SShlomo Pongratz htbl = rcu_dereference_protected(ntbl->htbl, 1600b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock)); 1601b63b70d8SShlomo Pongratz if (!htbl) 1602b63b70d8SShlomo Pongratz goto out_unlock; 1603b63b70d8SShlomo Pongratz 160466172c09SShlomo Pongratz wait_flushed = atomic_read(&priv->ntbl.entries); 160566172c09SShlomo Pongratz if (!wait_flushed) 160666172c09SShlomo Pongratz goto free_htbl; 160766172c09SShlomo Pongratz 1608b63b70d8SShlomo Pongratz for (i = 0; i < htbl->size; i++) { 1609b63b70d8SShlomo Pongratz struct ipoib_neigh *neigh; 1610b63b70d8SShlomo Pongratz struct ipoib_neigh __rcu **np = &htbl->buckets[i]; 1611b63b70d8SShlomo Pongratz 1612b63b70d8SShlomo Pongratz while ((neigh = rcu_dereference_protected(*np, 1613b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock))) != NULL) { 1614b63b70d8SShlomo Pongratz rcu_assign_pointer(*np, 1615b63b70d8SShlomo Pongratz rcu_dereference_protected(neigh->hnext, 1616b5120a6eSShlomo Pongratz lockdep_is_held(&priv->lock))); 1617b63b70d8SShlomo Pongratz /* remove from path/mc list */ 1618c586071dSFeras Daoud list_del_init(&neigh->list); 1619b63b70d8SShlomo Pongratz call_rcu(&neigh->rcu, ipoib_neigh_reclaim); 1620b63b70d8SShlomo Pongratz } 1621b63b70d8SShlomo Pongratz } 1622b63b70d8SShlomo Pongratz 162366172c09SShlomo Pongratz free_htbl: 1624b63b70d8SShlomo Pongratz rcu_assign_pointer(ntbl->htbl, NULL); 1625b63b70d8SShlomo Pongratz call_rcu(&htbl->rcu, neigh_hash_free_rcu); 1626b63b70d8SShlomo Pongratz 1627b63b70d8SShlomo Pongratz out_unlock: 1628b5120a6eSShlomo Pongratz spin_unlock_irqrestore(&priv->lock, flags); 162966172c09SShlomo Pongratz if (wait_flushed) 163066172c09SShlomo Pongratz wait_for_completion(&priv->ntbl.flushed); 1631b63b70d8SShlomo Pongratz } 1632b63b70d8SShlomo Pongratz 1633b63b70d8SShlomo Pongratz static void ipoib_neigh_hash_uninit(struct net_device *dev) 1634b63b70d8SShlomo Pongratz { 1635b63b70d8SShlomo Pongratz struct ipoib_dev_priv *priv = netdev_priv(dev); 1636b63b70d8SShlomo Pongratz int stopped; 1637b63b70d8SShlomo Pongratz 1638b63b70d8SShlomo Pongratz ipoib_dbg(priv, "ipoib_neigh_hash_uninit\n"); 163966172c09SShlomo Pongratz init_completion(&priv->ntbl.deleted); 1640b63b70d8SShlomo Pongratz set_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags); 1641b63b70d8SShlomo Pongratz 1642b63b70d8SShlomo Pongratz /* Stop GC if called at init fail need to cancel work */ 1643b63b70d8SShlomo Pongratz stopped = test_and_set_bit(IPOIB_STOP_NEIGH_GC, &priv->flags); 1644b63b70d8SShlomo Pongratz if (!stopped) 1645b63b70d8SShlomo Pongratz cancel_delayed_work(&priv->neigh_reap_task); 1646b63b70d8SShlomo Pongratz 1647b63b70d8SShlomo Pongratz ipoib_flush_neighs(priv); 164866172c09SShlomo Pongratz 164966172c09SShlomo Pongratz wait_for_completion(&priv->ntbl.deleted); 1650b63b70d8SShlomo Pongratz } 1651b63b70d8SShlomo Pongratz 1652b63b70d8SShlomo Pongratz 16531da177e4SLinus Torvalds int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) 16541da177e4SLinus Torvalds { 16551da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 16561da177e4SLinus Torvalds 16571da177e4SLinus Torvalds /* Allocate RX/TX "rings" to hold queued skbs */ 16580f485251SShirley Ma priv->rx_ring = kzalloc(ipoib_recvq_size * sizeof *priv->rx_ring, 16591da177e4SLinus Torvalds GFP_KERNEL); 166074226649SLeon Romanovsky if (!priv->rx_ring) 1661be7aa663SDoug Ledford goto out; 16621da177e4SLinus Torvalds 1663948579cdSJoe Perches priv->tx_ring = vzalloc(ipoib_sendq_size * sizeof *priv->tx_ring); 16641da177e4SLinus Torvalds if (!priv->tx_ring) { 16651da177e4SLinus Torvalds printk(KERN_WARNING "%s: failed to allocate TX ring (%d entries)\n", 16660f485251SShirley Ma ca->name, ipoib_sendq_size); 16671da177e4SLinus Torvalds goto out_rx_ring_cleanup; 16681da177e4SLinus Torvalds } 16691da177e4SLinus Torvalds 16701b524963SMichael S. Tsirkin /* priv->tx_head, tx_tail & tx_outstanding are already 0 */ 16711da177e4SLinus Torvalds 16721da177e4SLinus Torvalds if (ipoib_ib_dev_init(dev, ca, port)) 16731da177e4SLinus Torvalds goto out_tx_ring_cleanup; 16741da177e4SLinus Torvalds 1675be7aa663SDoug Ledford /* 1676be7aa663SDoug Ledford * Must be after ipoib_ib_dev_init so we can allocate a per 1677be7aa663SDoug Ledford * device wq there and use it here 1678be7aa663SDoug Ledford */ 1679be7aa663SDoug Ledford if (ipoib_neigh_hash_init(priv) < 0) 1680be7aa663SDoug Ledford goto out_dev_uninit; 1681be7aa663SDoug Ledford 16821da177e4SLinus Torvalds return 0; 16831da177e4SLinus Torvalds 1684be7aa663SDoug Ledford out_dev_uninit: 1685be7aa663SDoug Ledford ipoib_ib_dev_cleanup(dev); 1686be7aa663SDoug Ledford 16871da177e4SLinus Torvalds out_tx_ring_cleanup: 168810313cbbSRoland Dreier vfree(priv->tx_ring); 16891da177e4SLinus Torvalds 16901da177e4SLinus Torvalds out_rx_ring_cleanup: 16911da177e4SLinus Torvalds kfree(priv->rx_ring); 16921da177e4SLinus Torvalds 16931da177e4SLinus Torvalds out: 16941da177e4SLinus Torvalds return -ENOMEM; 16951da177e4SLinus Torvalds } 16961da177e4SLinus Torvalds 16971da177e4SLinus Torvalds void ipoib_dev_cleanup(struct net_device *dev) 16981da177e4SLinus Torvalds { 16991da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev), *cpriv, *tcpriv; 17009baa0b03SOr Gerlitz LIST_HEAD(head); 17019baa0b03SOr Gerlitz 17029baa0b03SOr Gerlitz ASSERT_RTNL(); 17031da177e4SLinus Torvalds 17041da177e4SLinus Torvalds /* Delete any child interfaces first */ 17051da177e4SLinus Torvalds list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, list) { 1706b63b70d8SShlomo Pongratz /* Stop GC on child */ 1707b63b70d8SShlomo Pongratz set_bit(IPOIB_STOP_NEIGH_GC, &cpriv->flags); 1708b63b70d8SShlomo Pongratz cancel_delayed_work(&cpriv->neigh_reap_task); 17099baa0b03SOr Gerlitz unregister_netdevice_queue(cpriv->dev, &head); 17101da177e4SLinus Torvalds } 17119baa0b03SOr Gerlitz unregister_netdevice_many(&head); 17121da177e4SLinus Torvalds 1713be7aa663SDoug Ledford /* 1714be7aa663SDoug Ledford * Must be before ipoib_ib_dev_cleanup or we delete an in use 1715be7aa663SDoug Ledford * work queue 1716be7aa663SDoug Ledford */ 1717be7aa663SDoug Ledford ipoib_neigh_hash_uninit(dev); 1718be7aa663SDoug Ledford 17191da177e4SLinus Torvalds ipoib_ib_dev_cleanup(dev); 17201da177e4SLinus Torvalds 17211da177e4SLinus Torvalds kfree(priv->rx_ring); 172210313cbbSRoland Dreier vfree(priv->tx_ring); 172392a6b34bSHal Rosenstock 172492a6b34bSHal Rosenstock priv->rx_ring = NULL; 17251da177e4SLinus Torvalds priv->tx_ring = NULL; 17261da177e4SLinus Torvalds } 17271da177e4SLinus Torvalds 17289c3c5f8eSEli Cohen static int ipoib_set_vf_link_state(struct net_device *dev, int vf, int link_state) 17299c3c5f8eSEli Cohen { 17309c3c5f8eSEli Cohen struct ipoib_dev_priv *priv = netdev_priv(dev); 17319c3c5f8eSEli Cohen 17329c3c5f8eSEli Cohen return ib_set_vf_link_state(priv->ca, vf, priv->port, link_state); 17339c3c5f8eSEli Cohen } 17349c3c5f8eSEli Cohen 17359c3c5f8eSEli Cohen static int ipoib_get_vf_config(struct net_device *dev, int vf, 17369c3c5f8eSEli Cohen struct ifla_vf_info *ivf) 17379c3c5f8eSEli Cohen { 17389c3c5f8eSEli Cohen struct ipoib_dev_priv *priv = netdev_priv(dev); 17399c3c5f8eSEli Cohen int err; 17409c3c5f8eSEli Cohen 17419c3c5f8eSEli Cohen err = ib_get_vf_config(priv->ca, vf, priv->port, ivf); 17429c3c5f8eSEli Cohen if (err) 17439c3c5f8eSEli Cohen return err; 17449c3c5f8eSEli Cohen 17459c3c5f8eSEli Cohen ivf->vf = vf; 17469c3c5f8eSEli Cohen 17479c3c5f8eSEli Cohen return 0; 17489c3c5f8eSEli Cohen } 17499c3c5f8eSEli Cohen 17509c3c5f8eSEli Cohen static int ipoib_set_vf_guid(struct net_device *dev, int vf, u64 guid, int type) 17519c3c5f8eSEli Cohen { 17529c3c5f8eSEli Cohen struct ipoib_dev_priv *priv = netdev_priv(dev); 17539c3c5f8eSEli Cohen 17549c3c5f8eSEli Cohen if (type != IFLA_VF_IB_NODE_GUID && type != IFLA_VF_IB_PORT_GUID) 17559c3c5f8eSEli Cohen return -EINVAL; 17569c3c5f8eSEli Cohen 17579c3c5f8eSEli Cohen return ib_set_vf_guid(priv->ca, vf, priv->port, guid, type); 17589c3c5f8eSEli Cohen } 17599c3c5f8eSEli Cohen 17609c3c5f8eSEli Cohen static int ipoib_get_vf_stats(struct net_device *dev, int vf, 17619c3c5f8eSEli Cohen struct ifla_vf_stats *vf_stats) 17629c3c5f8eSEli Cohen { 17639c3c5f8eSEli Cohen struct ipoib_dev_priv *priv = netdev_priv(dev); 17649c3c5f8eSEli Cohen 17659c3c5f8eSEli Cohen return ib_get_vf_stats(priv->ca, vf, priv->port, vf_stats); 17669c3c5f8eSEli Cohen } 17679c3c5f8eSEli Cohen 17683b04dddeSStephen Hemminger static const struct header_ops ipoib_header_ops = { 17693b04dddeSStephen Hemminger .create = ipoib_hard_header, 17703b04dddeSStephen Hemminger }; 17713b04dddeSStephen Hemminger 17729c3c5f8eSEli Cohen static const struct net_device_ops ipoib_netdev_ops_pf = { 17739c3c5f8eSEli Cohen .ndo_uninit = ipoib_uninit, 17749c3c5f8eSEli Cohen .ndo_open = ipoib_open, 17759c3c5f8eSEli Cohen .ndo_stop = ipoib_stop, 17769c3c5f8eSEli Cohen .ndo_change_mtu = ipoib_change_mtu, 17779c3c5f8eSEli Cohen .ndo_fix_features = ipoib_fix_features, 17789c3c5f8eSEli Cohen .ndo_start_xmit = ipoib_start_xmit, 17799c3c5f8eSEli Cohen .ndo_tx_timeout = ipoib_timeout, 17809c3c5f8eSEli Cohen .ndo_set_rx_mode = ipoib_set_mcast_list, 17819c3c5f8eSEli Cohen .ndo_get_iflink = ipoib_get_iflink, 17829c3c5f8eSEli Cohen .ndo_set_vf_link_state = ipoib_set_vf_link_state, 17839c3c5f8eSEli Cohen .ndo_get_vf_config = ipoib_get_vf_config, 17849c3c5f8eSEli Cohen .ndo_get_vf_stats = ipoib_get_vf_stats, 17859c3c5f8eSEli Cohen .ndo_set_vf_guid = ipoib_set_vf_guid, 1786492a7e67SMark Bloch .ndo_set_mac_address = ipoib_set_mac, 17879c3c5f8eSEli Cohen }; 17889c3c5f8eSEli Cohen 17899c3c5f8eSEli Cohen static const struct net_device_ops ipoib_netdev_ops_vf = { 17909baa0b03SOr Gerlitz .ndo_uninit = ipoib_uninit, 1791fe8114e8SStephen Hemminger .ndo_open = ipoib_open, 1792fe8114e8SStephen Hemminger .ndo_stop = ipoib_stop, 1793fe8114e8SStephen Hemminger .ndo_change_mtu = ipoib_change_mtu, 17943d96c74dSMichał Mirosław .ndo_fix_features = ipoib_fix_features, 1795fe8114e8SStephen Hemminger .ndo_start_xmit = ipoib_start_xmit, 1796fe8114e8SStephen Hemminger .ndo_tx_timeout = ipoib_timeout, 1797afc4b13dSJiri Pirko .ndo_set_rx_mode = ipoib_set_mcast_list, 17985aa7add8SNicolas Dichtel .ndo_get_iflink = ipoib_get_iflink, 1799fe8114e8SStephen Hemminger }; 1800fe8114e8SStephen Hemminger 18019baa0b03SOr Gerlitz void ipoib_setup(struct net_device *dev) 18021da177e4SLinus Torvalds { 18031da177e4SLinus Torvalds struct ipoib_dev_priv *priv = netdev_priv(dev); 18041da177e4SLinus Torvalds 18059c3c5f8eSEli Cohen if (priv->hca_caps & IB_DEVICE_VIRTUAL_FUNCTION) 18069c3c5f8eSEli Cohen dev->netdev_ops = &ipoib_netdev_ops_vf; 18079c3c5f8eSEli Cohen else 18089c3c5f8eSEli Cohen dev->netdev_ops = &ipoib_netdev_ops_pf; 18099c3c5f8eSEli Cohen 18103b04dddeSStephen Hemminger dev->header_ops = &ipoib_header_ops; 1811bea3348eSStephen Hemminger 181282c24c18SEli Cohen ipoib_set_ethtool_ops(dev); 181382c24c18SEli Cohen 18147f1a3867SMichal Schmidt netif_napi_add(dev, &priv->napi, ipoib_poll, NAPI_POLL_WEIGHT); 18151da177e4SLinus Torvalds 18161da177e4SLinus Torvalds dev->watchdog_timeo = HZ; 18171da177e4SLinus Torvalds 18181da177e4SLinus Torvalds dev->flags |= IFF_BROADCAST | IFF_MULTICAST; 18191da177e4SLinus Torvalds 1820fc791b63SPaolo Abeni dev->hard_header_len = IPOIB_HARD_LEN; 18211da177e4SLinus Torvalds dev->addr_len = INFINIBAND_ALEN; 18221da177e4SLinus Torvalds dev->type = ARPHRD_INFINIBAND; 18230f485251SShirley Ma dev->tx_queue_len = ipoib_sendq_size * 2; 1824eb14032fSEli Cohen dev->features = (NETIF_F_VLAN_CHALLENGED | 1825eb14032fSEli Cohen NETIF_F_HIGHDMA); 182602875878SEric Dumazet netif_keep_dst(dev); 18271da177e4SLinus Torvalds 18281da177e4SLinus Torvalds memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN); 18291da177e4SLinus Torvalds 18301da177e4SLinus Torvalds priv->dev = dev; 18311da177e4SLinus Torvalds 18321da177e4SLinus Torvalds spin_lock_init(&priv->lock); 18331da177e4SLinus Torvalds 1834f47944ccSErez Shitrit init_rwsem(&priv->vlan_rwsem); 18351da177e4SLinus Torvalds 18361da177e4SLinus Torvalds INIT_LIST_HEAD(&priv->path_list); 18371da177e4SLinus Torvalds INIT_LIST_HEAD(&priv->child_intfs); 18381da177e4SLinus Torvalds INIT_LIST_HEAD(&priv->dead_ahs); 18391da177e4SLinus Torvalds INIT_LIST_HEAD(&priv->multicast_list); 18401da177e4SLinus Torvalds 1841c4028958SDavid Howells INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task); 1842e8224e4bSYossi Etigin INIT_WORK(&priv->carrier_on_task, ipoib_mcast_carrier_on_task); 1843ee1e2c82SMoni Shoua INIT_WORK(&priv->flush_light, ipoib_ib_dev_flush_light); 1844ee1e2c82SMoni Shoua INIT_WORK(&priv->flush_normal, ipoib_ib_dev_flush_normal); 1845ee1e2c82SMoni Shoua INIT_WORK(&priv->flush_heavy, ipoib_ib_dev_flush_heavy); 1846c4028958SDavid Howells INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task); 1847c4028958SDavid Howells INIT_DELAYED_WORK(&priv->ah_reap_task, ipoib_reap_ah); 1848b63b70d8SShlomo Pongratz INIT_DELAYED_WORK(&priv->neigh_reap_task, ipoib_reap_neigh); 18491da177e4SLinus Torvalds } 18501da177e4SLinus Torvalds 18511da177e4SLinus Torvalds struct ipoib_dev_priv *ipoib_intf_alloc(const char *name) 18521da177e4SLinus Torvalds { 18531da177e4SLinus Torvalds struct net_device *dev; 18541da177e4SLinus Torvalds 18551da177e4SLinus Torvalds dev = alloc_netdev((int)sizeof(struct ipoib_dev_priv), name, 1856c835a677STom Gundersen NET_NAME_UNKNOWN, ipoib_setup); 18571da177e4SLinus Torvalds if (!dev) 18581da177e4SLinus Torvalds return NULL; 18591da177e4SLinus Torvalds 18601da177e4SLinus Torvalds return netdev_priv(dev); 18611da177e4SLinus Torvalds } 18621da177e4SLinus Torvalds 186343cb76d9SGreg Kroah-Hartman static ssize_t show_pkey(struct device *dev, 186443cb76d9SGreg Kroah-Hartman struct device_attribute *attr, char *buf) 18651da177e4SLinus Torvalds { 186643cb76d9SGreg Kroah-Hartman struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); 18671da177e4SLinus Torvalds 18681da177e4SLinus Torvalds return sprintf(buf, "0x%04x\n", priv->pkey); 18691da177e4SLinus Torvalds } 187043cb76d9SGreg Kroah-Hartman static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); 18711da177e4SLinus Torvalds 1872335a64a5SOr Gerlitz static ssize_t show_umcast(struct device *dev, 1873335a64a5SOr Gerlitz struct device_attribute *attr, char *buf) 1874335a64a5SOr Gerlitz { 1875335a64a5SOr Gerlitz struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); 1876335a64a5SOr Gerlitz 1877335a64a5SOr Gerlitz return sprintf(buf, "%d\n", test_bit(IPOIB_FLAG_UMCAST, &priv->flags)); 1878335a64a5SOr Gerlitz } 1879335a64a5SOr Gerlitz 1880862096a8SOr Gerlitz void ipoib_set_umcast(struct net_device *ndev, int umcast_val) 1881335a64a5SOr Gerlitz { 1882862096a8SOr Gerlitz struct ipoib_dev_priv *priv = netdev_priv(ndev); 1883335a64a5SOr Gerlitz 1884335a64a5SOr Gerlitz if (umcast_val > 0) { 1885335a64a5SOr Gerlitz set_bit(IPOIB_FLAG_UMCAST, &priv->flags); 1886335a64a5SOr Gerlitz ipoib_warn(priv, "ignoring multicast groups joined directly " 1887335a64a5SOr Gerlitz "by userspace\n"); 1888335a64a5SOr Gerlitz } else 1889335a64a5SOr Gerlitz clear_bit(IPOIB_FLAG_UMCAST, &priv->flags); 1890862096a8SOr Gerlitz } 1891862096a8SOr Gerlitz 1892862096a8SOr Gerlitz static ssize_t set_umcast(struct device *dev, 1893862096a8SOr Gerlitz struct device_attribute *attr, 1894862096a8SOr Gerlitz const char *buf, size_t count) 1895862096a8SOr Gerlitz { 1896862096a8SOr Gerlitz unsigned long umcast_val = simple_strtoul(buf, NULL, 0); 1897862096a8SOr Gerlitz 1898862096a8SOr Gerlitz ipoib_set_umcast(to_net_dev(dev), umcast_val); 1899335a64a5SOr Gerlitz 1900335a64a5SOr Gerlitz return count; 1901335a64a5SOr Gerlitz } 1902335a64a5SOr Gerlitz static DEVICE_ATTR(umcast, S_IWUSR | S_IRUGO, show_umcast, set_umcast); 1903335a64a5SOr Gerlitz 1904335a64a5SOr Gerlitz int ipoib_add_umcast_attr(struct net_device *dev) 1905335a64a5SOr Gerlitz { 1906335a64a5SOr Gerlitz return device_create_file(&dev->dev, &dev_attr_umcast); 1907335a64a5SOr Gerlitz } 1908335a64a5SOr Gerlitz 1909492a7e67SMark Bloch static void set_base_guid(struct ipoib_dev_priv *priv, union ib_gid *gid) 1910492a7e67SMark Bloch { 1911492a7e67SMark Bloch struct ipoib_dev_priv *child_priv; 1912492a7e67SMark Bloch struct net_device *netdev = priv->dev; 1913492a7e67SMark Bloch 19149b29953bSMark Bloch netif_addr_lock_bh(netdev); 1915492a7e67SMark Bloch 1916492a7e67SMark Bloch memcpy(&priv->local_gid.global.interface_id, 1917492a7e67SMark Bloch &gid->global.interface_id, 1918492a7e67SMark Bloch sizeof(gid->global.interface_id)); 1919492a7e67SMark Bloch memcpy(netdev->dev_addr + 4, &priv->local_gid, sizeof(priv->local_gid)); 1920492a7e67SMark Bloch clear_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags); 1921492a7e67SMark Bloch 19229b29953bSMark Bloch netif_addr_unlock_bh(netdev); 1923492a7e67SMark Bloch 1924492a7e67SMark Bloch if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { 1925492a7e67SMark Bloch down_read(&priv->vlan_rwsem); 1926492a7e67SMark Bloch list_for_each_entry(child_priv, &priv->child_intfs, list) 1927492a7e67SMark Bloch set_base_guid(child_priv, gid); 1928492a7e67SMark Bloch up_read(&priv->vlan_rwsem); 1929492a7e67SMark Bloch } 1930492a7e67SMark Bloch } 1931492a7e67SMark Bloch 1932492a7e67SMark Bloch static int ipoib_check_lladdr(struct net_device *dev, 1933492a7e67SMark Bloch struct sockaddr_storage *ss) 1934492a7e67SMark Bloch { 1935492a7e67SMark Bloch union ib_gid *gid = (union ib_gid *)(ss->__data + 4); 1936492a7e67SMark Bloch int ret = 0; 1937492a7e67SMark Bloch 19389b29953bSMark Bloch netif_addr_lock_bh(dev); 1939492a7e67SMark Bloch 1940492a7e67SMark Bloch /* Make sure the QPN, reserved and subnet prefix match the current 1941492a7e67SMark Bloch * lladdr, it also makes sure the lladdr is unicast. 1942492a7e67SMark Bloch */ 1943492a7e67SMark Bloch if (memcmp(dev->dev_addr, ss->__data, 1944492a7e67SMark Bloch 4 + sizeof(gid->global.subnet_prefix)) || 1945492a7e67SMark Bloch gid->global.interface_id == 0) 1946492a7e67SMark Bloch ret = -EINVAL; 1947492a7e67SMark Bloch 19489b29953bSMark Bloch netif_addr_unlock_bh(dev); 1949492a7e67SMark Bloch 1950492a7e67SMark Bloch return ret; 1951492a7e67SMark Bloch } 1952492a7e67SMark Bloch 1953492a7e67SMark Bloch static int ipoib_set_mac(struct net_device *dev, void *addr) 1954492a7e67SMark Bloch { 1955492a7e67SMark Bloch struct ipoib_dev_priv *priv = netdev_priv(dev); 1956492a7e67SMark Bloch struct sockaddr_storage *ss = addr; 1957492a7e67SMark Bloch int ret; 1958492a7e67SMark Bloch 1959492a7e67SMark Bloch if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev)) 1960492a7e67SMark Bloch return -EBUSY; 1961492a7e67SMark Bloch 1962492a7e67SMark Bloch ret = ipoib_check_lladdr(dev, ss); 1963492a7e67SMark Bloch if (ret) 1964492a7e67SMark Bloch return ret; 1965492a7e67SMark Bloch 1966492a7e67SMark Bloch set_base_guid(priv, (union ib_gid *)(ss->__data + 4)); 1967492a7e67SMark Bloch 1968492a7e67SMark Bloch queue_work(ipoib_workqueue, &priv->flush_light); 1969492a7e67SMark Bloch 1970492a7e67SMark Bloch return 0; 1971492a7e67SMark Bloch } 1972492a7e67SMark Bloch 197343cb76d9SGreg Kroah-Hartman static ssize_t create_child(struct device *dev, 197443cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 19751da177e4SLinus Torvalds const char *buf, size_t count) 19761da177e4SLinus Torvalds { 19771da177e4SLinus Torvalds int pkey; 19781da177e4SLinus Torvalds int ret; 19791da177e4SLinus Torvalds 19801da177e4SLinus Torvalds if (sscanf(buf, "%i", &pkey) != 1) 19811da177e4SLinus Torvalds return -EINVAL; 19821da177e4SLinus Torvalds 19833d790a4cSOr Gerlitz if (pkey <= 0 || pkey > 0xffff || pkey == 0x8000) 19841da177e4SLinus Torvalds return -EINVAL; 19851da177e4SLinus Torvalds 19864ce05937SRoland Dreier /* 19874ce05937SRoland Dreier * Set the full membership bit, so that we join the right 19884ce05937SRoland Dreier * broadcast group, etc. 19894ce05937SRoland Dreier */ 19904ce05937SRoland Dreier pkey |= 0x8000; 19914ce05937SRoland Dreier 199243cb76d9SGreg Kroah-Hartman ret = ipoib_vlan_add(to_net_dev(dev), pkey); 19931da177e4SLinus Torvalds 19941da177e4SLinus Torvalds return ret ? ret : count; 19951da177e4SLinus Torvalds } 19967a52b34bSOr Gerlitz static DEVICE_ATTR(create_child, S_IWUSR, NULL, create_child); 19971da177e4SLinus Torvalds 199843cb76d9SGreg Kroah-Hartman static ssize_t delete_child(struct device *dev, 199943cb76d9SGreg Kroah-Hartman struct device_attribute *attr, 20001da177e4SLinus Torvalds const char *buf, size_t count) 20011da177e4SLinus Torvalds { 20021da177e4SLinus Torvalds int pkey; 20031da177e4SLinus Torvalds int ret; 20041da177e4SLinus Torvalds 20051da177e4SLinus Torvalds if (sscanf(buf, "%i", &pkey) != 1) 20061da177e4SLinus Torvalds return -EINVAL; 20071da177e4SLinus Torvalds 20081da177e4SLinus Torvalds if (pkey < 0 || pkey > 0xffff) 20091da177e4SLinus Torvalds return -EINVAL; 20101da177e4SLinus Torvalds 201143cb76d9SGreg Kroah-Hartman ret = ipoib_vlan_delete(to_net_dev(dev), pkey); 20121da177e4SLinus Torvalds 20131da177e4SLinus Torvalds return ret ? ret : count; 20141da177e4SLinus Torvalds 20151da177e4SLinus Torvalds } 20167a52b34bSOr Gerlitz static DEVICE_ATTR(delete_child, S_IWUSR, NULL, delete_child); 20171da177e4SLinus Torvalds 20181da177e4SLinus Torvalds int ipoib_add_pkey_attr(struct net_device *dev) 20191da177e4SLinus Torvalds { 202043cb76d9SGreg Kroah-Hartman return device_create_file(&dev->dev, &dev_attr_pkey); 20211da177e4SLinus Torvalds } 20221da177e4SLinus Torvalds 2023f7534f45SZhu Yanjun void ipoib_set_dev_features(struct ipoib_dev_priv *priv, struct ib_device *hca) 202483bb63f6SOr Gerlitz { 20254a061b28SOr Gerlitz priv->hca_caps = hca->attrs.device_cap_flags; 202683bb63f6SOr Gerlitz 202783bb63f6SOr Gerlitz if (priv->hca_caps & IB_DEVICE_UD_IP_CSUM) { 20285faba546SYuval Shaia priv->dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM; 20293d96c74dSMichał Mirosław 20303d96c74dSMichał Mirosław if (priv->hca_caps & IB_DEVICE_UD_TSO) 20313d96c74dSMichał Mirosław priv->dev->hw_features |= NETIF_F_TSO; 20323d96c74dSMichał Mirosław 20333d96c74dSMichał Mirosław priv->dev->features |= priv->dev->hw_features; 203483bb63f6SOr Gerlitz } 203583bb63f6SOr Gerlitz } 203683bb63f6SOr Gerlitz 20371da177e4SLinus Torvalds static struct net_device *ipoib_add_port(const char *format, 20381da177e4SLinus Torvalds struct ib_device *hca, u8 port) 20391da177e4SLinus Torvalds { 20401da177e4SLinus Torvalds struct ipoib_dev_priv *priv; 2041bc7b3a36SShirley Ma struct ib_port_attr attr; 20421da177e4SLinus Torvalds int result = -ENOMEM; 20431da177e4SLinus Torvalds 20441da177e4SLinus Torvalds priv = ipoib_intf_alloc(format); 20451da177e4SLinus Torvalds if (!priv) 20461da177e4SLinus Torvalds goto alloc_mem_failed; 20471da177e4SLinus Torvalds 2048db97ed0aSBart Van Assche SET_NETDEV_DEV(priv->dev, hca->dev.parent); 2049c3aa9b18SEli Cohen priv->dev->dev_id = port - 1; 20501da177e4SLinus Torvalds 205158e9cc90SAmir Vadai result = ib_query_port(hca, port, &attr); 205258e9cc90SAmir Vadai if (!result) 2053bc7b3a36SShirley Ma priv->max_ib_mtu = ib_mtu_enum_to_int(attr.max_mtu); 2054bc7b3a36SShirley Ma else { 2055bc7b3a36SShirley Ma printk(KERN_WARNING "%s: ib_query_port %d failed\n", 2056bc7b3a36SShirley Ma hca->name, port); 2057bc7b3a36SShirley Ma goto device_init_failed; 2058bc7b3a36SShirley Ma } 2059bc7b3a36SShirley Ma 2060bc7b3a36SShirley Ma /* MTU will be reset when mcast join happens */ 2061bc7b3a36SShirley Ma priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu); 2062bc7b3a36SShirley Ma priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu; 2063b3e3893eSJarod Wilson priv->dev->max_mtu = IPOIB_CM_MTU; 2064bc7b3a36SShirley Ma 2065596b9b68SDavid Miller priv->dev->neigh_priv_len = sizeof(struct ipoib_neigh); 2066596b9b68SDavid Miller 20671da177e4SLinus Torvalds result = ib_query_pkey(hca, port, 0, &priv->pkey); 20681da177e4SLinus Torvalds if (result) { 20691da177e4SLinus Torvalds printk(KERN_WARNING "%s: ib_query_pkey port %d failed (ret = %d)\n", 20701da177e4SLinus Torvalds hca->name, port, result); 2071ca6de177SEli Cohen goto device_init_failed; 20721da177e4SLinus Torvalds } 20731da177e4SLinus Torvalds 2074f7534f45SZhu Yanjun ipoib_set_dev_features(priv, hca); 2075af40da89SVladimir Sokolovsky 20764ce05937SRoland Dreier /* 20774ce05937SRoland Dreier * Set the full membership bit, so that we join the right 20784ce05937SRoland Dreier * broadcast group, etc. 20794ce05937SRoland Dreier */ 20804ce05937SRoland Dreier priv->pkey |= 0x8000; 20814ce05937SRoland Dreier 20821da177e4SLinus Torvalds priv->dev->broadcast[8] = priv->pkey >> 8; 20831da177e4SLinus Torvalds priv->dev->broadcast[9] = priv->pkey & 0xff; 20841da177e4SLinus Torvalds 208555ee3ab2SMatan Barak result = ib_query_gid(hca, port, 0, &priv->local_gid, NULL); 20861da177e4SLinus Torvalds if (result) { 20871da177e4SLinus Torvalds printk(KERN_WARNING "%s: ib_query_gid port %d failed (ret = %d)\n", 20881da177e4SLinus Torvalds hca->name, port, result); 2089ca6de177SEli Cohen goto device_init_failed; 20901da177e4SLinus Torvalds } else 20911da177e4SLinus Torvalds memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid)); 2092492a7e67SMark Bloch set_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags); 20931da177e4SLinus Torvalds 20941da177e4SLinus Torvalds result = ipoib_dev_init(priv->dev, hca, port); 20951da177e4SLinus Torvalds if (result < 0) { 20961da177e4SLinus Torvalds printk(KERN_WARNING "%s: failed to initialize port %d (ret = %d)\n", 20971da177e4SLinus Torvalds hca->name, port, result); 20981da177e4SLinus Torvalds goto device_init_failed; 20991da177e4SLinus Torvalds } 21001da177e4SLinus Torvalds 21011da177e4SLinus Torvalds INIT_IB_EVENT_HANDLER(&priv->event_handler, 21021da177e4SLinus Torvalds priv->ca, ipoib_event); 21031da177e4SLinus Torvalds result = ib_register_event_handler(&priv->event_handler); 21041da177e4SLinus Torvalds if (result < 0) { 21051da177e4SLinus Torvalds printk(KERN_WARNING "%s: ib_register_event_handler failed for " 21061da177e4SLinus Torvalds "port %d (ret = %d)\n", 21071da177e4SLinus Torvalds hca->name, port, result); 21081da177e4SLinus Torvalds goto event_failed; 21091da177e4SLinus Torvalds } 21101da177e4SLinus Torvalds 21111da177e4SLinus Torvalds result = register_netdev(priv->dev); 21121da177e4SLinus Torvalds if (result) { 21131da177e4SLinus Torvalds printk(KERN_WARNING "%s: couldn't register ipoib port %d; error %d\n", 21141da177e4SLinus Torvalds hca->name, port, result); 21151da177e4SLinus Torvalds goto register_failed; 21161da177e4SLinus Torvalds } 21171da177e4SLinus Torvalds 2118839fcabaSMichael S. Tsirkin if (ipoib_cm_add_mode_attr(priv->dev)) 2119839fcabaSMichael S. Tsirkin goto sysfs_failed; 21201da177e4SLinus Torvalds if (ipoib_add_pkey_attr(priv->dev)) 21211da177e4SLinus Torvalds goto sysfs_failed; 2122335a64a5SOr Gerlitz if (ipoib_add_umcast_attr(priv->dev)) 2123335a64a5SOr Gerlitz goto sysfs_failed; 212443cb76d9SGreg Kroah-Hartman if (device_create_file(&priv->dev->dev, &dev_attr_create_child)) 21251da177e4SLinus Torvalds goto sysfs_failed; 212643cb76d9SGreg Kroah-Hartman if (device_create_file(&priv->dev->dev, &dev_attr_delete_child)) 21271da177e4SLinus Torvalds goto sysfs_failed; 21281da177e4SLinus Torvalds 21291da177e4SLinus Torvalds return priv->dev; 21301da177e4SLinus Torvalds 21311da177e4SLinus Torvalds sysfs_failed: 21321da177e4SLinus Torvalds unregister_netdev(priv->dev); 21331da177e4SLinus Torvalds 21341da177e4SLinus Torvalds register_failed: 21351da177e4SLinus Torvalds ib_unregister_event_handler(&priv->event_handler); 21360b39578bSDoug Ledford flush_workqueue(ipoib_workqueue); 2137b63b70d8SShlomo Pongratz /* Stop GC if started before flush */ 2138b63b70d8SShlomo Pongratz set_bit(IPOIB_STOP_NEIGH_GC, &priv->flags); 2139b63b70d8SShlomo Pongratz cancel_delayed_work(&priv->neigh_reap_task); 21400b39578bSDoug Ledford flush_workqueue(priv->wq); 21411da177e4SLinus Torvalds 21421da177e4SLinus Torvalds event_failed: 21431da177e4SLinus Torvalds ipoib_dev_cleanup(priv->dev); 21441da177e4SLinus Torvalds 21451da177e4SLinus Torvalds device_init_failed: 21461da177e4SLinus Torvalds free_netdev(priv->dev); 21471da177e4SLinus Torvalds 21481da177e4SLinus Torvalds alloc_mem_failed: 21491da177e4SLinus Torvalds return ERR_PTR(result); 21501da177e4SLinus Torvalds } 21511da177e4SLinus Torvalds 21521da177e4SLinus Torvalds static void ipoib_add_one(struct ib_device *device) 21531da177e4SLinus Torvalds { 21541da177e4SLinus Torvalds struct list_head *dev_list; 21551da177e4SLinus Torvalds struct net_device *dev; 21561da177e4SLinus Torvalds struct ipoib_dev_priv *priv; 21574139032bSHal Rosenstock int p; 21588e37ab68SMichael Wang int count = 0; 215907ebafbaSTom Tucker 21601da177e4SLinus Torvalds dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL); 21611da177e4SLinus Torvalds if (!dev_list) 21621da177e4SLinus Torvalds return; 21631da177e4SLinus Torvalds 21641da177e4SLinus Torvalds INIT_LIST_HEAD(dev_list); 21651da177e4SLinus Torvalds 21664139032bSHal Rosenstock for (p = rdma_start_port(device); p <= rdma_end_port(device); ++p) { 21678e37ab68SMichael Wang if (!rdma_protocol_ib(device, p)) 21687b4c8769SEli Cohen continue; 21691da177e4SLinus Torvalds dev = ipoib_add_port("ib%d", device, p); 21701da177e4SLinus Torvalds if (!IS_ERR(dev)) { 21711da177e4SLinus Torvalds priv = netdev_priv(dev); 21721da177e4SLinus Torvalds list_add_tail(&priv->list, dev_list); 21738e37ab68SMichael Wang count++; 21741da177e4SLinus Torvalds } 21751da177e4SLinus Torvalds } 21761da177e4SLinus Torvalds 21778e37ab68SMichael Wang if (!count) { 21788e37ab68SMichael Wang kfree(dev_list); 21798e37ab68SMichael Wang return; 21808e37ab68SMichael Wang } 21818e37ab68SMichael Wang 21821da177e4SLinus Torvalds ib_set_client_data(device, &ipoib_client, dev_list); 21831da177e4SLinus Torvalds } 21841da177e4SLinus Torvalds 21857c1eb45aSHaggai Eran static void ipoib_remove_one(struct ib_device *device, void *client_data) 21861da177e4SLinus Torvalds { 21871da177e4SLinus Torvalds struct ipoib_dev_priv *priv, *tmp; 21887c1eb45aSHaggai Eran struct list_head *dev_list = client_data; 21891da177e4SLinus Torvalds 21905a2815f0SItai Garbi if (!dev_list) 21915a2815f0SItai Garbi return; 21921da177e4SLinus Torvalds 21931da177e4SLinus Torvalds list_for_each_entry_safe(priv, tmp, dev_list, list) { 21941da177e4SLinus Torvalds ib_unregister_event_handler(&priv->event_handler); 21950b39578bSDoug Ledford flush_workqueue(ipoib_workqueue); 2196a77a57a1SRoland Dreier 2197198b12f7SErez Shitrit /* mark interface in the middle of destruction */ 2198198b12f7SErez Shitrit set_bit(IPOIB_FLAG_GOING_DOWN, &priv->flags); 2199198b12f7SErez Shitrit 2200a77a57a1SRoland Dreier rtnl_lock(); 2201a77a57a1SRoland Dreier dev_change_flags(priv->dev, priv->dev->flags & ~IFF_UP); 2202a77a57a1SRoland Dreier rtnl_unlock(); 2203a77a57a1SRoland Dreier 2204b63b70d8SShlomo Pongratz /* Stop GC */ 2205b63b70d8SShlomo Pongratz set_bit(IPOIB_STOP_NEIGH_GC, &priv->flags); 2206b63b70d8SShlomo Pongratz cancel_delayed_work(&priv->neigh_reap_task); 22070b39578bSDoug Ledford flush_workqueue(priv->wq); 22081da177e4SLinus Torvalds 22091da177e4SLinus Torvalds unregister_netdev(priv->dev); 22101da177e4SLinus Torvalds free_netdev(priv->dev); 22111da177e4SLinus Torvalds } 221206c56e44SMichael S. Tsirkin 221306c56e44SMichael S. Tsirkin kfree(dev_list); 22141da177e4SLinus Torvalds } 22151da177e4SLinus Torvalds 2216771a5258SShamir Rabinovitch #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 2217771a5258SShamir Rabinovitch static struct notifier_block ipoib_netdev_notifier = { 2218771a5258SShamir Rabinovitch .notifier_call = ipoib_netdev_event, 2219771a5258SShamir Rabinovitch }; 2220771a5258SShamir Rabinovitch #endif 2221771a5258SShamir Rabinovitch 22221da177e4SLinus Torvalds static int __init ipoib_init_module(void) 22231da177e4SLinus Torvalds { 22241da177e4SLinus Torvalds int ret; 22251da177e4SLinus Torvalds 22260f485251SShirley Ma ipoib_recvq_size = roundup_pow_of_two(ipoib_recvq_size); 22270f485251SShirley Ma ipoib_recvq_size = min(ipoib_recvq_size, IPOIB_MAX_QUEUE_SIZE); 22280f485251SShirley Ma ipoib_recvq_size = max(ipoib_recvq_size, IPOIB_MIN_QUEUE_SIZE); 22290f485251SShirley Ma 22300f485251SShirley Ma ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size); 22310f485251SShirley Ma ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE); 2232732eacc0SHagen Paul Pfeifer ipoib_sendq_size = max3(ipoib_sendq_size, 2 * MAX_SEND_CQE, IPOIB_MIN_QUEUE_SIZE); 223368e995a2SPradeep Satyanarayana #ifdef CONFIG_INFINIBAND_IPOIB_CM 223468e995a2SPradeep Satyanarayana ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP); 223568e995a2SPradeep Satyanarayana #endif 22360f485251SShirley Ma 2237f89271daSEli Cohen /* 2238f89271daSEli Cohen * When copying small received packets, we only copy from the 2239f89271daSEli Cohen * linear data part of the SKB, so we rely on this condition. 2240f89271daSEli Cohen */ 2241f89271daSEli Cohen BUILD_BUG_ON(IPOIB_CM_COPYBREAK > IPOIB_CM_HEAD_SIZE); 2242f89271daSEli Cohen 22431da177e4SLinus Torvalds ret = ipoib_register_debugfs(); 22441da177e4SLinus Torvalds if (ret) 22451da177e4SLinus Torvalds return ret; 22461da177e4SLinus Torvalds 22471da177e4SLinus Torvalds /* 22480b39578bSDoug Ledford * We create a global workqueue here that is used for all flush 22490b39578bSDoug Ledford * operations. However, if you attempt to flush a workqueue 22500b39578bSDoug Ledford * from a task on that same workqueue, it deadlocks the system. 22510b39578bSDoug Ledford * We want to be able to flush the tasks associated with a 22520b39578bSDoug Ledford * specific net device, so we also create a workqueue for each 22530b39578bSDoug Ledford * netdevice. We queue up the tasks for that device only on 22540b39578bSDoug Ledford * its private workqueue, and we only queue up flush events 22550b39578bSDoug Ledford * on our global flush workqueue. This avoids the deadlocks. 22561da177e4SLinus Torvalds */ 2257855cda68SBhaktipriya Shridhar ipoib_workqueue = alloc_ordered_workqueue("ipoib_flush", 2258855cda68SBhaktipriya Shridhar WQ_MEM_RECLAIM); 22591da177e4SLinus Torvalds if (!ipoib_workqueue) { 22601da177e4SLinus Torvalds ret = -ENOMEM; 22611da177e4SLinus Torvalds goto err_fs; 22621da177e4SLinus Torvalds } 22631da177e4SLinus Torvalds 2264c1a0b23bSMichael S. Tsirkin ib_sa_register_client(&ipoib_sa_client); 2265c1a0b23bSMichael S. Tsirkin 22661da177e4SLinus Torvalds ret = ib_register_client(&ipoib_client); 22671da177e4SLinus Torvalds if (ret) 2268c1a0b23bSMichael S. Tsirkin goto err_sa; 22691da177e4SLinus Torvalds 22709baa0b03SOr Gerlitz ret = ipoib_netlink_init(); 22719baa0b03SOr Gerlitz if (ret) 22729baa0b03SOr Gerlitz goto err_client; 22739baa0b03SOr Gerlitz 2274771a5258SShamir Rabinovitch #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 2275771a5258SShamir Rabinovitch register_netdevice_notifier(&ipoib_netdev_notifier); 2276771a5258SShamir Rabinovitch #endif 22771da177e4SLinus Torvalds return 0; 22781da177e4SLinus Torvalds 22799baa0b03SOr Gerlitz err_client: 22809baa0b03SOr Gerlitz ib_unregister_client(&ipoib_client); 22819baa0b03SOr Gerlitz 2282c1a0b23bSMichael S. Tsirkin err_sa: 2283c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&ipoib_sa_client); 22841da177e4SLinus Torvalds destroy_workqueue(ipoib_workqueue); 22851da177e4SLinus Torvalds 22869adec1a8SRoland Dreier err_fs: 22879adec1a8SRoland Dreier ipoib_unregister_debugfs(); 22889adec1a8SRoland Dreier 22891da177e4SLinus Torvalds return ret; 22901da177e4SLinus Torvalds } 22911da177e4SLinus Torvalds 22921da177e4SLinus Torvalds static void __exit ipoib_cleanup_module(void) 22931da177e4SLinus Torvalds { 2294771a5258SShamir Rabinovitch #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 2295771a5258SShamir Rabinovitch unregister_netdevice_notifier(&ipoib_netdev_notifier); 2296771a5258SShamir Rabinovitch #endif 22979baa0b03SOr Gerlitz ipoib_netlink_fini(); 22981da177e4SLinus Torvalds ib_unregister_client(&ipoib_client); 2299c1a0b23bSMichael S. Tsirkin ib_sa_unregister_client(&ipoib_sa_client); 23009adec1a8SRoland Dreier ipoib_unregister_debugfs(); 23011da177e4SLinus Torvalds destroy_workqueue(ipoib_workqueue); 23021da177e4SLinus Torvalds } 23031da177e4SLinus Torvalds 23041da177e4SLinus Torvalds module_init(ipoib_init_module); 23051da177e4SLinus Torvalds module_exit(ipoib_cleanup_module); 2306