18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2004 Topspin Communications. All rights reserved. 38c2ecf20Sopenharmony_ci * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 48c2ecf20Sopenharmony_ci * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 78c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 88c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 98c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 108c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 138c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 148c2ecf20Sopenharmony_ci * conditions are met: 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 178c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 188c2ecf20Sopenharmony_ci * disclaimer. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 218c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 228c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 238c2ecf20Sopenharmony_ci * provided with the distribution. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 268c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 278c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 288c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 298c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 308c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 318c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 328c2ecf20Sopenharmony_ci * SOFTWARE. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "ipoib.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/module.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include <linux/init.h> 408c2ecf20Sopenharmony_ci#include <linux/slab.h> 418c2ecf20Sopenharmony_ci#include <linux/kernel.h> 428c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include <linux/if_arp.h> /* For ARPHRD_xxx */ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#include <linux/ip.h> 478c2ecf20Sopenharmony_ci#include <linux/in.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include <linux/jhash.h> 508c2ecf20Sopenharmony_ci#include <net/arp.h> 518c2ecf20Sopenharmony_ci#include <net/addrconf.h> 528c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> 538c2ecf20Sopenharmony_ci#include <rdma/ib_cache.h> 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ciMODULE_AUTHOR("Roland Dreier"); 568c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IP-over-InfiniBand net driver"); 578c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ciint ipoib_sendq_size __read_mostly = IPOIB_TX_RING_SIZE; 608c2ecf20Sopenharmony_ciint ipoib_recvq_size __read_mostly = IPOIB_RX_RING_SIZE; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cimodule_param_named(send_queue_size, ipoib_sendq_size, int, 0444); 638c2ecf20Sopenharmony_ciMODULE_PARM_DESC(send_queue_size, "Number of descriptors in send queue"); 648c2ecf20Sopenharmony_cimodule_param_named(recv_queue_size, ipoib_recvq_size, int, 0444); 658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(recv_queue_size, "Number of descriptors in receive queue"); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 688c2ecf20Sopenharmony_ciint ipoib_debug_level; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cimodule_param_named(debug_level, ipoib_debug_level, int, 0644); 718c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); 728c2ecf20Sopenharmony_ci#endif 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistruct ipoib_path_iter { 758c2ecf20Sopenharmony_ci struct net_device *dev; 768c2ecf20Sopenharmony_ci struct ipoib_path path; 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic const u8 ipv4_bcast_addr[] = { 808c2ecf20Sopenharmony_ci 0x00, 0xff, 0xff, 0xff, 818c2ecf20Sopenharmony_ci 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, 828c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistruct workqueue_struct *ipoib_workqueue; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistruct ib_sa_client ipoib_sa_client; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic int ipoib_add_one(struct ib_device *device); 908c2ecf20Sopenharmony_cistatic void ipoib_remove_one(struct ib_device *device, void *client_data); 918c2ecf20Sopenharmony_cistatic void ipoib_neigh_reclaim(struct rcu_head *rp); 928c2ecf20Sopenharmony_cistatic struct net_device *ipoib_get_net_dev_by_params( 938c2ecf20Sopenharmony_ci struct ib_device *dev, u8 port, u16 pkey, 948c2ecf20Sopenharmony_ci const union ib_gid *gid, const struct sockaddr *addr, 958c2ecf20Sopenharmony_ci void *client_data); 968c2ecf20Sopenharmony_cistatic int ipoib_set_mac(struct net_device *dev, void *addr); 978c2ecf20Sopenharmony_cistatic int ipoib_ioctl(struct net_device *dev, struct ifreq *ifr, 988c2ecf20Sopenharmony_ci int cmd); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic struct ib_client ipoib_client = { 1018c2ecf20Sopenharmony_ci .name = "ipoib", 1028c2ecf20Sopenharmony_ci .add = ipoib_add_one, 1038c2ecf20Sopenharmony_ci .remove = ipoib_remove_one, 1048c2ecf20Sopenharmony_ci .get_net_dev_by_params = ipoib_get_net_dev_by_params, 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 1088c2ecf20Sopenharmony_cistatic int ipoib_netdev_event(struct notifier_block *this, 1098c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct netdev_notifier_info *ni = ptr; 1128c2ecf20Sopenharmony_ci struct net_device *dev = ni->dev; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (dev->netdev_ops->ndo_open != ipoib_open) 1158c2ecf20Sopenharmony_ci return NOTIFY_DONE; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci switch (event) { 1188c2ecf20Sopenharmony_ci case NETDEV_REGISTER: 1198c2ecf20Sopenharmony_ci ipoib_create_debug_files(dev); 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci case NETDEV_CHANGENAME: 1228c2ecf20Sopenharmony_ci ipoib_delete_debug_files(dev); 1238c2ecf20Sopenharmony_ci ipoib_create_debug_files(dev); 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci case NETDEV_UNREGISTER: 1268c2ecf20Sopenharmony_ci ipoib_delete_debug_files(dev); 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci return NOTIFY_DONE; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci#endif 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ciint ipoib_open(struct net_device *dev) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci ipoib_dbg(priv, "bringing up interface\n"); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci netif_carrier_off(dev); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci priv->sm_fullmember_sendonly_support = false; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (ipoib_ib_dev_open(dev)) { 1478c2ecf20Sopenharmony_ci if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) 1488c2ecf20Sopenharmony_ci return 0; 1498c2ecf20Sopenharmony_ci goto err_disable; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci ipoib_ib_dev_up(dev); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { 1558c2ecf20Sopenharmony_ci struct ipoib_dev_priv *cpriv; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* Bring up any child interfaces too */ 1588c2ecf20Sopenharmony_ci down_read(&priv->vlan_rwsem); 1598c2ecf20Sopenharmony_ci list_for_each_entry(cpriv, &priv->child_intfs, list) { 1608c2ecf20Sopenharmony_ci int flags; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci flags = cpriv->dev->flags; 1638c2ecf20Sopenharmony_ci if (flags & IFF_UP) 1648c2ecf20Sopenharmony_ci continue; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci dev_change_flags(cpriv->dev, flags | IFF_UP, NULL); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci up_read(&priv->vlan_rwsem); 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci netif_start_queue(dev); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cierr_disable: 1768c2ecf20Sopenharmony_ci clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return -EINVAL; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int ipoib_stop(struct net_device *dev) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci ipoib_dbg(priv, "stopping interface\n"); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci netif_stop_queue(dev); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci ipoib_ib_dev_down(dev); 1928c2ecf20Sopenharmony_ci ipoib_ib_dev_stop(dev); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { 1958c2ecf20Sopenharmony_ci struct ipoib_dev_priv *cpriv; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* Bring down any child interfaces too */ 1988c2ecf20Sopenharmony_ci down_read(&priv->vlan_rwsem); 1998c2ecf20Sopenharmony_ci list_for_each_entry(cpriv, &priv->child_intfs, list) { 2008c2ecf20Sopenharmony_ci int flags; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci flags = cpriv->dev->flags; 2038c2ecf20Sopenharmony_ci if (!(flags & IFF_UP)) 2048c2ecf20Sopenharmony_ci continue; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci dev_change_flags(cpriv->dev, flags & ~IFF_UP, NULL); 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci up_read(&priv->vlan_rwsem); 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return 0; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic netdev_features_t ipoib_fix_features(struct net_device *dev, netdev_features_t features) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags)) 2198c2ecf20Sopenharmony_ci features &= ~(NETIF_F_IP_CSUM | NETIF_F_TSO); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return features; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic int ipoib_change_mtu(struct net_device *dev, int new_mtu) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 2278c2ecf20Sopenharmony_ci int ret = 0; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* dev->mtu > 2K ==> connected mode */ 2308c2ecf20Sopenharmony_ci if (ipoib_cm_admin_enabled(dev)) { 2318c2ecf20Sopenharmony_ci if (new_mtu > ipoib_cm_max_mtu(dev)) 2328c2ecf20Sopenharmony_ci return -EINVAL; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (new_mtu > priv->mcast_mtu) 2358c2ecf20Sopenharmony_ci ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n", 2368c2ecf20Sopenharmony_ci priv->mcast_mtu); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (new_mtu < (ETH_MIN_MTU + IPOIB_ENCAP_LEN) || 2438c2ecf20Sopenharmony_ci new_mtu > IPOIB_UD_MTU(priv->max_ib_mtu)) 2448c2ecf20Sopenharmony_ci return -EINVAL; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci priv->admin_mtu = new_mtu; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (priv->mcast_mtu < priv->admin_mtu) 2498c2ecf20Sopenharmony_ci ipoib_dbg(priv, "MTU must be smaller than the underlying " 2508c2ecf20Sopenharmony_ci "link layer MTU - 4 (%u)\n", priv->mcast_mtu); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci new_mtu = min(priv->mcast_mtu, priv->admin_mtu); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (priv->rn_ops->ndo_change_mtu) { 2558c2ecf20Sopenharmony_ci bool carrier_status = netif_carrier_ok(dev); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci netif_carrier_off(dev); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* notify lower level on the real mtu */ 2608c2ecf20Sopenharmony_ci ret = priv->rn_ops->ndo_change_mtu(dev, new_mtu); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (carrier_status) 2638c2ecf20Sopenharmony_ci netif_carrier_on(dev); 2648c2ecf20Sopenharmony_ci } else { 2658c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return ret; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic void ipoib_get_stats(struct net_device *dev, 2728c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *stats) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (priv->rn_ops->ndo_get_stats64) 2778c2ecf20Sopenharmony_ci priv->rn_ops->ndo_get_stats64(dev, stats); 2788c2ecf20Sopenharmony_ci else 2798c2ecf20Sopenharmony_ci netdev_stats_to_stats64(stats, &dev->stats); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* Called with an RCU read lock taken */ 2838c2ecf20Sopenharmony_cistatic bool ipoib_is_dev_match_addr_rcu(const struct sockaddr *addr, 2848c2ecf20Sopenharmony_ci struct net_device *dev) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct net *net = dev_net(dev); 2878c2ecf20Sopenharmony_ci struct in_device *in_dev; 2888c2ecf20Sopenharmony_ci struct sockaddr_in *addr_in = (struct sockaddr_in *)addr; 2898c2ecf20Sopenharmony_ci struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr; 2908c2ecf20Sopenharmony_ci __be32 ret_addr; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci switch (addr->sa_family) { 2938c2ecf20Sopenharmony_ci case AF_INET: 2948c2ecf20Sopenharmony_ci in_dev = in_dev_get(dev); 2958c2ecf20Sopenharmony_ci if (!in_dev) 2968c2ecf20Sopenharmony_ci return false; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci ret_addr = inet_confirm_addr(net, in_dev, 0, 2998c2ecf20Sopenharmony_ci addr_in->sin_addr.s_addr, 3008c2ecf20Sopenharmony_ci RT_SCOPE_HOST); 3018c2ecf20Sopenharmony_ci in_dev_put(in_dev); 3028c2ecf20Sopenharmony_ci if (ret_addr) 3038c2ecf20Sopenharmony_ci return true; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci case AF_INET6: 3078c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_IPV6) && 3088c2ecf20Sopenharmony_ci ipv6_chk_addr(net, &addr_in6->sin6_addr, dev, 1)) 3098c2ecf20Sopenharmony_ci return true; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci break; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci return false; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci/** 3178c2ecf20Sopenharmony_ci * Find the master net_device on top of the given net_device. 3188c2ecf20Sopenharmony_ci * @dev: base IPoIB net_device 3198c2ecf20Sopenharmony_ci * 3208c2ecf20Sopenharmony_ci * Returns the master net_device with a reference held, or the same net_device 3218c2ecf20Sopenharmony_ci * if no master exists. 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_cistatic struct net_device *ipoib_get_master_net_dev(struct net_device *dev) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct net_device *master; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci rcu_read_lock(); 3288c2ecf20Sopenharmony_ci master = netdev_master_upper_dev_get_rcu(dev); 3298c2ecf20Sopenharmony_ci if (master) 3308c2ecf20Sopenharmony_ci dev_hold(master); 3318c2ecf20Sopenharmony_ci rcu_read_unlock(); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (master) 3348c2ecf20Sopenharmony_ci return master; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci dev_hold(dev); 3378c2ecf20Sopenharmony_ci return dev; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistruct ipoib_walk_data { 3418c2ecf20Sopenharmony_ci const struct sockaddr *addr; 3428c2ecf20Sopenharmony_ci struct net_device *result; 3438c2ecf20Sopenharmony_ci}; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic int ipoib_upper_walk(struct net_device *upper, 3468c2ecf20Sopenharmony_ci struct netdev_nested_priv *priv) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct ipoib_walk_data *data = (struct ipoib_walk_data *)priv->data; 3498c2ecf20Sopenharmony_ci int ret = 0; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (ipoib_is_dev_match_addr_rcu(data->addr, upper)) { 3528c2ecf20Sopenharmony_ci dev_hold(upper); 3538c2ecf20Sopenharmony_ci data->result = upper; 3548c2ecf20Sopenharmony_ci ret = 1; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return ret; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci/** 3618c2ecf20Sopenharmony_ci * Find a net_device matching the given address, which is an upper device of 3628c2ecf20Sopenharmony_ci * the given net_device. 3638c2ecf20Sopenharmony_ci * @addr: IP address to look for. 3648c2ecf20Sopenharmony_ci * @dev: base IPoIB net_device 3658c2ecf20Sopenharmony_ci * 3668c2ecf20Sopenharmony_ci * If found, returns the net_device with a reference held. Otherwise return 3678c2ecf20Sopenharmony_ci * NULL. 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_cistatic struct net_device *ipoib_get_net_dev_match_addr( 3708c2ecf20Sopenharmony_ci const struct sockaddr *addr, struct net_device *dev) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct netdev_nested_priv priv; 3738c2ecf20Sopenharmony_ci struct ipoib_walk_data data = { 3748c2ecf20Sopenharmony_ci .addr = addr, 3758c2ecf20Sopenharmony_ci }; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci priv.data = (void *)&data; 3788c2ecf20Sopenharmony_ci rcu_read_lock(); 3798c2ecf20Sopenharmony_ci if (ipoib_is_dev_match_addr_rcu(addr, dev)) { 3808c2ecf20Sopenharmony_ci dev_hold(dev); 3818c2ecf20Sopenharmony_ci data.result = dev; 3828c2ecf20Sopenharmony_ci goto out; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci netdev_walk_all_upper_dev_rcu(dev, ipoib_upper_walk, &priv); 3868c2ecf20Sopenharmony_ciout: 3878c2ecf20Sopenharmony_ci rcu_read_unlock(); 3888c2ecf20Sopenharmony_ci return data.result; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci/* returns the number of IPoIB netdevs on top a given ipoib device matching a 3928c2ecf20Sopenharmony_ci * pkey_index and address, if one exists. 3938c2ecf20Sopenharmony_ci * 3948c2ecf20Sopenharmony_ci * @found_net_dev: contains a matching net_device if the return value >= 1, 3958c2ecf20Sopenharmony_ci * with a reference held. */ 3968c2ecf20Sopenharmony_cistatic int ipoib_match_gid_pkey_addr(struct ipoib_dev_priv *priv, 3978c2ecf20Sopenharmony_ci const union ib_gid *gid, 3988c2ecf20Sopenharmony_ci u16 pkey_index, 3998c2ecf20Sopenharmony_ci const struct sockaddr *addr, 4008c2ecf20Sopenharmony_ci int nesting, 4018c2ecf20Sopenharmony_ci struct net_device **found_net_dev) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct ipoib_dev_priv *child_priv; 4048c2ecf20Sopenharmony_ci struct net_device *net_dev = NULL; 4058c2ecf20Sopenharmony_ci int matches = 0; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (priv->pkey_index == pkey_index && 4088c2ecf20Sopenharmony_ci (!gid || !memcmp(gid, &priv->local_gid, sizeof(*gid)))) { 4098c2ecf20Sopenharmony_ci if (!addr) { 4108c2ecf20Sopenharmony_ci net_dev = ipoib_get_master_net_dev(priv->dev); 4118c2ecf20Sopenharmony_ci } else { 4128c2ecf20Sopenharmony_ci /* Verify the net_device matches the IP address, as 4138c2ecf20Sopenharmony_ci * IPoIB child devices currently share a GID. */ 4148c2ecf20Sopenharmony_ci net_dev = ipoib_get_net_dev_match_addr(addr, priv->dev); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci if (net_dev) { 4178c2ecf20Sopenharmony_ci if (!*found_net_dev) 4188c2ecf20Sopenharmony_ci *found_net_dev = net_dev; 4198c2ecf20Sopenharmony_ci else 4208c2ecf20Sopenharmony_ci dev_put(net_dev); 4218c2ecf20Sopenharmony_ci ++matches; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* Check child interfaces */ 4268c2ecf20Sopenharmony_ci down_read_nested(&priv->vlan_rwsem, nesting); 4278c2ecf20Sopenharmony_ci list_for_each_entry(child_priv, &priv->child_intfs, list) { 4288c2ecf20Sopenharmony_ci matches += ipoib_match_gid_pkey_addr(child_priv, gid, 4298c2ecf20Sopenharmony_ci pkey_index, addr, 4308c2ecf20Sopenharmony_ci nesting + 1, 4318c2ecf20Sopenharmony_ci found_net_dev); 4328c2ecf20Sopenharmony_ci if (matches > 1) 4338c2ecf20Sopenharmony_ci break; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci up_read(&priv->vlan_rwsem); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return matches; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci/* Returns the number of matching net_devs found (between 0 and 2). Also 4418c2ecf20Sopenharmony_ci * return the matching net_device in the @net_dev parameter, holding a 4428c2ecf20Sopenharmony_ci * reference to the net_device, if the number of matches >= 1 */ 4438c2ecf20Sopenharmony_cistatic int __ipoib_get_net_dev_by_params(struct list_head *dev_list, u8 port, 4448c2ecf20Sopenharmony_ci u16 pkey_index, 4458c2ecf20Sopenharmony_ci const union ib_gid *gid, 4468c2ecf20Sopenharmony_ci const struct sockaddr *addr, 4478c2ecf20Sopenharmony_ci struct net_device **net_dev) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv; 4508c2ecf20Sopenharmony_ci int matches = 0; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci *net_dev = NULL; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci list_for_each_entry(priv, dev_list, list) { 4558c2ecf20Sopenharmony_ci if (priv->port != port) 4568c2ecf20Sopenharmony_ci continue; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci matches += ipoib_match_gid_pkey_addr(priv, gid, pkey_index, 4598c2ecf20Sopenharmony_ci addr, 0, net_dev); 4608c2ecf20Sopenharmony_ci if (matches > 1) 4618c2ecf20Sopenharmony_ci break; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return matches; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic struct net_device *ipoib_get_net_dev_by_params( 4688c2ecf20Sopenharmony_ci struct ib_device *dev, u8 port, u16 pkey, 4698c2ecf20Sopenharmony_ci const union ib_gid *gid, const struct sockaddr *addr, 4708c2ecf20Sopenharmony_ci void *client_data) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct net_device *net_dev; 4738c2ecf20Sopenharmony_ci struct list_head *dev_list = client_data; 4748c2ecf20Sopenharmony_ci u16 pkey_index; 4758c2ecf20Sopenharmony_ci int matches; 4768c2ecf20Sopenharmony_ci int ret; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (!rdma_protocol_ib(dev, port)) 4798c2ecf20Sopenharmony_ci return NULL; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci ret = ib_find_cached_pkey(dev, port, pkey, &pkey_index); 4828c2ecf20Sopenharmony_ci if (ret) 4838c2ecf20Sopenharmony_ci return NULL; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* See if we can find a unique device matching the L2 parameters */ 4868c2ecf20Sopenharmony_ci matches = __ipoib_get_net_dev_by_params(dev_list, port, pkey_index, 4878c2ecf20Sopenharmony_ci gid, NULL, &net_dev); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci switch (matches) { 4908c2ecf20Sopenharmony_ci case 0: 4918c2ecf20Sopenharmony_ci return NULL; 4928c2ecf20Sopenharmony_ci case 1: 4938c2ecf20Sopenharmony_ci return net_dev; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci dev_put(net_dev); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci /* Couldn't find a unique device with L2 parameters only. Use L3 4998c2ecf20Sopenharmony_ci * address to uniquely match the net device */ 5008c2ecf20Sopenharmony_ci matches = __ipoib_get_net_dev_by_params(dev_list, port, pkey_index, 5018c2ecf20Sopenharmony_ci gid, addr, &net_dev); 5028c2ecf20Sopenharmony_ci switch (matches) { 5038c2ecf20Sopenharmony_ci case 0: 5048c2ecf20Sopenharmony_ci return NULL; 5058c2ecf20Sopenharmony_ci default: 5068c2ecf20Sopenharmony_ci dev_warn_ratelimited(&dev->dev, 5078c2ecf20Sopenharmony_ci "duplicate IP address detected\n"); 5088c2ecf20Sopenharmony_ci fallthrough; 5098c2ecf20Sopenharmony_ci case 1: 5108c2ecf20Sopenharmony_ci return net_dev; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ciint ipoib_set_mode(struct net_device *dev, const char *buf) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if ((test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags) && 5198c2ecf20Sopenharmony_ci !strcmp(buf, "connected\n")) || 5208c2ecf20Sopenharmony_ci (!test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags) && 5218c2ecf20Sopenharmony_ci !strcmp(buf, "datagram\n"))) { 5228c2ecf20Sopenharmony_ci return 0; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* flush paths if we switch modes so that connections are restarted */ 5268c2ecf20Sopenharmony_ci if (IPOIB_CM_SUPPORTED(dev->dev_addr) && !strcmp(buf, "connected\n")) { 5278c2ecf20Sopenharmony_ci set_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); 5288c2ecf20Sopenharmony_ci ipoib_warn(priv, "enabling connected mode " 5298c2ecf20Sopenharmony_ci "will cause multicast packet drops\n"); 5308c2ecf20Sopenharmony_ci netdev_update_features(dev); 5318c2ecf20Sopenharmony_ci dev_set_mtu(dev, ipoib_cm_max_mtu(dev)); 5328c2ecf20Sopenharmony_ci netif_set_real_num_tx_queues(dev, 1); 5338c2ecf20Sopenharmony_ci rtnl_unlock(); 5348c2ecf20Sopenharmony_ci priv->tx_wr.wr.send_flags &= ~IB_SEND_IP_CSUM; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci ipoib_flush_paths(dev); 5378c2ecf20Sopenharmony_ci return (!rtnl_trylock()) ? -EBUSY : 0; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (!strcmp(buf, "datagram\n")) { 5418c2ecf20Sopenharmony_ci clear_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); 5428c2ecf20Sopenharmony_ci netdev_update_features(dev); 5438c2ecf20Sopenharmony_ci dev_set_mtu(dev, min(priv->mcast_mtu, dev->mtu)); 5448c2ecf20Sopenharmony_ci netif_set_real_num_tx_queues(dev, dev->num_tx_queues); 5458c2ecf20Sopenharmony_ci rtnl_unlock(); 5468c2ecf20Sopenharmony_ci ipoib_flush_paths(dev); 5478c2ecf20Sopenharmony_ci return (!rtnl_trylock()) ? -EBUSY : 0; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return -EINVAL; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistruct ipoib_path *__path_find(struct net_device *dev, void *gid) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 5568c2ecf20Sopenharmony_ci struct rb_node *n = priv->path_tree.rb_node; 5578c2ecf20Sopenharmony_ci struct ipoib_path *path; 5588c2ecf20Sopenharmony_ci int ret; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci while (n) { 5618c2ecf20Sopenharmony_ci path = rb_entry(n, struct ipoib_path, rb_node); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci ret = memcmp(gid, path->pathrec.dgid.raw, 5648c2ecf20Sopenharmony_ci sizeof (union ib_gid)); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (ret < 0) 5678c2ecf20Sopenharmony_ci n = n->rb_left; 5688c2ecf20Sopenharmony_ci else if (ret > 0) 5698c2ecf20Sopenharmony_ci n = n->rb_right; 5708c2ecf20Sopenharmony_ci else 5718c2ecf20Sopenharmony_ci return path; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci return NULL; 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic int __path_add(struct net_device *dev, struct ipoib_path *path) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 5808c2ecf20Sopenharmony_ci struct rb_node **n = &priv->path_tree.rb_node; 5818c2ecf20Sopenharmony_ci struct rb_node *pn = NULL; 5828c2ecf20Sopenharmony_ci struct ipoib_path *tpath; 5838c2ecf20Sopenharmony_ci int ret; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci while (*n) { 5868c2ecf20Sopenharmony_ci pn = *n; 5878c2ecf20Sopenharmony_ci tpath = rb_entry(pn, struct ipoib_path, rb_node); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci ret = memcmp(path->pathrec.dgid.raw, tpath->pathrec.dgid.raw, 5908c2ecf20Sopenharmony_ci sizeof (union ib_gid)); 5918c2ecf20Sopenharmony_ci if (ret < 0) 5928c2ecf20Sopenharmony_ci n = &pn->rb_left; 5938c2ecf20Sopenharmony_ci else if (ret > 0) 5948c2ecf20Sopenharmony_ci n = &pn->rb_right; 5958c2ecf20Sopenharmony_ci else 5968c2ecf20Sopenharmony_ci return -EEXIST; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci rb_link_node(&path->rb_node, pn, n); 6008c2ecf20Sopenharmony_ci rb_insert_color(&path->rb_node, &priv->path_tree); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci list_add_tail(&path->list, &priv->path_list); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return 0; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic void path_free(struct net_device *dev, struct ipoib_path *path) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci struct sk_buff *skb; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&path->queue))) 6128c2ecf20Sopenharmony_ci dev_kfree_skb_irq(skb); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci ipoib_dbg(ipoib_priv(dev), "%s\n", __func__); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* remove all neigh connected to this path */ 6178c2ecf20Sopenharmony_ci ipoib_del_neighs_by_gid(dev, path->pathrec.dgid.raw); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (path->ah) 6208c2ecf20Sopenharmony_ci ipoib_put_ah(path->ah); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci kfree(path); 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistruct ipoib_path_iter *ipoib_path_iter_init(struct net_device *dev) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci struct ipoib_path_iter *iter; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci iter = kmalloc(sizeof(*iter), GFP_KERNEL); 6328c2ecf20Sopenharmony_ci if (!iter) 6338c2ecf20Sopenharmony_ci return NULL; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci iter->dev = dev; 6368c2ecf20Sopenharmony_ci memset(iter->path.pathrec.dgid.raw, 0, 16); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (ipoib_path_iter_next(iter)) { 6398c2ecf20Sopenharmony_ci kfree(iter); 6408c2ecf20Sopenharmony_ci return NULL; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci return iter; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ciint ipoib_path_iter_next(struct ipoib_path_iter *iter) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(iter->dev); 6498c2ecf20Sopenharmony_ci struct rb_node *n; 6508c2ecf20Sopenharmony_ci struct ipoib_path *path; 6518c2ecf20Sopenharmony_ci int ret = 1; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci spin_lock_irq(&priv->lock); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci n = rb_first(&priv->path_tree); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci while (n) { 6588c2ecf20Sopenharmony_ci path = rb_entry(n, struct ipoib_path, rb_node); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci if (memcmp(iter->path.pathrec.dgid.raw, path->pathrec.dgid.raw, 6618c2ecf20Sopenharmony_ci sizeof (union ib_gid)) < 0) { 6628c2ecf20Sopenharmony_ci iter->path = *path; 6638c2ecf20Sopenharmony_ci ret = 0; 6648c2ecf20Sopenharmony_ci break; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci n = rb_next(n); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci spin_unlock_irq(&priv->lock); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci return ret; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_civoid ipoib_path_iter_read(struct ipoib_path_iter *iter, 6768c2ecf20Sopenharmony_ci struct ipoib_path *path) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci *path = iter->path; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci#endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */ 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_civoid ipoib_mark_paths_invalid(struct net_device *dev) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 6868c2ecf20Sopenharmony_ci struct ipoib_path *path, *tp; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci spin_lock_irq(&priv->lock); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci list_for_each_entry_safe(path, tp, &priv->path_list, list) { 6918c2ecf20Sopenharmony_ci ipoib_dbg(priv, "mark path LID 0x%08x GID %pI6 invalid\n", 6928c2ecf20Sopenharmony_ci be32_to_cpu(sa_path_get_dlid(&path->pathrec)), 6938c2ecf20Sopenharmony_ci path->pathrec.dgid.raw); 6948c2ecf20Sopenharmony_ci if (path->ah) 6958c2ecf20Sopenharmony_ci path->ah->valid = 0; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci spin_unlock_irq(&priv->lock); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic void push_pseudo_header(struct sk_buff *skb, const char *daddr) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci struct ipoib_pseudo_header *phdr; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci phdr = skb_push(skb, sizeof(*phdr)); 7068c2ecf20Sopenharmony_ci memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_civoid ipoib_flush_paths(struct net_device *dev) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 7128c2ecf20Sopenharmony_ci struct ipoib_path *path, *tp; 7138c2ecf20Sopenharmony_ci LIST_HEAD(remove_list); 7148c2ecf20Sopenharmony_ci unsigned long flags; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci netif_tx_lock_bh(dev); 7178c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci list_splice_init(&priv->path_list, &remove_list); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci list_for_each_entry(path, &remove_list, list) 7228c2ecf20Sopenharmony_ci rb_erase(&path->rb_node, &priv->path_tree); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci list_for_each_entry_safe(path, tp, &remove_list, list) { 7258c2ecf20Sopenharmony_ci if (path->query) 7268c2ecf20Sopenharmony_ci ib_sa_cancel_query(path->query_id, path->query); 7278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 7288c2ecf20Sopenharmony_ci netif_tx_unlock_bh(dev); 7298c2ecf20Sopenharmony_ci wait_for_completion(&path->done); 7308c2ecf20Sopenharmony_ci path_free(dev, path); 7318c2ecf20Sopenharmony_ci netif_tx_lock_bh(dev); 7328c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 7368c2ecf20Sopenharmony_ci netif_tx_unlock_bh(dev); 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic void path_rec_completion(int status, 7408c2ecf20Sopenharmony_ci struct sa_path_rec *pathrec, 7418c2ecf20Sopenharmony_ci void *path_ptr) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct ipoib_path *path = path_ptr; 7448c2ecf20Sopenharmony_ci struct net_device *dev = path->dev; 7458c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 7468c2ecf20Sopenharmony_ci struct ipoib_ah *ah = NULL; 7478c2ecf20Sopenharmony_ci struct ipoib_ah *old_ah = NULL; 7488c2ecf20Sopenharmony_ci struct ipoib_neigh *neigh, *tn; 7498c2ecf20Sopenharmony_ci struct sk_buff_head skqueue; 7508c2ecf20Sopenharmony_ci struct sk_buff *skb; 7518c2ecf20Sopenharmony_ci unsigned long flags; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (!status) 7548c2ecf20Sopenharmony_ci ipoib_dbg(priv, "PathRec LID 0x%04x for GID %pI6\n", 7558c2ecf20Sopenharmony_ci be32_to_cpu(sa_path_get_dlid(pathrec)), 7568c2ecf20Sopenharmony_ci pathrec->dgid.raw); 7578c2ecf20Sopenharmony_ci else 7588c2ecf20Sopenharmony_ci ipoib_dbg(priv, "PathRec status %d for GID %pI6\n", 7598c2ecf20Sopenharmony_ci status, path->pathrec.dgid.raw); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci skb_queue_head_init(&skqueue); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (!status) { 7648c2ecf20Sopenharmony_ci struct rdma_ah_attr av; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (!ib_init_ah_attr_from_path(priv->ca, priv->port, 7678c2ecf20Sopenharmony_ci pathrec, &av, NULL)) { 7688c2ecf20Sopenharmony_ci ah = ipoib_create_ah(dev, priv->pd, &av); 7698c2ecf20Sopenharmony_ci rdma_destroy_ah_attr(&av); 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(ah)) { 7768c2ecf20Sopenharmony_ci /* 7778c2ecf20Sopenharmony_ci * pathrec.dgid is used as the database key from the LLADDR, 7788c2ecf20Sopenharmony_ci * it must remain unchanged even if the SA returns a different 7798c2ecf20Sopenharmony_ci * GID to use in the AH. 7808c2ecf20Sopenharmony_ci */ 7818c2ecf20Sopenharmony_ci if (memcmp(pathrec->dgid.raw, path->pathrec.dgid.raw, 7828c2ecf20Sopenharmony_ci sizeof(union ib_gid))) { 7838c2ecf20Sopenharmony_ci ipoib_dbg( 7848c2ecf20Sopenharmony_ci priv, 7858c2ecf20Sopenharmony_ci "%s got PathRec for gid %pI6 while asked for %pI6\n", 7868c2ecf20Sopenharmony_ci dev->name, pathrec->dgid.raw, 7878c2ecf20Sopenharmony_ci path->pathrec.dgid.raw); 7888c2ecf20Sopenharmony_ci memcpy(pathrec->dgid.raw, path->pathrec.dgid.raw, 7898c2ecf20Sopenharmony_ci sizeof(union ib_gid)); 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci path->pathrec = *pathrec; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci old_ah = path->ah; 7958c2ecf20Sopenharmony_ci path->ah = ah; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci ipoib_dbg(priv, "created address handle %p for LID 0x%04x, SL %d\n", 7988c2ecf20Sopenharmony_ci ah, be32_to_cpu(sa_path_get_dlid(pathrec)), 7998c2ecf20Sopenharmony_ci pathrec->sl); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&path->queue))) 8028c2ecf20Sopenharmony_ci __skb_queue_tail(&skqueue, skb); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci list_for_each_entry_safe(neigh, tn, &path->neigh_list, list) { 8058c2ecf20Sopenharmony_ci if (neigh->ah) { 8068c2ecf20Sopenharmony_ci WARN_ON(neigh->ah != old_ah); 8078c2ecf20Sopenharmony_ci /* 8088c2ecf20Sopenharmony_ci * Dropping the ah reference inside 8098c2ecf20Sopenharmony_ci * priv->lock is safe here, because we 8108c2ecf20Sopenharmony_ci * will hold one more reference from 8118c2ecf20Sopenharmony_ci * the original value of path->ah (ie 8128c2ecf20Sopenharmony_ci * old_ah). 8138c2ecf20Sopenharmony_ci */ 8148c2ecf20Sopenharmony_ci ipoib_put_ah(neigh->ah); 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci kref_get(&path->ah->ref); 8178c2ecf20Sopenharmony_ci neigh->ah = path->ah; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (ipoib_cm_enabled(dev, neigh->daddr)) { 8208c2ecf20Sopenharmony_ci if (!ipoib_cm_get(neigh)) 8218c2ecf20Sopenharmony_ci ipoib_cm_set(neigh, ipoib_cm_create_tx(dev, 8228c2ecf20Sopenharmony_ci path, 8238c2ecf20Sopenharmony_ci neigh)); 8248c2ecf20Sopenharmony_ci if (!ipoib_cm_get(neigh)) { 8258c2ecf20Sopenharmony_ci ipoib_neigh_free(neigh); 8268c2ecf20Sopenharmony_ci continue; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&neigh->queue))) 8318c2ecf20Sopenharmony_ci __skb_queue_tail(&skqueue, skb); 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci path->ah->valid = 1; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci path->query = NULL; 8378c2ecf20Sopenharmony_ci complete(&path->done); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(ah)) 8428c2ecf20Sopenharmony_ci ipoib_del_neighs_by_gid(dev, path->pathrec.dgid.raw); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci if (old_ah) 8458c2ecf20Sopenharmony_ci ipoib_put_ah(old_ah); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&skqueue))) { 8488c2ecf20Sopenharmony_ci int ret; 8498c2ecf20Sopenharmony_ci skb->dev = dev; 8508c2ecf20Sopenharmony_ci ret = dev_queue_xmit(skb); 8518c2ecf20Sopenharmony_ci if (ret) 8528c2ecf20Sopenharmony_ci ipoib_warn(priv, "%s: dev_queue_xmit failed to re-queue packet, ret:%d\n", 8538c2ecf20Sopenharmony_ci __func__, ret); 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic void init_path_rec(struct ipoib_dev_priv *priv, struct ipoib_path *path, 8588c2ecf20Sopenharmony_ci void *gid) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci path->dev = priv->dev; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci if (rdma_cap_opa_ah(priv->ca, priv->port)) 8638c2ecf20Sopenharmony_ci path->pathrec.rec_type = SA_PATH_REC_TYPE_OPA; 8648c2ecf20Sopenharmony_ci else 8658c2ecf20Sopenharmony_ci path->pathrec.rec_type = SA_PATH_REC_TYPE_IB; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci memcpy(path->pathrec.dgid.raw, gid, sizeof(union ib_gid)); 8688c2ecf20Sopenharmony_ci path->pathrec.sgid = priv->local_gid; 8698c2ecf20Sopenharmony_ci path->pathrec.pkey = cpu_to_be16(priv->pkey); 8708c2ecf20Sopenharmony_ci path->pathrec.numb_path = 1; 8718c2ecf20Sopenharmony_ci path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic struct ipoib_path *path_rec_create(struct net_device *dev, void *gid) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 8778c2ecf20Sopenharmony_ci struct ipoib_path *path; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (!priv->broadcast) 8808c2ecf20Sopenharmony_ci return NULL; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci path = kzalloc(sizeof(*path), GFP_ATOMIC); 8838c2ecf20Sopenharmony_ci if (!path) 8848c2ecf20Sopenharmony_ci return NULL; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci skb_queue_head_init(&path->queue); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&path->neigh_list); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci init_path_rec(priv, path, gid); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci return path; 8938c2ecf20Sopenharmony_ci} 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cistatic int path_rec_start(struct net_device *dev, 8968c2ecf20Sopenharmony_ci struct ipoib_path *path) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci ipoib_dbg(priv, "Start path record lookup for %pI6\n", 9018c2ecf20Sopenharmony_ci path->pathrec.dgid.raw); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci init_completion(&path->done); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci path->query_id = 9068c2ecf20Sopenharmony_ci ib_sa_path_rec_get(&ipoib_sa_client, priv->ca, priv->port, 9078c2ecf20Sopenharmony_ci &path->pathrec, 9088c2ecf20Sopenharmony_ci IB_SA_PATH_REC_DGID | 9098c2ecf20Sopenharmony_ci IB_SA_PATH_REC_SGID | 9108c2ecf20Sopenharmony_ci IB_SA_PATH_REC_NUMB_PATH | 9118c2ecf20Sopenharmony_ci IB_SA_PATH_REC_TRAFFIC_CLASS | 9128c2ecf20Sopenharmony_ci IB_SA_PATH_REC_PKEY, 9138c2ecf20Sopenharmony_ci 1000, GFP_ATOMIC, 9148c2ecf20Sopenharmony_ci path_rec_completion, 9158c2ecf20Sopenharmony_ci path, &path->query); 9168c2ecf20Sopenharmony_ci if (path->query_id < 0) { 9178c2ecf20Sopenharmony_ci ipoib_warn(priv, "ib_sa_path_rec_get failed: %d\n", path->query_id); 9188c2ecf20Sopenharmony_ci path->query = NULL; 9198c2ecf20Sopenharmony_ci complete(&path->done); 9208c2ecf20Sopenharmony_ci return path->query_id; 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci return 0; 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_cistatic void neigh_refresh_path(struct ipoib_neigh *neigh, u8 *daddr, 9278c2ecf20Sopenharmony_ci struct net_device *dev) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 9308c2ecf20Sopenharmony_ci struct ipoib_path *path; 9318c2ecf20Sopenharmony_ci unsigned long flags; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci path = __path_find(dev, daddr + 4); 9368c2ecf20Sopenharmony_ci if (!path) 9378c2ecf20Sopenharmony_ci goto out; 9388c2ecf20Sopenharmony_ci if (!path->query) 9398c2ecf20Sopenharmony_ci path_rec_start(dev, path); 9408c2ecf20Sopenharmony_ciout: 9418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 9428c2ecf20Sopenharmony_ci} 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_cistatic struct ipoib_neigh *neigh_add_path(struct sk_buff *skb, u8 *daddr, 9458c2ecf20Sopenharmony_ci struct net_device *dev) 9468c2ecf20Sopenharmony_ci{ 9478c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 9488c2ecf20Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 9498c2ecf20Sopenharmony_ci struct ipoib_path *path; 9508c2ecf20Sopenharmony_ci struct ipoib_neigh *neigh; 9518c2ecf20Sopenharmony_ci unsigned long flags; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 9548c2ecf20Sopenharmony_ci neigh = ipoib_neigh_alloc(daddr, dev); 9558c2ecf20Sopenharmony_ci if (!neigh) { 9568c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 9578c2ecf20Sopenharmony_ci ++dev->stats.tx_dropped; 9588c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 9598c2ecf20Sopenharmony_ci return NULL; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci /* To avoid race condition, make sure that the 9638c2ecf20Sopenharmony_ci * neigh will be added only once. 9648c2ecf20Sopenharmony_ci */ 9658c2ecf20Sopenharmony_ci if (unlikely(!list_empty(&neigh->list))) { 9668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 9678c2ecf20Sopenharmony_ci return neigh; 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci path = __path_find(dev, daddr + 4); 9718c2ecf20Sopenharmony_ci if (!path) { 9728c2ecf20Sopenharmony_ci path = path_rec_create(dev, daddr + 4); 9738c2ecf20Sopenharmony_ci if (!path) 9748c2ecf20Sopenharmony_ci goto err_path; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci __path_add(dev, path); 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci list_add_tail(&neigh->list, &path->neigh_list); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (path->ah && path->ah->valid) { 9828c2ecf20Sopenharmony_ci kref_get(&path->ah->ref); 9838c2ecf20Sopenharmony_ci neigh->ah = path->ah; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (ipoib_cm_enabled(dev, neigh->daddr)) { 9868c2ecf20Sopenharmony_ci if (!ipoib_cm_get(neigh)) 9878c2ecf20Sopenharmony_ci ipoib_cm_set(neigh, ipoib_cm_create_tx(dev, path, neigh)); 9888c2ecf20Sopenharmony_ci if (!ipoib_cm_get(neigh)) { 9898c2ecf20Sopenharmony_ci ipoib_neigh_free(neigh); 9908c2ecf20Sopenharmony_ci goto err_drop; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci if (skb_queue_len(&neigh->queue) < 9938c2ecf20Sopenharmony_ci IPOIB_MAX_PATH_REC_QUEUE) { 9948c2ecf20Sopenharmony_ci push_pseudo_header(skb, neigh->daddr); 9958c2ecf20Sopenharmony_ci __skb_queue_tail(&neigh->queue, skb); 9968c2ecf20Sopenharmony_ci } else { 9978c2ecf20Sopenharmony_ci ipoib_warn(priv, "queue length limit %d. Packet drop.\n", 9988c2ecf20Sopenharmony_ci skb_queue_len(&neigh->queue)); 9998c2ecf20Sopenharmony_ci goto err_drop; 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci } else { 10028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 10038c2ecf20Sopenharmony_ci path->ah->last_send = rn->send(dev, skb, path->ah->ah, 10048c2ecf20Sopenharmony_ci IPOIB_QPN(daddr)); 10058c2ecf20Sopenharmony_ci ipoib_neigh_put(neigh); 10068c2ecf20Sopenharmony_ci return NULL; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci } else { 10098c2ecf20Sopenharmony_ci neigh->ah = NULL; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (!path->query && path_rec_start(dev, path)) 10128c2ecf20Sopenharmony_ci goto err_path; 10138c2ecf20Sopenharmony_ci if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { 10148c2ecf20Sopenharmony_ci push_pseudo_header(skb, neigh->daddr); 10158c2ecf20Sopenharmony_ci __skb_queue_tail(&neigh->queue, skb); 10168c2ecf20Sopenharmony_ci } else { 10178c2ecf20Sopenharmony_ci goto err_drop; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 10228c2ecf20Sopenharmony_ci ipoib_neigh_put(neigh); 10238c2ecf20Sopenharmony_ci return NULL; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_cierr_path: 10268c2ecf20Sopenharmony_ci ipoib_neigh_free(neigh); 10278c2ecf20Sopenharmony_cierr_drop: 10288c2ecf20Sopenharmony_ci ++dev->stats.tx_dropped; 10298c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 10328c2ecf20Sopenharmony_ci ipoib_neigh_put(neigh); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci return NULL; 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_cistatic void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, 10388c2ecf20Sopenharmony_ci struct ipoib_pseudo_header *phdr) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 10418c2ecf20Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 10428c2ecf20Sopenharmony_ci struct ipoib_path *path; 10438c2ecf20Sopenharmony_ci unsigned long flags; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci /* no broadcast means that all paths are (going to be) not valid */ 10488c2ecf20Sopenharmony_ci if (!priv->broadcast) 10498c2ecf20Sopenharmony_ci goto drop_and_unlock; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci path = __path_find(dev, phdr->hwaddr + 4); 10528c2ecf20Sopenharmony_ci if (!path || !path->ah || !path->ah->valid) { 10538c2ecf20Sopenharmony_ci if (!path) { 10548c2ecf20Sopenharmony_ci path = path_rec_create(dev, phdr->hwaddr + 4); 10558c2ecf20Sopenharmony_ci if (!path) 10568c2ecf20Sopenharmony_ci goto drop_and_unlock; 10578c2ecf20Sopenharmony_ci __path_add(dev, path); 10588c2ecf20Sopenharmony_ci } else { 10598c2ecf20Sopenharmony_ci /* 10608c2ecf20Sopenharmony_ci * make sure there are no changes in the existing 10618c2ecf20Sopenharmony_ci * path record 10628c2ecf20Sopenharmony_ci */ 10638c2ecf20Sopenharmony_ci init_path_rec(priv, path, phdr->hwaddr + 4); 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci if (!path->query && path_rec_start(dev, path)) { 10668c2ecf20Sopenharmony_ci goto drop_and_unlock; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci if (skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { 10708c2ecf20Sopenharmony_ci push_pseudo_header(skb, phdr->hwaddr); 10718c2ecf20Sopenharmony_ci __skb_queue_tail(&path->queue, skb); 10728c2ecf20Sopenharmony_ci goto unlock; 10738c2ecf20Sopenharmony_ci } else { 10748c2ecf20Sopenharmony_ci goto drop_and_unlock; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 10798c2ecf20Sopenharmony_ci ipoib_dbg(priv, "Send unicast ARP to %08x\n", 10808c2ecf20Sopenharmony_ci be32_to_cpu(sa_path_get_dlid(&path->pathrec))); 10818c2ecf20Sopenharmony_ci path->ah->last_send = rn->send(dev, skb, path->ah->ah, 10828c2ecf20Sopenharmony_ci IPOIB_QPN(phdr->hwaddr)); 10838c2ecf20Sopenharmony_ci return; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cidrop_and_unlock: 10868c2ecf20Sopenharmony_ci ++dev->stats.tx_dropped; 10878c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 10888c2ecf20Sopenharmony_ciunlock: 10898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 10908c2ecf20Sopenharmony_ci} 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_cistatic netdev_tx_t ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 10958c2ecf20Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 10968c2ecf20Sopenharmony_ci struct ipoib_neigh *neigh; 10978c2ecf20Sopenharmony_ci struct ipoib_pseudo_header *phdr; 10988c2ecf20Sopenharmony_ci struct ipoib_header *header; 10998c2ecf20Sopenharmony_ci unsigned long flags; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci phdr = (struct ipoib_pseudo_header *) skb->data; 11028c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(*phdr)); 11038c2ecf20Sopenharmony_ci header = (struct ipoib_header *) skb->data; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (unlikely(phdr->hwaddr[4] == 0xff)) { 11068c2ecf20Sopenharmony_ci /* multicast, arrange "if" according to probability */ 11078c2ecf20Sopenharmony_ci if ((header->proto != htons(ETH_P_IP)) && 11088c2ecf20Sopenharmony_ci (header->proto != htons(ETH_P_IPV6)) && 11098c2ecf20Sopenharmony_ci (header->proto != htons(ETH_P_ARP)) && 11108c2ecf20Sopenharmony_ci (header->proto != htons(ETH_P_RARP)) && 11118c2ecf20Sopenharmony_ci (header->proto != htons(ETH_P_TIPC))) { 11128c2ecf20Sopenharmony_ci /* ethertype not supported by IPoIB */ 11138c2ecf20Sopenharmony_ci ++dev->stats.tx_dropped; 11148c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 11158c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci /* Add in the P_Key for multicast*/ 11188c2ecf20Sopenharmony_ci phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff; 11198c2ecf20Sopenharmony_ci phdr->hwaddr[9] = priv->pkey & 0xff; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci neigh = ipoib_neigh_get(dev, phdr->hwaddr); 11228c2ecf20Sopenharmony_ci if (likely(neigh)) 11238c2ecf20Sopenharmony_ci goto send_using_neigh; 11248c2ecf20Sopenharmony_ci ipoib_mcast_send(dev, phdr->hwaddr, skb); 11258c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* unicast, arrange "switch" according to probability */ 11298c2ecf20Sopenharmony_ci switch (header->proto) { 11308c2ecf20Sopenharmony_ci case htons(ETH_P_IP): 11318c2ecf20Sopenharmony_ci case htons(ETH_P_IPV6): 11328c2ecf20Sopenharmony_ci case htons(ETH_P_TIPC): 11338c2ecf20Sopenharmony_ci neigh = ipoib_neigh_get(dev, phdr->hwaddr); 11348c2ecf20Sopenharmony_ci if (unlikely(!neigh)) { 11358c2ecf20Sopenharmony_ci neigh = neigh_add_path(skb, phdr->hwaddr, dev); 11368c2ecf20Sopenharmony_ci if (likely(!neigh)) 11378c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci break; 11408c2ecf20Sopenharmony_ci case htons(ETH_P_ARP): 11418c2ecf20Sopenharmony_ci case htons(ETH_P_RARP): 11428c2ecf20Sopenharmony_ci /* for unicast ARP and RARP should always perform path find */ 11438c2ecf20Sopenharmony_ci unicast_arp_send(skb, dev, phdr); 11448c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 11458c2ecf20Sopenharmony_ci default: 11468c2ecf20Sopenharmony_ci /* ethertype not supported by IPoIB */ 11478c2ecf20Sopenharmony_ci ++dev->stats.tx_dropped; 11488c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 11498c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cisend_using_neigh: 11538c2ecf20Sopenharmony_ci /* note we now hold a ref to neigh */ 11548c2ecf20Sopenharmony_ci if (ipoib_cm_get(neigh)) { 11558c2ecf20Sopenharmony_ci if (ipoib_cm_up(neigh)) { 11568c2ecf20Sopenharmony_ci ipoib_cm_send(dev, skb, ipoib_cm_get(neigh)); 11578c2ecf20Sopenharmony_ci goto unref; 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci } else if (neigh->ah && neigh->ah->valid) { 11608c2ecf20Sopenharmony_ci neigh->ah->last_send = rn->send(dev, skb, neigh->ah->ah, 11618c2ecf20Sopenharmony_ci IPOIB_QPN(phdr->hwaddr)); 11628c2ecf20Sopenharmony_ci goto unref; 11638c2ecf20Sopenharmony_ci } else if (neigh->ah) { 11648c2ecf20Sopenharmony_ci neigh_refresh_path(neigh, phdr->hwaddr, dev); 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { 11688c2ecf20Sopenharmony_ci push_pseudo_header(skb, phdr->hwaddr); 11698c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 11708c2ecf20Sopenharmony_ci __skb_queue_tail(&neigh->queue, skb); 11718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 11728c2ecf20Sopenharmony_ci } else { 11738c2ecf20Sopenharmony_ci ++dev->stats.tx_dropped; 11748c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ciunref: 11788c2ecf20Sopenharmony_ci ipoib_neigh_put(neigh); 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_cistatic void ipoib_timeout(struct net_device *dev, unsigned int txqueue) 11848c2ecf20Sopenharmony_ci{ 11858c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci ipoib_warn(priv, "transmit timeout: latency %d msecs\n", 11888c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - dev_trans_start(dev))); 11898c2ecf20Sopenharmony_ci ipoib_warn(priv, 11908c2ecf20Sopenharmony_ci "queue stopped %d, tx_head %u, tx_tail %u, global_tx_head %u, global_tx_tail %u\n", 11918c2ecf20Sopenharmony_ci netif_queue_stopped(dev), priv->tx_head, priv->tx_tail, 11928c2ecf20Sopenharmony_ci priv->global_tx_head, priv->global_tx_tail); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci /* XXX reset QP, etc. */ 11958c2ecf20Sopenharmony_ci} 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_cistatic int ipoib_hard_header(struct sk_buff *skb, 11988c2ecf20Sopenharmony_ci struct net_device *dev, 11998c2ecf20Sopenharmony_ci unsigned short type, 12008c2ecf20Sopenharmony_ci const void *daddr, 12018c2ecf20Sopenharmony_ci const void *saddr, 12028c2ecf20Sopenharmony_ci unsigned int len) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci struct ipoib_header *header; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci header = skb_push(skb, sizeof(*header)); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci header->proto = htons(type); 12098c2ecf20Sopenharmony_ci header->reserved = 0; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci /* 12128c2ecf20Sopenharmony_ci * we don't rely on dst_entry structure, always stuff the 12138c2ecf20Sopenharmony_ci * destination address into skb hard header so we can figure out where 12148c2ecf20Sopenharmony_ci * to send the packet later. 12158c2ecf20Sopenharmony_ci */ 12168c2ecf20Sopenharmony_ci push_pseudo_header(skb, daddr); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci return IPOIB_HARD_LEN; 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_cistatic void ipoib_set_mcast_list(struct net_device *dev) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) { 12268c2ecf20Sopenharmony_ci ipoib_dbg(priv, "IPOIB_FLAG_OPER_UP not set"); 12278c2ecf20Sopenharmony_ci return; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci queue_work(priv->wq, &priv->restart_task); 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_cistatic int ipoib_get_iflink(const struct net_device *dev) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci /* parent interface */ 12388c2ecf20Sopenharmony_ci if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) 12398c2ecf20Sopenharmony_ci return dev->ifindex; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci /* child/vlan interface */ 12428c2ecf20Sopenharmony_ci return priv->parent->ifindex; 12438c2ecf20Sopenharmony_ci} 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_cistatic u32 ipoib_addr_hash(struct ipoib_neigh_hash *htbl, u8 *daddr) 12468c2ecf20Sopenharmony_ci{ 12478c2ecf20Sopenharmony_ci /* 12488c2ecf20Sopenharmony_ci * Use only the address parts that contributes to spreading 12498c2ecf20Sopenharmony_ci * The subnet prefix is not used as one can not connect to 12508c2ecf20Sopenharmony_ci * same remote port (GUID) using the same remote QPN via two 12518c2ecf20Sopenharmony_ci * different subnets. 12528c2ecf20Sopenharmony_ci */ 12538c2ecf20Sopenharmony_ci /* qpn octets[1:4) & port GUID octets[12:20) */ 12548c2ecf20Sopenharmony_ci u32 *d32 = (u32 *) daddr; 12558c2ecf20Sopenharmony_ci u32 hv; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci hv = jhash_3words(d32[3], d32[4], IPOIB_QPN_MASK & d32[0], 0); 12588c2ecf20Sopenharmony_ci return hv & htbl->mask; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistruct ipoib_neigh *ipoib_neigh_get(struct net_device *dev, u8 *daddr) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 12648c2ecf20Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 12658c2ecf20Sopenharmony_ci struct ipoib_neigh_hash *htbl; 12668c2ecf20Sopenharmony_ci struct ipoib_neigh *neigh = NULL; 12678c2ecf20Sopenharmony_ci u32 hash_val; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci rcu_read_lock_bh(); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci htbl = rcu_dereference_bh(ntbl->htbl); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci if (!htbl) 12748c2ecf20Sopenharmony_ci goto out_unlock; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci hash_val = ipoib_addr_hash(htbl, daddr); 12778c2ecf20Sopenharmony_ci for (neigh = rcu_dereference_bh(htbl->buckets[hash_val]); 12788c2ecf20Sopenharmony_ci neigh != NULL; 12798c2ecf20Sopenharmony_ci neigh = rcu_dereference_bh(neigh->hnext)) { 12808c2ecf20Sopenharmony_ci if (memcmp(daddr, neigh->daddr, INFINIBAND_ALEN) == 0) { 12818c2ecf20Sopenharmony_ci /* found, take one ref on behalf of the caller */ 12828c2ecf20Sopenharmony_ci if (!atomic_inc_not_zero(&neigh->refcnt)) { 12838c2ecf20Sopenharmony_ci /* deleted */ 12848c2ecf20Sopenharmony_ci neigh = NULL; 12858c2ecf20Sopenharmony_ci goto out_unlock; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci if (likely(skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE)) 12898c2ecf20Sopenharmony_ci neigh->alive = jiffies; 12908c2ecf20Sopenharmony_ci goto out_unlock; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ciout_unlock: 12958c2ecf20Sopenharmony_ci rcu_read_unlock_bh(); 12968c2ecf20Sopenharmony_ci return neigh; 12978c2ecf20Sopenharmony_ci} 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_cistatic void __ipoib_reap_neigh(struct ipoib_dev_priv *priv) 13008c2ecf20Sopenharmony_ci{ 13018c2ecf20Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 13028c2ecf20Sopenharmony_ci struct ipoib_neigh_hash *htbl; 13038c2ecf20Sopenharmony_ci unsigned long neigh_obsolete; 13048c2ecf20Sopenharmony_ci unsigned long dt; 13058c2ecf20Sopenharmony_ci unsigned long flags; 13068c2ecf20Sopenharmony_ci int i; 13078c2ecf20Sopenharmony_ci LIST_HEAD(remove_list); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci htbl = rcu_dereference_protected(ntbl->htbl, 13128c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock)); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci if (!htbl) 13158c2ecf20Sopenharmony_ci goto out_unlock; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci /* neigh is obsolete if it was idle for two GC periods */ 13188c2ecf20Sopenharmony_ci dt = 2 * arp_tbl.gc_interval; 13198c2ecf20Sopenharmony_ci neigh_obsolete = jiffies - dt; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci for (i = 0; i < htbl->size; i++) { 13228c2ecf20Sopenharmony_ci struct ipoib_neigh *neigh; 13238c2ecf20Sopenharmony_ci struct ipoib_neigh __rcu **np = &htbl->buckets[i]; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci while ((neigh = rcu_dereference_protected(*np, 13268c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock))) != NULL) { 13278c2ecf20Sopenharmony_ci /* was the neigh idle for two GC periods */ 13288c2ecf20Sopenharmony_ci if (time_after(neigh_obsolete, neigh->alive)) { 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci ipoib_check_and_add_mcast_sendonly(priv, neigh->daddr + 4, &remove_list); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci rcu_assign_pointer(*np, 13338c2ecf20Sopenharmony_ci rcu_dereference_protected(neigh->hnext, 13348c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock))); 13358c2ecf20Sopenharmony_ci /* remove from path/mc list */ 13368c2ecf20Sopenharmony_ci list_del_init(&neigh->list); 13378c2ecf20Sopenharmony_ci call_rcu(&neigh->rcu, ipoib_neigh_reclaim); 13388c2ecf20Sopenharmony_ci } else { 13398c2ecf20Sopenharmony_ci np = &neigh->hnext; 13408c2ecf20Sopenharmony_ci } 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci } 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ciout_unlock: 13468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 13478c2ecf20Sopenharmony_ci ipoib_mcast_remove_list(&remove_list); 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_cistatic void ipoib_reap_neigh(struct work_struct *work) 13518c2ecf20Sopenharmony_ci{ 13528c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = 13538c2ecf20Sopenharmony_ci container_of(work, struct ipoib_dev_priv, neigh_reap_task.work); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci __ipoib_reap_neigh(priv); 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci queue_delayed_work(priv->wq, &priv->neigh_reap_task, 13588c2ecf20Sopenharmony_ci arp_tbl.gc_interval); 13598c2ecf20Sopenharmony_ci} 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_cistatic struct ipoib_neigh *ipoib_neigh_ctor(u8 *daddr, 13638c2ecf20Sopenharmony_ci struct net_device *dev) 13648c2ecf20Sopenharmony_ci{ 13658c2ecf20Sopenharmony_ci struct ipoib_neigh *neigh; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci neigh = kzalloc(sizeof(*neigh), GFP_ATOMIC); 13688c2ecf20Sopenharmony_ci if (!neigh) 13698c2ecf20Sopenharmony_ci return NULL; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci neigh->dev = dev; 13728c2ecf20Sopenharmony_ci memcpy(&neigh->daddr, daddr, sizeof(neigh->daddr)); 13738c2ecf20Sopenharmony_ci skb_queue_head_init(&neigh->queue); 13748c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&neigh->list); 13758c2ecf20Sopenharmony_ci ipoib_cm_set(neigh, NULL); 13768c2ecf20Sopenharmony_ci /* one ref on behalf of the caller */ 13778c2ecf20Sopenharmony_ci atomic_set(&neigh->refcnt, 1); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci return neigh; 13808c2ecf20Sopenharmony_ci} 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_cistruct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr, 13838c2ecf20Sopenharmony_ci struct net_device *dev) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 13868c2ecf20Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 13878c2ecf20Sopenharmony_ci struct ipoib_neigh_hash *htbl; 13888c2ecf20Sopenharmony_ci struct ipoib_neigh *neigh; 13898c2ecf20Sopenharmony_ci u32 hash_val; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci htbl = rcu_dereference_protected(ntbl->htbl, 13928c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock)); 13938c2ecf20Sopenharmony_ci if (!htbl) { 13948c2ecf20Sopenharmony_ci neigh = NULL; 13958c2ecf20Sopenharmony_ci goto out_unlock; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci /* need to add a new neigh, but maybe some other thread succeeded? 13998c2ecf20Sopenharmony_ci * recalc hash, maybe hash resize took place so we do a search 14008c2ecf20Sopenharmony_ci */ 14018c2ecf20Sopenharmony_ci hash_val = ipoib_addr_hash(htbl, daddr); 14028c2ecf20Sopenharmony_ci for (neigh = rcu_dereference_protected(htbl->buckets[hash_val], 14038c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock)); 14048c2ecf20Sopenharmony_ci neigh != NULL; 14058c2ecf20Sopenharmony_ci neigh = rcu_dereference_protected(neigh->hnext, 14068c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock))) { 14078c2ecf20Sopenharmony_ci if (memcmp(daddr, neigh->daddr, INFINIBAND_ALEN) == 0) { 14088c2ecf20Sopenharmony_ci /* found, take one ref on behalf of the caller */ 14098c2ecf20Sopenharmony_ci if (!atomic_inc_not_zero(&neigh->refcnt)) { 14108c2ecf20Sopenharmony_ci /* deleted */ 14118c2ecf20Sopenharmony_ci neigh = NULL; 14128c2ecf20Sopenharmony_ci break; 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci neigh->alive = jiffies; 14158c2ecf20Sopenharmony_ci goto out_unlock; 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci } 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci neigh = ipoib_neigh_ctor(daddr, dev); 14208c2ecf20Sopenharmony_ci if (!neigh) 14218c2ecf20Sopenharmony_ci goto out_unlock; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci /* one ref on behalf of the hash table */ 14248c2ecf20Sopenharmony_ci atomic_inc(&neigh->refcnt); 14258c2ecf20Sopenharmony_ci neigh->alive = jiffies; 14268c2ecf20Sopenharmony_ci /* put in hash */ 14278c2ecf20Sopenharmony_ci rcu_assign_pointer(neigh->hnext, 14288c2ecf20Sopenharmony_ci rcu_dereference_protected(htbl->buckets[hash_val], 14298c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock))); 14308c2ecf20Sopenharmony_ci rcu_assign_pointer(htbl->buckets[hash_val], neigh); 14318c2ecf20Sopenharmony_ci atomic_inc(&ntbl->entries); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ciout_unlock: 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci return neigh; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_civoid ipoib_neigh_dtor(struct ipoib_neigh *neigh) 14398c2ecf20Sopenharmony_ci{ 14408c2ecf20Sopenharmony_ci /* neigh reference count was dropprd to zero */ 14418c2ecf20Sopenharmony_ci struct net_device *dev = neigh->dev; 14428c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 14438c2ecf20Sopenharmony_ci struct sk_buff *skb; 14448c2ecf20Sopenharmony_ci if (neigh->ah) 14458c2ecf20Sopenharmony_ci ipoib_put_ah(neigh->ah); 14468c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&neigh->queue))) { 14478c2ecf20Sopenharmony_ci ++dev->stats.tx_dropped; 14488c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci if (ipoib_cm_get(neigh)) 14518c2ecf20Sopenharmony_ci ipoib_cm_destroy_tx(ipoib_cm_get(neigh)); 14528c2ecf20Sopenharmony_ci ipoib_dbg(ipoib_priv(dev), 14538c2ecf20Sopenharmony_ci "neigh free for %06x %pI6\n", 14548c2ecf20Sopenharmony_ci IPOIB_QPN(neigh->daddr), 14558c2ecf20Sopenharmony_ci neigh->daddr + 4); 14568c2ecf20Sopenharmony_ci kfree(neigh); 14578c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&priv->ntbl.entries)) { 14588c2ecf20Sopenharmony_ci if (test_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags)) 14598c2ecf20Sopenharmony_ci complete(&priv->ntbl.flushed); 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_cistatic void ipoib_neigh_reclaim(struct rcu_head *rp) 14648c2ecf20Sopenharmony_ci{ 14658c2ecf20Sopenharmony_ci /* Called as a result of removal from hash table */ 14668c2ecf20Sopenharmony_ci struct ipoib_neigh *neigh = container_of(rp, struct ipoib_neigh, rcu); 14678c2ecf20Sopenharmony_ci /* note TX context may hold another ref */ 14688c2ecf20Sopenharmony_ci ipoib_neigh_put(neigh); 14698c2ecf20Sopenharmony_ci} 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_civoid ipoib_neigh_free(struct ipoib_neigh *neigh) 14728c2ecf20Sopenharmony_ci{ 14738c2ecf20Sopenharmony_ci struct net_device *dev = neigh->dev; 14748c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 14758c2ecf20Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 14768c2ecf20Sopenharmony_ci struct ipoib_neigh_hash *htbl; 14778c2ecf20Sopenharmony_ci struct ipoib_neigh __rcu **np; 14788c2ecf20Sopenharmony_ci struct ipoib_neigh *n; 14798c2ecf20Sopenharmony_ci u32 hash_val; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci htbl = rcu_dereference_protected(ntbl->htbl, 14828c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock)); 14838c2ecf20Sopenharmony_ci if (!htbl) 14848c2ecf20Sopenharmony_ci return; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci hash_val = ipoib_addr_hash(htbl, neigh->daddr); 14878c2ecf20Sopenharmony_ci np = &htbl->buckets[hash_val]; 14888c2ecf20Sopenharmony_ci for (n = rcu_dereference_protected(*np, 14898c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock)); 14908c2ecf20Sopenharmony_ci n != NULL; 14918c2ecf20Sopenharmony_ci n = rcu_dereference_protected(*np, 14928c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock))) { 14938c2ecf20Sopenharmony_ci if (n == neigh) { 14948c2ecf20Sopenharmony_ci /* found */ 14958c2ecf20Sopenharmony_ci rcu_assign_pointer(*np, 14968c2ecf20Sopenharmony_ci rcu_dereference_protected(neigh->hnext, 14978c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock))); 14988c2ecf20Sopenharmony_ci /* remove from parent list */ 14998c2ecf20Sopenharmony_ci list_del_init(&neigh->list); 15008c2ecf20Sopenharmony_ci call_rcu(&neigh->rcu, ipoib_neigh_reclaim); 15018c2ecf20Sopenharmony_ci return; 15028c2ecf20Sopenharmony_ci } else { 15038c2ecf20Sopenharmony_ci np = &n->hnext; 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci } 15068c2ecf20Sopenharmony_ci} 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_cistatic int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv) 15098c2ecf20Sopenharmony_ci{ 15108c2ecf20Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 15118c2ecf20Sopenharmony_ci struct ipoib_neigh_hash *htbl; 15128c2ecf20Sopenharmony_ci struct ipoib_neigh __rcu **buckets; 15138c2ecf20Sopenharmony_ci u32 size; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci clear_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags); 15168c2ecf20Sopenharmony_ci ntbl->htbl = NULL; 15178c2ecf20Sopenharmony_ci htbl = kzalloc(sizeof(*htbl), GFP_KERNEL); 15188c2ecf20Sopenharmony_ci if (!htbl) 15198c2ecf20Sopenharmony_ci return -ENOMEM; 15208c2ecf20Sopenharmony_ci size = roundup_pow_of_two(arp_tbl.gc_thresh3); 15218c2ecf20Sopenharmony_ci buckets = kvcalloc(size, sizeof(*buckets), GFP_KERNEL); 15228c2ecf20Sopenharmony_ci if (!buckets) { 15238c2ecf20Sopenharmony_ci kfree(htbl); 15248c2ecf20Sopenharmony_ci return -ENOMEM; 15258c2ecf20Sopenharmony_ci } 15268c2ecf20Sopenharmony_ci htbl->size = size; 15278c2ecf20Sopenharmony_ci htbl->mask = (size - 1); 15288c2ecf20Sopenharmony_ci htbl->buckets = buckets; 15298c2ecf20Sopenharmony_ci RCU_INIT_POINTER(ntbl->htbl, htbl); 15308c2ecf20Sopenharmony_ci htbl->ntbl = ntbl; 15318c2ecf20Sopenharmony_ci atomic_set(&ntbl->entries, 0); 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci /* start garbage collection */ 15348c2ecf20Sopenharmony_ci queue_delayed_work(priv->wq, &priv->neigh_reap_task, 15358c2ecf20Sopenharmony_ci arp_tbl.gc_interval); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci return 0; 15388c2ecf20Sopenharmony_ci} 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_cistatic void neigh_hash_free_rcu(struct rcu_head *head) 15418c2ecf20Sopenharmony_ci{ 15428c2ecf20Sopenharmony_ci struct ipoib_neigh_hash *htbl = container_of(head, 15438c2ecf20Sopenharmony_ci struct ipoib_neigh_hash, 15448c2ecf20Sopenharmony_ci rcu); 15458c2ecf20Sopenharmony_ci struct ipoib_neigh __rcu **buckets = htbl->buckets; 15468c2ecf20Sopenharmony_ci struct ipoib_neigh_table *ntbl = htbl->ntbl; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci kvfree(buckets); 15498c2ecf20Sopenharmony_ci kfree(htbl); 15508c2ecf20Sopenharmony_ci complete(&ntbl->deleted); 15518c2ecf20Sopenharmony_ci} 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_civoid ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid) 15548c2ecf20Sopenharmony_ci{ 15558c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 15568c2ecf20Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 15578c2ecf20Sopenharmony_ci struct ipoib_neigh_hash *htbl; 15588c2ecf20Sopenharmony_ci unsigned long flags; 15598c2ecf20Sopenharmony_ci int i; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci /* remove all neigh connected to a given path or mcast */ 15628c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci htbl = rcu_dereference_protected(ntbl->htbl, 15658c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock)); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci if (!htbl) 15688c2ecf20Sopenharmony_ci goto out_unlock; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci for (i = 0; i < htbl->size; i++) { 15718c2ecf20Sopenharmony_ci struct ipoib_neigh *neigh; 15728c2ecf20Sopenharmony_ci struct ipoib_neigh __rcu **np = &htbl->buckets[i]; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci while ((neigh = rcu_dereference_protected(*np, 15758c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock))) != NULL) { 15768c2ecf20Sopenharmony_ci /* delete neighs belong to this parent */ 15778c2ecf20Sopenharmony_ci if (!memcmp(gid, neigh->daddr + 4, sizeof (union ib_gid))) { 15788c2ecf20Sopenharmony_ci rcu_assign_pointer(*np, 15798c2ecf20Sopenharmony_ci rcu_dereference_protected(neigh->hnext, 15808c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock))); 15818c2ecf20Sopenharmony_ci /* remove from parent list */ 15828c2ecf20Sopenharmony_ci list_del_init(&neigh->list); 15838c2ecf20Sopenharmony_ci call_rcu(&neigh->rcu, ipoib_neigh_reclaim); 15848c2ecf20Sopenharmony_ci } else { 15858c2ecf20Sopenharmony_ci np = &neigh->hnext; 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci } 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ciout_unlock: 15918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 15928c2ecf20Sopenharmony_ci} 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_cistatic void ipoib_flush_neighs(struct ipoib_dev_priv *priv) 15958c2ecf20Sopenharmony_ci{ 15968c2ecf20Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 15978c2ecf20Sopenharmony_ci struct ipoib_neigh_hash *htbl; 15988c2ecf20Sopenharmony_ci unsigned long flags; 15998c2ecf20Sopenharmony_ci int i, wait_flushed = 0; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci init_completion(&priv->ntbl.flushed); 16028c2ecf20Sopenharmony_ci set_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags); 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci htbl = rcu_dereference_protected(ntbl->htbl, 16078c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock)); 16088c2ecf20Sopenharmony_ci if (!htbl) 16098c2ecf20Sopenharmony_ci goto out_unlock; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci wait_flushed = atomic_read(&priv->ntbl.entries); 16128c2ecf20Sopenharmony_ci if (!wait_flushed) 16138c2ecf20Sopenharmony_ci goto free_htbl; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci for (i = 0; i < htbl->size; i++) { 16168c2ecf20Sopenharmony_ci struct ipoib_neigh *neigh; 16178c2ecf20Sopenharmony_ci struct ipoib_neigh __rcu **np = &htbl->buckets[i]; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci while ((neigh = rcu_dereference_protected(*np, 16208c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock))) != NULL) { 16218c2ecf20Sopenharmony_ci rcu_assign_pointer(*np, 16228c2ecf20Sopenharmony_ci rcu_dereference_protected(neigh->hnext, 16238c2ecf20Sopenharmony_ci lockdep_is_held(&priv->lock))); 16248c2ecf20Sopenharmony_ci /* remove from path/mc list */ 16258c2ecf20Sopenharmony_ci list_del_init(&neigh->list); 16268c2ecf20Sopenharmony_ci call_rcu(&neigh->rcu, ipoib_neigh_reclaim); 16278c2ecf20Sopenharmony_ci } 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_cifree_htbl: 16318c2ecf20Sopenharmony_ci rcu_assign_pointer(ntbl->htbl, NULL); 16328c2ecf20Sopenharmony_ci call_rcu(&htbl->rcu, neigh_hash_free_rcu); 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ciout_unlock: 16358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 16368c2ecf20Sopenharmony_ci if (wait_flushed) 16378c2ecf20Sopenharmony_ci wait_for_completion(&priv->ntbl.flushed); 16388c2ecf20Sopenharmony_ci} 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_cistatic void ipoib_neigh_hash_uninit(struct net_device *dev) 16418c2ecf20Sopenharmony_ci{ 16428c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci ipoib_dbg(priv, "%s\n", __func__); 16458c2ecf20Sopenharmony_ci init_completion(&priv->ntbl.deleted); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&priv->neigh_reap_task); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci ipoib_flush_neighs(priv); 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci wait_for_completion(&priv->ntbl.deleted); 16528c2ecf20Sopenharmony_ci} 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_cistatic void ipoib_napi_add(struct net_device *dev) 16558c2ecf20Sopenharmony_ci{ 16568c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci netif_napi_add(dev, &priv->recv_napi, ipoib_rx_poll, IPOIB_NUM_WC); 16598c2ecf20Sopenharmony_ci netif_napi_add(dev, &priv->send_napi, ipoib_tx_poll, MAX_SEND_CQE); 16608c2ecf20Sopenharmony_ci} 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_cistatic void ipoib_napi_del(struct net_device *dev) 16638c2ecf20Sopenharmony_ci{ 16648c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci netif_napi_del(&priv->recv_napi); 16678c2ecf20Sopenharmony_ci netif_napi_del(&priv->send_napi); 16688c2ecf20Sopenharmony_ci} 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_cistatic void ipoib_dev_uninit_default(struct net_device *dev) 16718c2ecf20Sopenharmony_ci{ 16728c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci ipoib_transport_dev_cleanup(dev); 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci ipoib_napi_del(dev); 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci ipoib_cm_dev_cleanup(dev); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci kfree(priv->rx_ring); 16818c2ecf20Sopenharmony_ci vfree(priv->tx_ring); 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci priv->rx_ring = NULL; 16848c2ecf20Sopenharmony_ci priv->tx_ring = NULL; 16858c2ecf20Sopenharmony_ci} 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_cistatic int ipoib_dev_init_default(struct net_device *dev) 16888c2ecf20Sopenharmony_ci{ 16898c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci ipoib_napi_add(dev); 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci /* Allocate RX/TX "rings" to hold queued skbs */ 16948c2ecf20Sopenharmony_ci priv->rx_ring = kcalloc(ipoib_recvq_size, 16958c2ecf20Sopenharmony_ci sizeof(*priv->rx_ring), 16968c2ecf20Sopenharmony_ci GFP_KERNEL); 16978c2ecf20Sopenharmony_ci if (!priv->rx_ring) 16988c2ecf20Sopenharmony_ci goto out; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci priv->tx_ring = vzalloc(array_size(ipoib_sendq_size, 17018c2ecf20Sopenharmony_ci sizeof(*priv->tx_ring))); 17028c2ecf20Sopenharmony_ci if (!priv->tx_ring) { 17038c2ecf20Sopenharmony_ci pr_warn("%s: failed to allocate TX ring (%d entries)\n", 17048c2ecf20Sopenharmony_ci priv->ca->name, ipoib_sendq_size); 17058c2ecf20Sopenharmony_ci goto out_rx_ring_cleanup; 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci /* priv->tx_head, tx_tail and global_tx_tail/head are already 0 */ 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci if (ipoib_transport_dev_init(dev, priv->ca)) { 17118c2ecf20Sopenharmony_ci pr_warn("%s: ipoib_transport_dev_init failed\n", 17128c2ecf20Sopenharmony_ci priv->ca->name); 17138c2ecf20Sopenharmony_ci goto out_tx_ring_cleanup; 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci /* after qp created set dev address */ 17178c2ecf20Sopenharmony_ci priv->dev->dev_addr[1] = (priv->qp->qp_num >> 16) & 0xff; 17188c2ecf20Sopenharmony_ci priv->dev->dev_addr[2] = (priv->qp->qp_num >> 8) & 0xff; 17198c2ecf20Sopenharmony_ci priv->dev->dev_addr[3] = (priv->qp->qp_num) & 0xff; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci return 0; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ciout_tx_ring_cleanup: 17248c2ecf20Sopenharmony_ci vfree(priv->tx_ring); 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ciout_rx_ring_cleanup: 17278c2ecf20Sopenharmony_ci kfree(priv->rx_ring); 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ciout: 17308c2ecf20Sopenharmony_ci ipoib_napi_del(dev); 17318c2ecf20Sopenharmony_ci return -ENOMEM; 17328c2ecf20Sopenharmony_ci} 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_cistatic int ipoib_ioctl(struct net_device *dev, struct ifreq *ifr, 17358c2ecf20Sopenharmony_ci int cmd) 17368c2ecf20Sopenharmony_ci{ 17378c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci if (!priv->rn_ops->ndo_do_ioctl) 17408c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci return priv->rn_ops->ndo_do_ioctl(dev, ifr, cmd); 17438c2ecf20Sopenharmony_ci} 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_cistatic int ipoib_dev_init(struct net_device *dev) 17468c2ecf20Sopenharmony_ci{ 17478c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 17488c2ecf20Sopenharmony_ci int ret = -ENOMEM; 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci priv->qp = NULL; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci /* 17538c2ecf20Sopenharmony_ci * the various IPoIB tasks assume they will never race against 17548c2ecf20Sopenharmony_ci * themselves, so always use a single thread workqueue 17558c2ecf20Sopenharmony_ci */ 17568c2ecf20Sopenharmony_ci priv->wq = alloc_ordered_workqueue("ipoib_wq", WQ_MEM_RECLAIM); 17578c2ecf20Sopenharmony_ci if (!priv->wq) { 17588c2ecf20Sopenharmony_ci pr_warn("%s: failed to allocate device WQ\n", dev->name); 17598c2ecf20Sopenharmony_ci goto out; 17608c2ecf20Sopenharmony_ci } 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci /* create pd, which used both for control and datapath*/ 17638c2ecf20Sopenharmony_ci priv->pd = ib_alloc_pd(priv->ca, 0); 17648c2ecf20Sopenharmony_ci if (IS_ERR(priv->pd)) { 17658c2ecf20Sopenharmony_ci pr_warn("%s: failed to allocate PD\n", priv->ca->name); 17668c2ecf20Sopenharmony_ci goto clean_wq; 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci ret = priv->rn_ops->ndo_init(dev); 17708c2ecf20Sopenharmony_ci if (ret) { 17718c2ecf20Sopenharmony_ci pr_warn("%s failed to init HW resource\n", dev->name); 17728c2ecf20Sopenharmony_ci goto out_free_pd; 17738c2ecf20Sopenharmony_ci } 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci ret = ipoib_neigh_hash_init(priv); 17768c2ecf20Sopenharmony_ci if (ret) { 17778c2ecf20Sopenharmony_ci pr_warn("%s failed to init neigh hash\n", dev->name); 17788c2ecf20Sopenharmony_ci goto out_dev_uninit; 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci if (dev->flags & IFF_UP) { 17828c2ecf20Sopenharmony_ci if (ipoib_ib_dev_open(dev)) { 17838c2ecf20Sopenharmony_ci pr_warn("%s failed to open device\n", dev->name); 17848c2ecf20Sopenharmony_ci ret = -ENODEV; 17858c2ecf20Sopenharmony_ci goto out_hash_uninit; 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci } 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci return 0; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ciout_hash_uninit: 17928c2ecf20Sopenharmony_ci ipoib_neigh_hash_uninit(dev); 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ciout_dev_uninit: 17958c2ecf20Sopenharmony_ci ipoib_ib_dev_cleanup(dev); 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ciout_free_pd: 17988c2ecf20Sopenharmony_ci if (priv->pd) { 17998c2ecf20Sopenharmony_ci ib_dealloc_pd(priv->pd); 18008c2ecf20Sopenharmony_ci priv->pd = NULL; 18018c2ecf20Sopenharmony_ci } 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ciclean_wq: 18048c2ecf20Sopenharmony_ci if (priv->wq) { 18058c2ecf20Sopenharmony_ci destroy_workqueue(priv->wq); 18068c2ecf20Sopenharmony_ci priv->wq = NULL; 18078c2ecf20Sopenharmony_ci } 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ciout: 18108c2ecf20Sopenharmony_ci return ret; 18118c2ecf20Sopenharmony_ci} 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci/* 18148c2ecf20Sopenharmony_ci * This must be called before doing an unregister_netdev on a parent device to 18158c2ecf20Sopenharmony_ci * shutdown the IB event handler. 18168c2ecf20Sopenharmony_ci */ 18178c2ecf20Sopenharmony_cistatic void ipoib_parent_unregister_pre(struct net_device *ndev) 18188c2ecf20Sopenharmony_ci{ 18198c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci /* 18228c2ecf20Sopenharmony_ci * ipoib_set_mac checks netif_running before pushing work, clearing 18238c2ecf20Sopenharmony_ci * running ensures the it will not add more work. 18248c2ecf20Sopenharmony_ci */ 18258c2ecf20Sopenharmony_ci rtnl_lock(); 18268c2ecf20Sopenharmony_ci dev_change_flags(priv->dev, priv->dev->flags & ~IFF_UP, NULL); 18278c2ecf20Sopenharmony_ci rtnl_unlock(); 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci /* ipoib_event() cannot be running once this returns */ 18308c2ecf20Sopenharmony_ci ib_unregister_event_handler(&priv->event_handler); 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci /* 18338c2ecf20Sopenharmony_ci * Work on the queue grabs the rtnl lock, so this cannot be done while 18348c2ecf20Sopenharmony_ci * also holding it. 18358c2ecf20Sopenharmony_ci */ 18368c2ecf20Sopenharmony_ci flush_workqueue(ipoib_workqueue); 18378c2ecf20Sopenharmony_ci} 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_cistatic void ipoib_set_dev_features(struct ipoib_dev_priv *priv) 18408c2ecf20Sopenharmony_ci{ 18418c2ecf20Sopenharmony_ci priv->hca_caps = priv->ca->attrs.device_cap_flags; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci if (priv->hca_caps & IB_DEVICE_UD_IP_CSUM) { 18448c2ecf20Sopenharmony_ci priv->dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci if (priv->hca_caps & IB_DEVICE_UD_TSO) 18478c2ecf20Sopenharmony_ci priv->dev->hw_features |= NETIF_F_TSO; 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci priv->dev->features |= priv->dev->hw_features; 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci} 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_cistatic int ipoib_parent_init(struct net_device *ndev) 18548c2ecf20Sopenharmony_ci{ 18558c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 18568c2ecf20Sopenharmony_ci struct ib_port_attr attr; 18578c2ecf20Sopenharmony_ci int result; 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci result = ib_query_port(priv->ca, priv->port, &attr); 18608c2ecf20Sopenharmony_ci if (result) { 18618c2ecf20Sopenharmony_ci pr_warn("%s: ib_query_port %d failed\n", priv->ca->name, 18628c2ecf20Sopenharmony_ci priv->port); 18638c2ecf20Sopenharmony_ci return result; 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci priv->max_ib_mtu = rdma_mtu_from_attr(priv->ca, priv->port, &attr); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci result = ib_query_pkey(priv->ca, priv->port, 0, &priv->pkey); 18688c2ecf20Sopenharmony_ci if (result) { 18698c2ecf20Sopenharmony_ci pr_warn("%s: ib_query_pkey port %d failed (ret = %d)\n", 18708c2ecf20Sopenharmony_ci priv->ca->name, priv->port, result); 18718c2ecf20Sopenharmony_ci return result; 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci result = rdma_query_gid(priv->ca, priv->port, 0, &priv->local_gid); 18758c2ecf20Sopenharmony_ci if (result) { 18768c2ecf20Sopenharmony_ci pr_warn("%s: rdma_query_gid port %d failed (ret = %d)\n", 18778c2ecf20Sopenharmony_ci priv->ca->name, priv->port, result); 18788c2ecf20Sopenharmony_ci return result; 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, 18818c2ecf20Sopenharmony_ci sizeof(union ib_gid)); 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci SET_NETDEV_DEV(priv->dev, priv->ca->dev.parent); 18848c2ecf20Sopenharmony_ci priv->dev->dev_port = priv->port - 1; 18858c2ecf20Sopenharmony_ci /* Let's set this one too for backwards compatibility. */ 18868c2ecf20Sopenharmony_ci priv->dev->dev_id = priv->port - 1; 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci return 0; 18898c2ecf20Sopenharmony_ci} 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_cistatic void ipoib_child_init(struct net_device *ndev) 18928c2ecf20Sopenharmony_ci{ 18938c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 18948c2ecf20Sopenharmony_ci struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent); 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci priv->max_ib_mtu = ppriv->max_ib_mtu; 18978c2ecf20Sopenharmony_ci set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags); 18988c2ecf20Sopenharmony_ci if (memchr_inv(priv->dev->dev_addr, 0, INFINIBAND_ALEN)) 18998c2ecf20Sopenharmony_ci memcpy(&priv->local_gid, priv->dev->dev_addr + 4, 19008c2ecf20Sopenharmony_ci sizeof(priv->local_gid)); 19018c2ecf20Sopenharmony_ci else { 19028c2ecf20Sopenharmony_ci memcpy(priv->dev->dev_addr, ppriv->dev->dev_addr, 19038c2ecf20Sopenharmony_ci INFINIBAND_ALEN); 19048c2ecf20Sopenharmony_ci memcpy(&priv->local_gid, &ppriv->local_gid, 19058c2ecf20Sopenharmony_ci sizeof(priv->local_gid)); 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci} 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_cistatic int ipoib_ndo_init(struct net_device *ndev) 19108c2ecf20Sopenharmony_ci{ 19118c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 19128c2ecf20Sopenharmony_ci int rc; 19138c2ecf20Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(ndev); 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci if (priv->parent) { 19168c2ecf20Sopenharmony_ci ipoib_child_init(ndev); 19178c2ecf20Sopenharmony_ci } else { 19188c2ecf20Sopenharmony_ci rc = ipoib_parent_init(ndev); 19198c2ecf20Sopenharmony_ci if (rc) 19208c2ecf20Sopenharmony_ci return rc; 19218c2ecf20Sopenharmony_ci } 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci /* MTU will be reset when mcast join happens */ 19248c2ecf20Sopenharmony_ci ndev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu); 19258c2ecf20Sopenharmony_ci priv->mcast_mtu = priv->admin_mtu = ndev->mtu; 19268c2ecf20Sopenharmony_ci rn->mtu = priv->mcast_mtu; 19278c2ecf20Sopenharmony_ci ndev->max_mtu = IPOIB_CM_MTU; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci ndev->neigh_priv_len = sizeof(struct ipoib_neigh); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci /* 19328c2ecf20Sopenharmony_ci * Set the full membership bit, so that we join the right 19338c2ecf20Sopenharmony_ci * broadcast group, etc. 19348c2ecf20Sopenharmony_ci */ 19358c2ecf20Sopenharmony_ci priv->pkey |= 0x8000; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci ndev->broadcast[8] = priv->pkey >> 8; 19388c2ecf20Sopenharmony_ci ndev->broadcast[9] = priv->pkey & 0xff; 19398c2ecf20Sopenharmony_ci set_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags); 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci ipoib_set_dev_features(priv); 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci rc = ipoib_dev_init(ndev); 19448c2ecf20Sopenharmony_ci if (rc) { 19458c2ecf20Sopenharmony_ci pr_warn("%s: failed to initialize device: %s port %d (ret = %d)\n", 19468c2ecf20Sopenharmony_ci priv->ca->name, priv->dev->name, priv->port, rc); 19478c2ecf20Sopenharmony_ci return rc; 19488c2ecf20Sopenharmony_ci } 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci if (priv->parent) { 19518c2ecf20Sopenharmony_ci struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent); 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci dev_hold(priv->parent); 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci down_write(&ppriv->vlan_rwsem); 19568c2ecf20Sopenharmony_ci list_add_tail(&priv->list, &ppriv->child_intfs); 19578c2ecf20Sopenharmony_ci up_write(&ppriv->vlan_rwsem); 19588c2ecf20Sopenharmony_ci } 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci return 0; 19618c2ecf20Sopenharmony_ci} 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_cistatic void ipoib_ndo_uninit(struct net_device *dev) 19648c2ecf20Sopenharmony_ci{ 19658c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci ASSERT_RTNL(); 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci /* 19708c2ecf20Sopenharmony_ci * ipoib_remove_one guarantees the children are removed before the 19718c2ecf20Sopenharmony_ci * parent, and that is the only place where a parent can be removed. 19728c2ecf20Sopenharmony_ci */ 19738c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&priv->child_intfs)); 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci if (priv->parent) { 19768c2ecf20Sopenharmony_ci struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent); 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci down_write(&ppriv->vlan_rwsem); 19798c2ecf20Sopenharmony_ci list_del(&priv->list); 19808c2ecf20Sopenharmony_ci up_write(&ppriv->vlan_rwsem); 19818c2ecf20Sopenharmony_ci } 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci ipoib_neigh_hash_uninit(dev); 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci ipoib_ib_dev_cleanup(dev); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci /* no more works over the priv->wq */ 19888c2ecf20Sopenharmony_ci if (priv->wq) { 19898c2ecf20Sopenharmony_ci /* See ipoib_mcast_carrier_on_task() */ 19908c2ecf20Sopenharmony_ci WARN_ON(test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)); 19918c2ecf20Sopenharmony_ci flush_workqueue(priv->wq); 19928c2ecf20Sopenharmony_ci destroy_workqueue(priv->wq); 19938c2ecf20Sopenharmony_ci priv->wq = NULL; 19948c2ecf20Sopenharmony_ci } 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci if (priv->parent) 19978c2ecf20Sopenharmony_ci dev_put(priv->parent); 19988c2ecf20Sopenharmony_ci} 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_cistatic int ipoib_set_vf_link_state(struct net_device *dev, int vf, int link_state) 20018c2ecf20Sopenharmony_ci{ 20028c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci return ib_set_vf_link_state(priv->ca, vf, priv->port, link_state); 20058c2ecf20Sopenharmony_ci} 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_cistatic int ipoib_get_vf_config(struct net_device *dev, int vf, 20088c2ecf20Sopenharmony_ci struct ifla_vf_info *ivf) 20098c2ecf20Sopenharmony_ci{ 20108c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 20118c2ecf20Sopenharmony_ci int err; 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci err = ib_get_vf_config(priv->ca, vf, priv->port, ivf); 20148c2ecf20Sopenharmony_ci if (err) 20158c2ecf20Sopenharmony_ci return err; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci ivf->vf = vf; 20188c2ecf20Sopenharmony_ci memcpy(ivf->mac, dev->dev_addr, dev->addr_len); 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci return 0; 20218c2ecf20Sopenharmony_ci} 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_cistatic int ipoib_set_vf_guid(struct net_device *dev, int vf, u64 guid, int type) 20248c2ecf20Sopenharmony_ci{ 20258c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci if (type != IFLA_VF_IB_NODE_GUID && type != IFLA_VF_IB_PORT_GUID) 20288c2ecf20Sopenharmony_ci return -EINVAL; 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci return ib_set_vf_guid(priv->ca, vf, priv->port, guid, type); 20318c2ecf20Sopenharmony_ci} 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_cistatic int ipoib_get_vf_guid(struct net_device *dev, int vf, 20348c2ecf20Sopenharmony_ci struct ifla_vf_guid *node_guid, 20358c2ecf20Sopenharmony_ci struct ifla_vf_guid *port_guid) 20368c2ecf20Sopenharmony_ci{ 20378c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci return ib_get_vf_guid(priv->ca, vf, priv->port, node_guid, port_guid); 20408c2ecf20Sopenharmony_ci} 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_cistatic int ipoib_get_vf_stats(struct net_device *dev, int vf, 20438c2ecf20Sopenharmony_ci struct ifla_vf_stats *vf_stats) 20448c2ecf20Sopenharmony_ci{ 20458c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci return ib_get_vf_stats(priv->ca, vf, priv->port, vf_stats); 20488c2ecf20Sopenharmony_ci} 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_cistatic const struct header_ops ipoib_header_ops = { 20518c2ecf20Sopenharmony_ci .create = ipoib_hard_header, 20528c2ecf20Sopenharmony_ci}; 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_cistatic const struct net_device_ops ipoib_netdev_ops_pf = { 20558c2ecf20Sopenharmony_ci .ndo_init = ipoib_ndo_init, 20568c2ecf20Sopenharmony_ci .ndo_uninit = ipoib_ndo_uninit, 20578c2ecf20Sopenharmony_ci .ndo_open = ipoib_open, 20588c2ecf20Sopenharmony_ci .ndo_stop = ipoib_stop, 20598c2ecf20Sopenharmony_ci .ndo_change_mtu = ipoib_change_mtu, 20608c2ecf20Sopenharmony_ci .ndo_fix_features = ipoib_fix_features, 20618c2ecf20Sopenharmony_ci .ndo_start_xmit = ipoib_start_xmit, 20628c2ecf20Sopenharmony_ci .ndo_tx_timeout = ipoib_timeout, 20638c2ecf20Sopenharmony_ci .ndo_set_rx_mode = ipoib_set_mcast_list, 20648c2ecf20Sopenharmony_ci .ndo_get_iflink = ipoib_get_iflink, 20658c2ecf20Sopenharmony_ci .ndo_set_vf_link_state = ipoib_set_vf_link_state, 20668c2ecf20Sopenharmony_ci .ndo_get_vf_config = ipoib_get_vf_config, 20678c2ecf20Sopenharmony_ci .ndo_get_vf_stats = ipoib_get_vf_stats, 20688c2ecf20Sopenharmony_ci .ndo_get_vf_guid = ipoib_get_vf_guid, 20698c2ecf20Sopenharmony_ci .ndo_set_vf_guid = ipoib_set_vf_guid, 20708c2ecf20Sopenharmony_ci .ndo_set_mac_address = ipoib_set_mac, 20718c2ecf20Sopenharmony_ci .ndo_get_stats64 = ipoib_get_stats, 20728c2ecf20Sopenharmony_ci .ndo_do_ioctl = ipoib_ioctl, 20738c2ecf20Sopenharmony_ci}; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_cistatic const struct net_device_ops ipoib_netdev_ops_vf = { 20768c2ecf20Sopenharmony_ci .ndo_init = ipoib_ndo_init, 20778c2ecf20Sopenharmony_ci .ndo_uninit = ipoib_ndo_uninit, 20788c2ecf20Sopenharmony_ci .ndo_open = ipoib_open, 20798c2ecf20Sopenharmony_ci .ndo_stop = ipoib_stop, 20808c2ecf20Sopenharmony_ci .ndo_change_mtu = ipoib_change_mtu, 20818c2ecf20Sopenharmony_ci .ndo_fix_features = ipoib_fix_features, 20828c2ecf20Sopenharmony_ci .ndo_start_xmit = ipoib_start_xmit, 20838c2ecf20Sopenharmony_ci .ndo_tx_timeout = ipoib_timeout, 20848c2ecf20Sopenharmony_ci .ndo_set_rx_mode = ipoib_set_mcast_list, 20858c2ecf20Sopenharmony_ci .ndo_get_iflink = ipoib_get_iflink, 20868c2ecf20Sopenharmony_ci .ndo_get_stats64 = ipoib_get_stats, 20878c2ecf20Sopenharmony_ci .ndo_do_ioctl = ipoib_ioctl, 20888c2ecf20Sopenharmony_ci}; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_cistatic const struct net_device_ops ipoib_netdev_default_pf = { 20918c2ecf20Sopenharmony_ci .ndo_init = ipoib_dev_init_default, 20928c2ecf20Sopenharmony_ci .ndo_uninit = ipoib_dev_uninit_default, 20938c2ecf20Sopenharmony_ci .ndo_open = ipoib_ib_dev_open_default, 20948c2ecf20Sopenharmony_ci .ndo_stop = ipoib_ib_dev_stop_default, 20958c2ecf20Sopenharmony_ci}; 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_civoid ipoib_setup_common(struct net_device *dev) 20988c2ecf20Sopenharmony_ci{ 20998c2ecf20Sopenharmony_ci dev->header_ops = &ipoib_header_ops; 21008c2ecf20Sopenharmony_ci dev->netdev_ops = &ipoib_netdev_default_pf; 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci ipoib_set_ethtool_ops(dev); 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci dev->watchdog_timeo = HZ; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci dev->flags |= IFF_BROADCAST | IFF_MULTICAST; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci dev->hard_header_len = IPOIB_HARD_LEN; 21098c2ecf20Sopenharmony_ci dev->addr_len = INFINIBAND_ALEN; 21108c2ecf20Sopenharmony_ci dev->type = ARPHRD_INFINIBAND; 21118c2ecf20Sopenharmony_ci dev->tx_queue_len = ipoib_sendq_size * 2; 21128c2ecf20Sopenharmony_ci dev->features = (NETIF_F_VLAN_CHALLENGED | 21138c2ecf20Sopenharmony_ci NETIF_F_HIGHDMA); 21148c2ecf20Sopenharmony_ci netif_keep_dst(dev); 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci /* 21198c2ecf20Sopenharmony_ci * unregister_netdev always frees the netdev, we use this mode 21208c2ecf20Sopenharmony_ci * consistently to unify all the various unregister paths, including 21218c2ecf20Sopenharmony_ci * those connected to rtnl_link_ops which require it. 21228c2ecf20Sopenharmony_ci */ 21238c2ecf20Sopenharmony_ci dev->needs_free_netdev = true; 21248c2ecf20Sopenharmony_ci} 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_cistatic void ipoib_build_priv(struct net_device *dev) 21278c2ecf20Sopenharmony_ci{ 21288c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci priv->dev = dev; 21318c2ecf20Sopenharmony_ci spin_lock_init(&priv->lock); 21328c2ecf20Sopenharmony_ci init_rwsem(&priv->vlan_rwsem); 21338c2ecf20Sopenharmony_ci mutex_init(&priv->mcast_mutex); 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->path_list); 21368c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->child_intfs); 21378c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->dead_ahs); 21388c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->multicast_list); 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task); 21418c2ecf20Sopenharmony_ci INIT_WORK(&priv->carrier_on_task, ipoib_mcast_carrier_on_task); 21428c2ecf20Sopenharmony_ci INIT_WORK(&priv->flush_light, ipoib_ib_dev_flush_light); 21438c2ecf20Sopenharmony_ci INIT_WORK(&priv->flush_normal, ipoib_ib_dev_flush_normal); 21448c2ecf20Sopenharmony_ci INIT_WORK(&priv->flush_heavy, ipoib_ib_dev_flush_heavy); 21458c2ecf20Sopenharmony_ci INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task); 21468c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&priv->ah_reap_task, ipoib_reap_ah); 21478c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&priv->neigh_reap_task, ipoib_reap_neigh); 21488c2ecf20Sopenharmony_ci} 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_cistatic struct net_device *ipoib_alloc_netdev(struct ib_device *hca, u8 port, 21518c2ecf20Sopenharmony_ci const char *name) 21528c2ecf20Sopenharmony_ci{ 21538c2ecf20Sopenharmony_ci struct net_device *dev; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci dev = rdma_alloc_netdev(hca, port, RDMA_NETDEV_IPOIB, name, 21568c2ecf20Sopenharmony_ci NET_NAME_UNKNOWN, ipoib_setup_common); 21578c2ecf20Sopenharmony_ci if (!IS_ERR(dev) || PTR_ERR(dev) != -EOPNOTSUPP) 21588c2ecf20Sopenharmony_ci return dev; 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci dev = alloc_netdev(sizeof(struct rdma_netdev), name, NET_NAME_UNKNOWN, 21618c2ecf20Sopenharmony_ci ipoib_setup_common); 21628c2ecf20Sopenharmony_ci if (!dev) 21638c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 21648c2ecf20Sopenharmony_ci return dev; 21658c2ecf20Sopenharmony_ci} 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ciint ipoib_intf_init(struct ib_device *hca, u8 port, const char *name, 21688c2ecf20Sopenharmony_ci struct net_device *dev) 21698c2ecf20Sopenharmony_ci{ 21708c2ecf20Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 21718c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv; 21728c2ecf20Sopenharmony_ci int rc; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci priv = kzalloc(sizeof(*priv), GFP_KERNEL); 21758c2ecf20Sopenharmony_ci if (!priv) 21768c2ecf20Sopenharmony_ci return -ENOMEM; 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci priv->ca = hca; 21798c2ecf20Sopenharmony_ci priv->port = port; 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci rc = rdma_init_netdev(hca, port, RDMA_NETDEV_IPOIB, name, 21828c2ecf20Sopenharmony_ci NET_NAME_UNKNOWN, ipoib_setup_common, dev); 21838c2ecf20Sopenharmony_ci if (rc) { 21848c2ecf20Sopenharmony_ci if (rc != -EOPNOTSUPP) 21858c2ecf20Sopenharmony_ci goto out; 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci rn->send = ipoib_send; 21888c2ecf20Sopenharmony_ci rn->attach_mcast = ipoib_mcast_attach; 21898c2ecf20Sopenharmony_ci rn->detach_mcast = ipoib_mcast_detach; 21908c2ecf20Sopenharmony_ci rn->hca = hca; 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci rc = netif_set_real_num_tx_queues(dev, 1); 21938c2ecf20Sopenharmony_ci if (rc) 21948c2ecf20Sopenharmony_ci goto out; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci rc = netif_set_real_num_rx_queues(dev, 1); 21978c2ecf20Sopenharmony_ci if (rc) 21988c2ecf20Sopenharmony_ci goto out; 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci priv->rn_ops = dev->netdev_ops; 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci if (hca->attrs.device_cap_flags & IB_DEVICE_VIRTUAL_FUNCTION) 22048c2ecf20Sopenharmony_ci dev->netdev_ops = &ipoib_netdev_ops_vf; 22058c2ecf20Sopenharmony_ci else 22068c2ecf20Sopenharmony_ci dev->netdev_ops = &ipoib_netdev_ops_pf; 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci rn->clnt_priv = priv; 22098c2ecf20Sopenharmony_ci /* 22108c2ecf20Sopenharmony_ci * Only the child register_netdev flows can handle priv_destructor 22118c2ecf20Sopenharmony_ci * being set, so we force it to NULL here and handle manually until it 22128c2ecf20Sopenharmony_ci * is safe to turn on. 22138c2ecf20Sopenharmony_ci */ 22148c2ecf20Sopenharmony_ci priv->next_priv_destructor = dev->priv_destructor; 22158c2ecf20Sopenharmony_ci dev->priv_destructor = NULL; 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci ipoib_build_priv(dev); 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci return 0; 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ciout: 22228c2ecf20Sopenharmony_ci kfree(priv); 22238c2ecf20Sopenharmony_ci return rc; 22248c2ecf20Sopenharmony_ci} 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_cistruct net_device *ipoib_intf_alloc(struct ib_device *hca, u8 port, 22278c2ecf20Sopenharmony_ci const char *name) 22288c2ecf20Sopenharmony_ci{ 22298c2ecf20Sopenharmony_ci struct net_device *dev; 22308c2ecf20Sopenharmony_ci int rc; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci dev = ipoib_alloc_netdev(hca, port, name); 22338c2ecf20Sopenharmony_ci if (IS_ERR(dev)) 22348c2ecf20Sopenharmony_ci return dev; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci rc = ipoib_intf_init(hca, port, name, dev); 22378c2ecf20Sopenharmony_ci if (rc) { 22388c2ecf20Sopenharmony_ci free_netdev(dev); 22398c2ecf20Sopenharmony_ci return ERR_PTR(rc); 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci /* 22438c2ecf20Sopenharmony_ci * Upon success the caller must ensure ipoib_intf_free is called or 22448c2ecf20Sopenharmony_ci * register_netdevice succeed'd and priv_destructor is set to 22458c2ecf20Sopenharmony_ci * ipoib_intf_free. 22468c2ecf20Sopenharmony_ci */ 22478c2ecf20Sopenharmony_ci return dev; 22488c2ecf20Sopenharmony_ci} 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_civoid ipoib_intf_free(struct net_device *dev) 22518c2ecf20Sopenharmony_ci{ 22528c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 22538c2ecf20Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci dev->priv_destructor = priv->next_priv_destructor; 22568c2ecf20Sopenharmony_ci if (dev->priv_destructor) 22578c2ecf20Sopenharmony_ci dev->priv_destructor(dev); 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci /* 22608c2ecf20Sopenharmony_ci * There are some error flows around register_netdev failing that may 22618c2ecf20Sopenharmony_ci * attempt to call priv_destructor twice, prevent that from happening. 22628c2ecf20Sopenharmony_ci */ 22638c2ecf20Sopenharmony_ci dev->priv_destructor = NULL; 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci /* unregister/destroy is very complicated. Make bugs more obvious. */ 22668c2ecf20Sopenharmony_ci rn->clnt_priv = NULL; 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci kfree(priv); 22698c2ecf20Sopenharmony_ci} 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_cistatic ssize_t show_pkey(struct device *dev, 22728c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 22738c2ecf20Sopenharmony_ci{ 22748c2ecf20Sopenharmony_ci struct net_device *ndev = to_net_dev(dev); 22758c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci return sprintf(buf, "0x%04x\n", priv->pkey); 22788c2ecf20Sopenharmony_ci} 22798c2ecf20Sopenharmony_cistatic DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_cistatic ssize_t show_umcast(struct device *dev, 22828c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 22838c2ecf20Sopenharmony_ci{ 22848c2ecf20Sopenharmony_ci struct net_device *ndev = to_net_dev(dev); 22858c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", test_bit(IPOIB_FLAG_UMCAST, &priv->flags)); 22888c2ecf20Sopenharmony_ci} 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_civoid ipoib_set_umcast(struct net_device *ndev, int umcast_val) 22918c2ecf20Sopenharmony_ci{ 22928c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci if (umcast_val > 0) { 22958c2ecf20Sopenharmony_ci set_bit(IPOIB_FLAG_UMCAST, &priv->flags); 22968c2ecf20Sopenharmony_ci ipoib_warn(priv, "ignoring multicast groups joined directly " 22978c2ecf20Sopenharmony_ci "by userspace\n"); 22988c2ecf20Sopenharmony_ci } else 22998c2ecf20Sopenharmony_ci clear_bit(IPOIB_FLAG_UMCAST, &priv->flags); 23008c2ecf20Sopenharmony_ci} 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_cistatic ssize_t set_umcast(struct device *dev, 23038c2ecf20Sopenharmony_ci struct device_attribute *attr, 23048c2ecf20Sopenharmony_ci const char *buf, size_t count) 23058c2ecf20Sopenharmony_ci{ 23068c2ecf20Sopenharmony_ci unsigned long umcast_val = simple_strtoul(buf, NULL, 0); 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci ipoib_set_umcast(to_net_dev(dev), umcast_val); 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci return count; 23118c2ecf20Sopenharmony_ci} 23128c2ecf20Sopenharmony_cistatic DEVICE_ATTR(umcast, S_IWUSR | S_IRUGO, show_umcast, set_umcast); 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ciint ipoib_add_umcast_attr(struct net_device *dev) 23158c2ecf20Sopenharmony_ci{ 23168c2ecf20Sopenharmony_ci return device_create_file(&dev->dev, &dev_attr_umcast); 23178c2ecf20Sopenharmony_ci} 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_cistatic void set_base_guid(struct ipoib_dev_priv *priv, union ib_gid *gid) 23208c2ecf20Sopenharmony_ci{ 23218c2ecf20Sopenharmony_ci struct ipoib_dev_priv *child_priv; 23228c2ecf20Sopenharmony_ci struct net_device *netdev = priv->dev; 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci netif_addr_lock_bh(netdev); 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci memcpy(&priv->local_gid.global.interface_id, 23278c2ecf20Sopenharmony_ci &gid->global.interface_id, 23288c2ecf20Sopenharmony_ci sizeof(gid->global.interface_id)); 23298c2ecf20Sopenharmony_ci memcpy(netdev->dev_addr + 4, &priv->local_gid, sizeof(priv->local_gid)); 23308c2ecf20Sopenharmony_ci clear_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags); 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci netif_addr_unlock_bh(netdev); 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { 23358c2ecf20Sopenharmony_ci down_read(&priv->vlan_rwsem); 23368c2ecf20Sopenharmony_ci list_for_each_entry(child_priv, &priv->child_intfs, list) 23378c2ecf20Sopenharmony_ci set_base_guid(child_priv, gid); 23388c2ecf20Sopenharmony_ci up_read(&priv->vlan_rwsem); 23398c2ecf20Sopenharmony_ci } 23408c2ecf20Sopenharmony_ci} 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_cistatic int ipoib_check_lladdr(struct net_device *dev, 23438c2ecf20Sopenharmony_ci struct sockaddr_storage *ss) 23448c2ecf20Sopenharmony_ci{ 23458c2ecf20Sopenharmony_ci union ib_gid *gid = (union ib_gid *)(ss->__data + 4); 23468c2ecf20Sopenharmony_ci int ret = 0; 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci netif_addr_lock_bh(dev); 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci /* Make sure the QPN, reserved and subnet prefix match the current 23518c2ecf20Sopenharmony_ci * lladdr, it also makes sure the lladdr is unicast. 23528c2ecf20Sopenharmony_ci */ 23538c2ecf20Sopenharmony_ci if (memcmp(dev->dev_addr, ss->__data, 23548c2ecf20Sopenharmony_ci 4 + sizeof(gid->global.subnet_prefix)) || 23558c2ecf20Sopenharmony_ci gid->global.interface_id == 0) 23568c2ecf20Sopenharmony_ci ret = -EINVAL; 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci netif_addr_unlock_bh(dev); 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci return ret; 23618c2ecf20Sopenharmony_ci} 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_cistatic int ipoib_set_mac(struct net_device *dev, void *addr) 23648c2ecf20Sopenharmony_ci{ 23658c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 23668c2ecf20Sopenharmony_ci struct sockaddr_storage *ss = addr; 23678c2ecf20Sopenharmony_ci int ret; 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev)) 23708c2ecf20Sopenharmony_ci return -EBUSY; 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci ret = ipoib_check_lladdr(dev, ss); 23738c2ecf20Sopenharmony_ci if (ret) 23748c2ecf20Sopenharmony_ci return ret; 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci set_base_guid(priv, (union ib_gid *)(ss->__data + 4)); 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci queue_work(ipoib_workqueue, &priv->flush_light); 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci return 0; 23818c2ecf20Sopenharmony_ci} 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_cistatic ssize_t create_child(struct device *dev, 23848c2ecf20Sopenharmony_ci struct device_attribute *attr, 23858c2ecf20Sopenharmony_ci const char *buf, size_t count) 23868c2ecf20Sopenharmony_ci{ 23878c2ecf20Sopenharmony_ci int pkey; 23888c2ecf20Sopenharmony_ci int ret; 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci if (sscanf(buf, "%i", &pkey) != 1) 23918c2ecf20Sopenharmony_ci return -EINVAL; 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci if (pkey <= 0 || pkey > 0xffff || pkey == 0x8000) 23948c2ecf20Sopenharmony_ci return -EINVAL; 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci ret = ipoib_vlan_add(to_net_dev(dev), pkey); 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci return ret ? ret : count; 23998c2ecf20Sopenharmony_ci} 24008c2ecf20Sopenharmony_cistatic DEVICE_ATTR(create_child, S_IWUSR, NULL, create_child); 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_cistatic ssize_t delete_child(struct device *dev, 24038c2ecf20Sopenharmony_ci struct device_attribute *attr, 24048c2ecf20Sopenharmony_ci const char *buf, size_t count) 24058c2ecf20Sopenharmony_ci{ 24068c2ecf20Sopenharmony_ci int pkey; 24078c2ecf20Sopenharmony_ci int ret; 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci if (sscanf(buf, "%i", &pkey) != 1) 24108c2ecf20Sopenharmony_ci return -EINVAL; 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci if (pkey < 0 || pkey > 0xffff) 24138c2ecf20Sopenharmony_ci return -EINVAL; 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci ret = ipoib_vlan_delete(to_net_dev(dev), pkey); 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci return ret ? ret : count; 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci} 24208c2ecf20Sopenharmony_cistatic DEVICE_ATTR(delete_child, S_IWUSR, NULL, delete_child); 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ciint ipoib_add_pkey_attr(struct net_device *dev) 24238c2ecf20Sopenharmony_ci{ 24248c2ecf20Sopenharmony_ci return device_create_file(&dev->dev, &dev_attr_pkey); 24258c2ecf20Sopenharmony_ci} 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci/* 24288c2ecf20Sopenharmony_ci * We erroneously exposed the iface's port number in the dev_id 24298c2ecf20Sopenharmony_ci * sysfs field long after dev_port was introduced for that purpose[1], 24308c2ecf20Sopenharmony_ci * and we need to stop everyone from relying on that. 24318c2ecf20Sopenharmony_ci * Let's overload the shower routine for the dev_id file here 24328c2ecf20Sopenharmony_ci * to gently bring the issue up. 24338c2ecf20Sopenharmony_ci * 24348c2ecf20Sopenharmony_ci * [1] https://www.spinics.net/lists/netdev/msg272123.html 24358c2ecf20Sopenharmony_ci */ 24368c2ecf20Sopenharmony_cistatic ssize_t dev_id_show(struct device *dev, 24378c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 24388c2ecf20Sopenharmony_ci{ 24398c2ecf20Sopenharmony_ci struct net_device *ndev = to_net_dev(dev); 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci /* 24428c2ecf20Sopenharmony_ci * ndev->dev_port will be equal to 0 in old kernel prior to commit 24438c2ecf20Sopenharmony_ci * 9b8b2a323008 ("IB/ipoib: Use dev_port to expose network interface 24448c2ecf20Sopenharmony_ci * port numbers") Zero was chosen as special case for user space 24458c2ecf20Sopenharmony_ci * applications to fallback and query dev_id to check if it has 24468c2ecf20Sopenharmony_ci * different value or not. 24478c2ecf20Sopenharmony_ci * 24488c2ecf20Sopenharmony_ci * Don't print warning in such scenario. 24498c2ecf20Sopenharmony_ci * 24508c2ecf20Sopenharmony_ci * https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-net_id.c#L358 24518c2ecf20Sopenharmony_ci */ 24528c2ecf20Sopenharmony_ci if (ndev->dev_port && ndev->dev_id == ndev->dev_port) 24538c2ecf20Sopenharmony_ci netdev_info_once(ndev, 24548c2ecf20Sopenharmony_ci "\"%s\" wants to know my dev_id. Should it look at dev_port instead? See Documentation/ABI/testing/sysfs-class-net for more info.\n", 24558c2ecf20Sopenharmony_ci current->comm); 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci return sprintf(buf, "%#x\n", ndev->dev_id); 24588c2ecf20Sopenharmony_ci} 24598c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(dev_id); 24608c2ecf20Sopenharmony_ci 24618c2ecf20Sopenharmony_cistatic int ipoib_intercept_dev_id_attr(struct net_device *dev) 24628c2ecf20Sopenharmony_ci{ 24638c2ecf20Sopenharmony_ci device_remove_file(&dev->dev, &dev_attr_dev_id); 24648c2ecf20Sopenharmony_ci return device_create_file(&dev->dev, &dev_attr_dev_id); 24658c2ecf20Sopenharmony_ci} 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_cistatic struct net_device *ipoib_add_port(const char *format, 24688c2ecf20Sopenharmony_ci struct ib_device *hca, u8 port) 24698c2ecf20Sopenharmony_ci{ 24708c2ecf20Sopenharmony_ci struct rtnl_link_ops *ops = ipoib_get_link_ops(); 24718c2ecf20Sopenharmony_ci struct rdma_netdev_alloc_params params; 24728c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv; 24738c2ecf20Sopenharmony_ci struct net_device *ndev; 24748c2ecf20Sopenharmony_ci int result; 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci ndev = ipoib_intf_alloc(hca, port, format); 24778c2ecf20Sopenharmony_ci if (IS_ERR(ndev)) { 24788c2ecf20Sopenharmony_ci pr_warn("%s, %d: ipoib_intf_alloc failed %ld\n", hca->name, port, 24798c2ecf20Sopenharmony_ci PTR_ERR(ndev)); 24808c2ecf20Sopenharmony_ci return ndev; 24818c2ecf20Sopenharmony_ci } 24828c2ecf20Sopenharmony_ci priv = ipoib_priv(ndev); 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci INIT_IB_EVENT_HANDLER(&priv->event_handler, 24858c2ecf20Sopenharmony_ci priv->ca, ipoib_event); 24868c2ecf20Sopenharmony_ci ib_register_event_handler(&priv->event_handler); 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci /* call event handler to ensure pkey in sync */ 24898c2ecf20Sopenharmony_ci queue_work(ipoib_workqueue, &priv->flush_heavy); 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci ndev->rtnl_link_ops = ipoib_get_link_ops(); 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci result = register_netdev(ndev); 24948c2ecf20Sopenharmony_ci if (result) { 24958c2ecf20Sopenharmony_ci pr_warn("%s: couldn't register ipoib port %d; error %d\n", 24968c2ecf20Sopenharmony_ci hca->name, port, result); 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci ipoib_parent_unregister_pre(ndev); 24998c2ecf20Sopenharmony_ci ipoib_intf_free(ndev); 25008c2ecf20Sopenharmony_ci free_netdev(ndev); 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_ci return ERR_PTR(result); 25038c2ecf20Sopenharmony_ci } 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci if (hca->ops.rdma_netdev_get_params) { 25068c2ecf20Sopenharmony_ci int rc = hca->ops.rdma_netdev_get_params(hca, port, 25078c2ecf20Sopenharmony_ci RDMA_NETDEV_IPOIB, 25088c2ecf20Sopenharmony_ci ¶ms); 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci if (!rc && ops->priv_size < params.sizeof_priv) 25118c2ecf20Sopenharmony_ci ops->priv_size = params.sizeof_priv; 25128c2ecf20Sopenharmony_ci } 25138c2ecf20Sopenharmony_ci /* 25148c2ecf20Sopenharmony_ci * We cannot set priv_destructor before register_netdev because we 25158c2ecf20Sopenharmony_ci * need priv to be always valid during the error flow to execute 25168c2ecf20Sopenharmony_ci * ipoib_parent_unregister_pre(). Instead handle it manually and only 25178c2ecf20Sopenharmony_ci * enter priv_destructor mode once we are completely registered. 25188c2ecf20Sopenharmony_ci */ 25198c2ecf20Sopenharmony_ci ndev->priv_destructor = ipoib_intf_free; 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci if (ipoib_intercept_dev_id_attr(ndev)) 25228c2ecf20Sopenharmony_ci goto sysfs_failed; 25238c2ecf20Sopenharmony_ci if (ipoib_cm_add_mode_attr(ndev)) 25248c2ecf20Sopenharmony_ci goto sysfs_failed; 25258c2ecf20Sopenharmony_ci if (ipoib_add_pkey_attr(ndev)) 25268c2ecf20Sopenharmony_ci goto sysfs_failed; 25278c2ecf20Sopenharmony_ci if (ipoib_add_umcast_attr(ndev)) 25288c2ecf20Sopenharmony_ci goto sysfs_failed; 25298c2ecf20Sopenharmony_ci if (device_create_file(&ndev->dev, &dev_attr_create_child)) 25308c2ecf20Sopenharmony_ci goto sysfs_failed; 25318c2ecf20Sopenharmony_ci if (device_create_file(&ndev->dev, &dev_attr_delete_child)) 25328c2ecf20Sopenharmony_ci goto sysfs_failed; 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci return ndev; 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_cisysfs_failed: 25378c2ecf20Sopenharmony_ci ipoib_parent_unregister_pre(ndev); 25388c2ecf20Sopenharmony_ci unregister_netdev(ndev); 25398c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 25408c2ecf20Sopenharmony_ci} 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_cistatic int ipoib_add_one(struct ib_device *device) 25438c2ecf20Sopenharmony_ci{ 25448c2ecf20Sopenharmony_ci struct list_head *dev_list; 25458c2ecf20Sopenharmony_ci struct net_device *dev; 25468c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv; 25478c2ecf20Sopenharmony_ci unsigned int p; 25488c2ecf20Sopenharmony_ci int count = 0; 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci dev_list = kmalloc(sizeof(*dev_list), GFP_KERNEL); 25518c2ecf20Sopenharmony_ci if (!dev_list) 25528c2ecf20Sopenharmony_ci return -ENOMEM; 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci INIT_LIST_HEAD(dev_list); 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_ci rdma_for_each_port (device, p) { 25578c2ecf20Sopenharmony_ci if (!rdma_protocol_ib(device, p)) 25588c2ecf20Sopenharmony_ci continue; 25598c2ecf20Sopenharmony_ci dev = ipoib_add_port("ib%d", device, p); 25608c2ecf20Sopenharmony_ci if (!IS_ERR(dev)) { 25618c2ecf20Sopenharmony_ci priv = ipoib_priv(dev); 25628c2ecf20Sopenharmony_ci list_add_tail(&priv->list, dev_list); 25638c2ecf20Sopenharmony_ci count++; 25648c2ecf20Sopenharmony_ci } 25658c2ecf20Sopenharmony_ci } 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci if (!count) { 25688c2ecf20Sopenharmony_ci kfree(dev_list); 25698c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 25708c2ecf20Sopenharmony_ci } 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci ib_set_client_data(device, &ipoib_client, dev_list); 25738c2ecf20Sopenharmony_ci return 0; 25748c2ecf20Sopenharmony_ci} 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_cistatic void ipoib_remove_one(struct ib_device *device, void *client_data) 25778c2ecf20Sopenharmony_ci{ 25788c2ecf20Sopenharmony_ci struct ipoib_dev_priv *priv, *tmp, *cpriv, *tcpriv; 25798c2ecf20Sopenharmony_ci struct list_head *dev_list = client_data; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci list_for_each_entry_safe(priv, tmp, dev_list, list) { 25828c2ecf20Sopenharmony_ci LIST_HEAD(head); 25838c2ecf20Sopenharmony_ci ipoib_parent_unregister_pre(priv->dev); 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci rtnl_lock(); 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, 25888c2ecf20Sopenharmony_ci list) 25898c2ecf20Sopenharmony_ci unregister_netdevice_queue(cpriv->dev, &head); 25908c2ecf20Sopenharmony_ci unregister_netdevice_queue(priv->dev, &head); 25918c2ecf20Sopenharmony_ci unregister_netdevice_many(&head); 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci rtnl_unlock(); 25948c2ecf20Sopenharmony_ci } 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci kfree(dev_list); 25978c2ecf20Sopenharmony_ci} 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 26008c2ecf20Sopenharmony_cistatic struct notifier_block ipoib_netdev_notifier = { 26018c2ecf20Sopenharmony_ci .notifier_call = ipoib_netdev_event, 26028c2ecf20Sopenharmony_ci}; 26038c2ecf20Sopenharmony_ci#endif 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_cistatic int __init ipoib_init_module(void) 26068c2ecf20Sopenharmony_ci{ 26078c2ecf20Sopenharmony_ci int ret; 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci ipoib_recvq_size = roundup_pow_of_two(ipoib_recvq_size); 26108c2ecf20Sopenharmony_ci ipoib_recvq_size = min(ipoib_recvq_size, IPOIB_MAX_QUEUE_SIZE); 26118c2ecf20Sopenharmony_ci ipoib_recvq_size = max(ipoib_recvq_size, IPOIB_MIN_QUEUE_SIZE); 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size); 26148c2ecf20Sopenharmony_ci ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE); 26158c2ecf20Sopenharmony_ci ipoib_sendq_size = max3(ipoib_sendq_size, 2 * MAX_SEND_CQE, IPOIB_MIN_QUEUE_SIZE); 26168c2ecf20Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_CM 26178c2ecf20Sopenharmony_ci ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP); 26188c2ecf20Sopenharmony_ci ipoib_max_conn_qp = max(ipoib_max_conn_qp, 0); 26198c2ecf20Sopenharmony_ci#endif 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci /* 26228c2ecf20Sopenharmony_ci * When copying small received packets, we only copy from the 26238c2ecf20Sopenharmony_ci * linear data part of the SKB, so we rely on this condition. 26248c2ecf20Sopenharmony_ci */ 26258c2ecf20Sopenharmony_ci BUILD_BUG_ON(IPOIB_CM_COPYBREAK > IPOIB_CM_HEAD_SIZE); 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci ipoib_register_debugfs(); 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci /* 26308c2ecf20Sopenharmony_ci * We create a global workqueue here that is used for all flush 26318c2ecf20Sopenharmony_ci * operations. However, if you attempt to flush a workqueue 26328c2ecf20Sopenharmony_ci * from a task on that same workqueue, it deadlocks the system. 26338c2ecf20Sopenharmony_ci * We want to be able to flush the tasks associated with a 26348c2ecf20Sopenharmony_ci * specific net device, so we also create a workqueue for each 26358c2ecf20Sopenharmony_ci * netdevice. We queue up the tasks for that device only on 26368c2ecf20Sopenharmony_ci * its private workqueue, and we only queue up flush events 26378c2ecf20Sopenharmony_ci * on our global flush workqueue. This avoids the deadlocks. 26388c2ecf20Sopenharmony_ci */ 26398c2ecf20Sopenharmony_ci ipoib_workqueue = alloc_ordered_workqueue("ipoib_flush", 0); 26408c2ecf20Sopenharmony_ci if (!ipoib_workqueue) { 26418c2ecf20Sopenharmony_ci ret = -ENOMEM; 26428c2ecf20Sopenharmony_ci goto err_fs; 26438c2ecf20Sopenharmony_ci } 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci ib_sa_register_client(&ipoib_sa_client); 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci ret = ib_register_client(&ipoib_client); 26488c2ecf20Sopenharmony_ci if (ret) 26498c2ecf20Sopenharmony_ci goto err_sa; 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci ret = ipoib_netlink_init(); 26528c2ecf20Sopenharmony_ci if (ret) 26538c2ecf20Sopenharmony_ci goto err_client; 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 26568c2ecf20Sopenharmony_ci register_netdevice_notifier(&ipoib_netdev_notifier); 26578c2ecf20Sopenharmony_ci#endif 26588c2ecf20Sopenharmony_ci return 0; 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_cierr_client: 26618c2ecf20Sopenharmony_ci ib_unregister_client(&ipoib_client); 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_cierr_sa: 26648c2ecf20Sopenharmony_ci ib_sa_unregister_client(&ipoib_sa_client); 26658c2ecf20Sopenharmony_ci destroy_workqueue(ipoib_workqueue); 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_cierr_fs: 26688c2ecf20Sopenharmony_ci ipoib_unregister_debugfs(); 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci return ret; 26718c2ecf20Sopenharmony_ci} 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_cistatic void __exit ipoib_cleanup_module(void) 26748c2ecf20Sopenharmony_ci{ 26758c2ecf20Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 26768c2ecf20Sopenharmony_ci unregister_netdevice_notifier(&ipoib_netdev_notifier); 26778c2ecf20Sopenharmony_ci#endif 26788c2ecf20Sopenharmony_ci ipoib_netlink_fini(); 26798c2ecf20Sopenharmony_ci ib_unregister_client(&ipoib_client); 26808c2ecf20Sopenharmony_ci ib_sa_unregister_client(&ipoib_sa_client); 26818c2ecf20Sopenharmony_ci ipoib_unregister_debugfs(); 26828c2ecf20Sopenharmony_ci destroy_workqueue(ipoib_workqueue); 26838c2ecf20Sopenharmony_ci} 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_cimodule_init(ipoib_init_module); 26868c2ecf20Sopenharmony_cimodule_exit(ipoib_cleanup_module); 2687