162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2004 Topspin Communications. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1062306a36Sopenharmony_ci * OpenIB.org BSD license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1362306a36Sopenharmony_ci * without modification, are permitted provided that the following 1462306a36Sopenharmony_ci * conditions are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1762306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1862306a36Sopenharmony_ci * disclaimer. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2362306a36Sopenharmony_ci * provided with the distribution. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3262306a36Sopenharmony_ci * SOFTWARE. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include "ipoib.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <linux/module.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <linux/init.h> 4062306a36Sopenharmony_ci#include <linux/slab.h> 4162306a36Sopenharmony_ci#include <linux/kernel.h> 4262306a36Sopenharmony_ci#include <linux/vmalloc.h> 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#include <linux/if_arp.h> /* For ARPHRD_xxx */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include <linux/ip.h> 4762306a36Sopenharmony_ci#include <linux/in.h> 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#include <linux/jhash.h> 5062306a36Sopenharmony_ci#include <net/arp.h> 5162306a36Sopenharmony_ci#include <net/addrconf.h> 5262306a36Sopenharmony_ci#include <linux/inetdevice.h> 5362306a36Sopenharmony_ci#include <rdma/ib_cache.h> 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ciMODULE_AUTHOR("Roland Dreier"); 5662306a36Sopenharmony_ciMODULE_DESCRIPTION("IP-over-InfiniBand net driver"); 5762306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciint ipoib_sendq_size __read_mostly = IPOIB_TX_RING_SIZE; 6062306a36Sopenharmony_ciint ipoib_recvq_size __read_mostly = IPOIB_RX_RING_SIZE; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cimodule_param_named(send_queue_size, ipoib_sendq_size, int, 0444); 6362306a36Sopenharmony_ciMODULE_PARM_DESC(send_queue_size, "Number of descriptors in send queue"); 6462306a36Sopenharmony_cimodule_param_named(recv_queue_size, ipoib_recvq_size, int, 0444); 6562306a36Sopenharmony_ciMODULE_PARM_DESC(recv_queue_size, "Number of descriptors in receive queue"); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 6862306a36Sopenharmony_ciint ipoib_debug_level; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cimodule_param_named(debug_level, ipoib_debug_level, int, 0644); 7162306a36Sopenharmony_ciMODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); 7262306a36Sopenharmony_ci#endif 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistruct ipoib_path_iter { 7562306a36Sopenharmony_ci struct net_device *dev; 7662306a36Sopenharmony_ci struct ipoib_path path; 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic const u8 ipv4_bcast_addr[] = { 8062306a36Sopenharmony_ci 0x00, 0xff, 0xff, 0xff, 8162306a36Sopenharmony_ci 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, 8262306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistruct workqueue_struct *ipoib_workqueue; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistruct ib_sa_client ipoib_sa_client; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic int ipoib_add_one(struct ib_device *device); 9062306a36Sopenharmony_cistatic void ipoib_remove_one(struct ib_device *device, void *client_data); 9162306a36Sopenharmony_cistatic void ipoib_neigh_reclaim(struct rcu_head *rp); 9262306a36Sopenharmony_cistatic struct net_device *ipoib_get_net_dev_by_params( 9362306a36Sopenharmony_ci struct ib_device *dev, u32 port, u16 pkey, 9462306a36Sopenharmony_ci const union ib_gid *gid, const struct sockaddr *addr, 9562306a36Sopenharmony_ci void *client_data); 9662306a36Sopenharmony_cistatic int ipoib_set_mac(struct net_device *dev, void *addr); 9762306a36Sopenharmony_cistatic int ipoib_ioctl(struct net_device *dev, struct ifreq *ifr, 9862306a36Sopenharmony_ci int cmd); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic struct ib_client ipoib_client = { 10162306a36Sopenharmony_ci .name = "ipoib", 10262306a36Sopenharmony_ci .add = ipoib_add_one, 10362306a36Sopenharmony_ci .remove = ipoib_remove_one, 10462306a36Sopenharmony_ci .get_net_dev_by_params = ipoib_get_net_dev_by_params, 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 10862306a36Sopenharmony_cistatic int ipoib_netdev_event(struct notifier_block *this, 10962306a36Sopenharmony_ci unsigned long event, void *ptr) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct netdev_notifier_info *ni = ptr; 11262306a36Sopenharmony_ci struct net_device *dev = ni->dev; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (dev->netdev_ops->ndo_open != ipoib_open) 11562306a36Sopenharmony_ci return NOTIFY_DONE; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci switch (event) { 11862306a36Sopenharmony_ci case NETDEV_REGISTER: 11962306a36Sopenharmony_ci ipoib_create_debug_files(dev); 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci case NETDEV_CHANGENAME: 12262306a36Sopenharmony_ci ipoib_delete_debug_files(dev); 12362306a36Sopenharmony_ci ipoib_create_debug_files(dev); 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci case NETDEV_UNREGISTER: 12662306a36Sopenharmony_ci ipoib_delete_debug_files(dev); 12762306a36Sopenharmony_ci break; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci return NOTIFY_DONE; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci#endif 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ciint ipoib_open(struct net_device *dev) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci ipoib_dbg(priv, "bringing up interface\n"); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci netif_carrier_off(dev); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (ipoib_ib_dev_open(dev)) { 14562306a36Sopenharmony_ci if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci goto err_disable; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ipoib_ib_dev_up(dev); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { 15362306a36Sopenharmony_ci struct ipoib_dev_priv *cpriv; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* Bring up any child interfaces too */ 15662306a36Sopenharmony_ci down_read(&priv->vlan_rwsem); 15762306a36Sopenharmony_ci list_for_each_entry(cpriv, &priv->child_intfs, list) { 15862306a36Sopenharmony_ci int flags; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci flags = cpriv->dev->flags; 16162306a36Sopenharmony_ci if (flags & IFF_UP) 16262306a36Sopenharmony_ci continue; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci dev_change_flags(cpriv->dev, flags | IFF_UP, NULL); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci up_read(&priv->vlan_rwsem); 16762306a36Sopenharmony_ci } else if (priv->parent) { 16862306a36Sopenharmony_ci struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (!test_bit(IPOIB_FLAG_ADMIN_UP, &ppriv->flags)) 17162306a36Sopenharmony_ci ipoib_dbg(priv, "parent device %s is not up, so child device may be not functioning.\n", 17262306a36Sopenharmony_ci ppriv->dev->name); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci netif_start_queue(dev); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci return 0; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cierr_disable: 17962306a36Sopenharmony_ci clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return -EINVAL; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic int ipoib_stop(struct net_device *dev) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci ipoib_dbg(priv, "stopping interface\n"); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci netif_stop_queue(dev); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci ipoib_ib_dev_down(dev); 19562306a36Sopenharmony_ci ipoib_ib_dev_stop(dev); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { 19862306a36Sopenharmony_ci struct ipoib_dev_priv *cpriv; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Bring down any child interfaces too */ 20162306a36Sopenharmony_ci down_read(&priv->vlan_rwsem); 20262306a36Sopenharmony_ci list_for_each_entry(cpriv, &priv->child_intfs, list) { 20362306a36Sopenharmony_ci int flags; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci flags = cpriv->dev->flags; 20662306a36Sopenharmony_ci if (!(flags & IFF_UP)) 20762306a36Sopenharmony_ci continue; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci dev_change_flags(cpriv->dev, flags & ~IFF_UP, NULL); 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci up_read(&priv->vlan_rwsem); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic netdev_features_t ipoib_fix_features(struct net_device *dev, netdev_features_t features) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags)) 22262306a36Sopenharmony_ci features &= ~(NETIF_F_IP_CSUM | NETIF_F_TSO); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci return features; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic int ipoib_change_mtu(struct net_device *dev, int new_mtu) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 23062306a36Sopenharmony_ci int ret = 0; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* dev->mtu > 2K ==> connected mode */ 23362306a36Sopenharmony_ci if (ipoib_cm_admin_enabled(dev)) { 23462306a36Sopenharmony_ci if (new_mtu > ipoib_cm_max_mtu(dev)) 23562306a36Sopenharmony_ci return -EINVAL; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (new_mtu > priv->mcast_mtu) 23862306a36Sopenharmony_ci ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n", 23962306a36Sopenharmony_ci priv->mcast_mtu); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci dev->mtu = new_mtu; 24262306a36Sopenharmony_ci return 0; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (new_mtu < (ETH_MIN_MTU + IPOIB_ENCAP_LEN) || 24662306a36Sopenharmony_ci new_mtu > IPOIB_UD_MTU(priv->max_ib_mtu)) 24762306a36Sopenharmony_ci return -EINVAL; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci priv->admin_mtu = new_mtu; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (priv->mcast_mtu < priv->admin_mtu) 25262306a36Sopenharmony_ci ipoib_dbg(priv, "MTU must be smaller than the underlying " 25362306a36Sopenharmony_ci "link layer MTU - 4 (%u)\n", priv->mcast_mtu); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci new_mtu = min(priv->mcast_mtu, priv->admin_mtu); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (priv->rn_ops->ndo_change_mtu) { 25862306a36Sopenharmony_ci bool carrier_status = netif_carrier_ok(dev); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci netif_carrier_off(dev); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci /* notify lower level on the real mtu */ 26362306a36Sopenharmony_ci ret = priv->rn_ops->ndo_change_mtu(dev, new_mtu); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (carrier_status) 26662306a36Sopenharmony_ci netif_carrier_on(dev); 26762306a36Sopenharmony_ci } else { 26862306a36Sopenharmony_ci dev->mtu = new_mtu; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return ret; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic void ipoib_get_stats(struct net_device *dev, 27562306a36Sopenharmony_ci struct rtnl_link_stats64 *stats) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (priv->rn_ops->ndo_get_stats64) 28062306a36Sopenharmony_ci priv->rn_ops->ndo_get_stats64(dev, stats); 28162306a36Sopenharmony_ci else 28262306a36Sopenharmony_ci netdev_stats_to_stats64(stats, &dev->stats); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci/* Called with an RCU read lock taken */ 28662306a36Sopenharmony_cistatic bool ipoib_is_dev_match_addr_rcu(const struct sockaddr *addr, 28762306a36Sopenharmony_ci struct net_device *dev) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct net *net = dev_net(dev); 29062306a36Sopenharmony_ci struct in_device *in_dev; 29162306a36Sopenharmony_ci struct sockaddr_in *addr_in = (struct sockaddr_in *)addr; 29262306a36Sopenharmony_ci struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr; 29362306a36Sopenharmony_ci __be32 ret_addr; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci switch (addr->sa_family) { 29662306a36Sopenharmony_ci case AF_INET: 29762306a36Sopenharmony_ci in_dev = in_dev_get(dev); 29862306a36Sopenharmony_ci if (!in_dev) 29962306a36Sopenharmony_ci return false; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci ret_addr = inet_confirm_addr(net, in_dev, 0, 30262306a36Sopenharmony_ci addr_in->sin_addr.s_addr, 30362306a36Sopenharmony_ci RT_SCOPE_HOST); 30462306a36Sopenharmony_ci in_dev_put(in_dev); 30562306a36Sopenharmony_ci if (ret_addr) 30662306a36Sopenharmony_ci return true; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci break; 30962306a36Sopenharmony_ci case AF_INET6: 31062306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_IPV6) && 31162306a36Sopenharmony_ci ipv6_chk_addr(net, &addr_in6->sin6_addr, dev, 1)) 31262306a36Sopenharmony_ci return true; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci break; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci return false; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci/* 32062306a36Sopenharmony_ci * Find the master net_device on top of the given net_device. 32162306a36Sopenharmony_ci * @dev: base IPoIB net_device 32262306a36Sopenharmony_ci * 32362306a36Sopenharmony_ci * Returns the master net_device with a reference held, or the same net_device 32462306a36Sopenharmony_ci * if no master exists. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_cistatic struct net_device *ipoib_get_master_net_dev(struct net_device *dev) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct net_device *master; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci rcu_read_lock(); 33162306a36Sopenharmony_ci master = netdev_master_upper_dev_get_rcu(dev); 33262306a36Sopenharmony_ci if (master) 33362306a36Sopenharmony_ci dev_hold(master); 33462306a36Sopenharmony_ci rcu_read_unlock(); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (master) 33762306a36Sopenharmony_ci return master; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci dev_hold(dev); 34062306a36Sopenharmony_ci return dev; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistruct ipoib_walk_data { 34462306a36Sopenharmony_ci const struct sockaddr *addr; 34562306a36Sopenharmony_ci struct net_device *result; 34662306a36Sopenharmony_ci}; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic int ipoib_upper_walk(struct net_device *upper, 34962306a36Sopenharmony_ci struct netdev_nested_priv *priv) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct ipoib_walk_data *data = (struct ipoib_walk_data *)priv->data; 35262306a36Sopenharmony_ci int ret = 0; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (ipoib_is_dev_match_addr_rcu(data->addr, upper)) { 35562306a36Sopenharmony_ci dev_hold(upper); 35662306a36Sopenharmony_ci data->result = upper; 35762306a36Sopenharmony_ci ret = 1; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci return ret; 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci/** 36462306a36Sopenharmony_ci * ipoib_get_net_dev_match_addr - Find a net_device matching 36562306a36Sopenharmony_ci * the given address, which is an upper device of the given net_device. 36662306a36Sopenharmony_ci * 36762306a36Sopenharmony_ci * @addr: IP address to look for. 36862306a36Sopenharmony_ci * @dev: base IPoIB net_device 36962306a36Sopenharmony_ci * 37062306a36Sopenharmony_ci * If found, returns the net_device with a reference held. Otherwise return 37162306a36Sopenharmony_ci * NULL. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_cistatic struct net_device *ipoib_get_net_dev_match_addr( 37462306a36Sopenharmony_ci const struct sockaddr *addr, struct net_device *dev) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct netdev_nested_priv priv; 37762306a36Sopenharmony_ci struct ipoib_walk_data data = { 37862306a36Sopenharmony_ci .addr = addr, 37962306a36Sopenharmony_ci }; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci priv.data = (void *)&data; 38262306a36Sopenharmony_ci rcu_read_lock(); 38362306a36Sopenharmony_ci if (ipoib_is_dev_match_addr_rcu(addr, dev)) { 38462306a36Sopenharmony_ci dev_hold(dev); 38562306a36Sopenharmony_ci data.result = dev; 38662306a36Sopenharmony_ci goto out; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci netdev_walk_all_upper_dev_rcu(dev, ipoib_upper_walk, &priv); 39062306a36Sopenharmony_ciout: 39162306a36Sopenharmony_ci rcu_read_unlock(); 39262306a36Sopenharmony_ci return data.result; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci/* returns the number of IPoIB netdevs on top a given ipoib device matching a 39662306a36Sopenharmony_ci * pkey_index and address, if one exists. 39762306a36Sopenharmony_ci * 39862306a36Sopenharmony_ci * @found_net_dev: contains a matching net_device if the return value >= 1, 39962306a36Sopenharmony_ci * with a reference held. */ 40062306a36Sopenharmony_cistatic int ipoib_match_gid_pkey_addr(struct ipoib_dev_priv *priv, 40162306a36Sopenharmony_ci const union ib_gid *gid, 40262306a36Sopenharmony_ci u16 pkey_index, 40362306a36Sopenharmony_ci const struct sockaddr *addr, 40462306a36Sopenharmony_ci int nesting, 40562306a36Sopenharmony_ci struct net_device **found_net_dev) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct ipoib_dev_priv *child_priv; 40862306a36Sopenharmony_ci struct net_device *net_dev = NULL; 40962306a36Sopenharmony_ci int matches = 0; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (priv->pkey_index == pkey_index && 41262306a36Sopenharmony_ci (!gid || !memcmp(gid, &priv->local_gid, sizeof(*gid)))) { 41362306a36Sopenharmony_ci if (!addr) { 41462306a36Sopenharmony_ci net_dev = ipoib_get_master_net_dev(priv->dev); 41562306a36Sopenharmony_ci } else { 41662306a36Sopenharmony_ci /* Verify the net_device matches the IP address, as 41762306a36Sopenharmony_ci * IPoIB child devices currently share a GID. */ 41862306a36Sopenharmony_ci net_dev = ipoib_get_net_dev_match_addr(addr, priv->dev); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci if (net_dev) { 42162306a36Sopenharmony_ci if (!*found_net_dev) 42262306a36Sopenharmony_ci *found_net_dev = net_dev; 42362306a36Sopenharmony_ci else 42462306a36Sopenharmony_ci dev_put(net_dev); 42562306a36Sopenharmony_ci ++matches; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* Check child interfaces */ 43062306a36Sopenharmony_ci down_read_nested(&priv->vlan_rwsem, nesting); 43162306a36Sopenharmony_ci list_for_each_entry(child_priv, &priv->child_intfs, list) { 43262306a36Sopenharmony_ci matches += ipoib_match_gid_pkey_addr(child_priv, gid, 43362306a36Sopenharmony_ci pkey_index, addr, 43462306a36Sopenharmony_ci nesting + 1, 43562306a36Sopenharmony_ci found_net_dev); 43662306a36Sopenharmony_ci if (matches > 1) 43762306a36Sopenharmony_ci break; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci up_read(&priv->vlan_rwsem); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return matches; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci/* Returns the number of matching net_devs found (between 0 and 2). Also 44562306a36Sopenharmony_ci * return the matching net_device in the @net_dev parameter, holding a 44662306a36Sopenharmony_ci * reference to the net_device, if the number of matches >= 1 */ 44762306a36Sopenharmony_cistatic int __ipoib_get_net_dev_by_params(struct list_head *dev_list, u32 port, 44862306a36Sopenharmony_ci u16 pkey_index, 44962306a36Sopenharmony_ci const union ib_gid *gid, 45062306a36Sopenharmony_ci const struct sockaddr *addr, 45162306a36Sopenharmony_ci struct net_device **net_dev) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct ipoib_dev_priv *priv; 45462306a36Sopenharmony_ci int matches = 0; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci *net_dev = NULL; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci list_for_each_entry(priv, dev_list, list) { 45962306a36Sopenharmony_ci if (priv->port != port) 46062306a36Sopenharmony_ci continue; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci matches += ipoib_match_gid_pkey_addr(priv, gid, pkey_index, 46362306a36Sopenharmony_ci addr, 0, net_dev); 46462306a36Sopenharmony_ci if (matches > 1) 46562306a36Sopenharmony_ci break; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci return matches; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic struct net_device *ipoib_get_net_dev_by_params( 47262306a36Sopenharmony_ci struct ib_device *dev, u32 port, u16 pkey, 47362306a36Sopenharmony_ci const union ib_gid *gid, const struct sockaddr *addr, 47462306a36Sopenharmony_ci void *client_data) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct net_device *net_dev; 47762306a36Sopenharmony_ci struct list_head *dev_list = client_data; 47862306a36Sopenharmony_ci u16 pkey_index; 47962306a36Sopenharmony_ci int matches; 48062306a36Sopenharmony_ci int ret; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (!rdma_protocol_ib(dev, port)) 48362306a36Sopenharmony_ci return NULL; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci ret = ib_find_cached_pkey(dev, port, pkey, &pkey_index); 48662306a36Sopenharmony_ci if (ret) 48762306a36Sopenharmony_ci return NULL; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* See if we can find a unique device matching the L2 parameters */ 49062306a36Sopenharmony_ci matches = __ipoib_get_net_dev_by_params(dev_list, port, pkey_index, 49162306a36Sopenharmony_ci gid, NULL, &net_dev); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci switch (matches) { 49462306a36Sopenharmony_ci case 0: 49562306a36Sopenharmony_ci return NULL; 49662306a36Sopenharmony_ci case 1: 49762306a36Sopenharmony_ci return net_dev; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci dev_put(net_dev); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* Couldn't find a unique device with L2 parameters only. Use L3 50362306a36Sopenharmony_ci * address to uniquely match the net device */ 50462306a36Sopenharmony_ci matches = __ipoib_get_net_dev_by_params(dev_list, port, pkey_index, 50562306a36Sopenharmony_ci gid, addr, &net_dev); 50662306a36Sopenharmony_ci switch (matches) { 50762306a36Sopenharmony_ci case 0: 50862306a36Sopenharmony_ci return NULL; 50962306a36Sopenharmony_ci default: 51062306a36Sopenharmony_ci dev_warn_ratelimited(&dev->dev, 51162306a36Sopenharmony_ci "duplicate IP address detected\n"); 51262306a36Sopenharmony_ci fallthrough; 51362306a36Sopenharmony_ci case 1: 51462306a36Sopenharmony_ci return net_dev; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ciint ipoib_set_mode(struct net_device *dev, const char *buf) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if ((test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags) && 52362306a36Sopenharmony_ci !strcmp(buf, "connected\n")) || 52462306a36Sopenharmony_ci (!test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags) && 52562306a36Sopenharmony_ci !strcmp(buf, "datagram\n"))) { 52662306a36Sopenharmony_ci return 0; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci /* flush paths if we switch modes so that connections are restarted */ 53062306a36Sopenharmony_ci if (IPOIB_CM_SUPPORTED(dev->dev_addr) && !strcmp(buf, "connected\n")) { 53162306a36Sopenharmony_ci set_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); 53262306a36Sopenharmony_ci ipoib_warn(priv, "enabling connected mode " 53362306a36Sopenharmony_ci "will cause multicast packet drops\n"); 53462306a36Sopenharmony_ci netdev_update_features(dev); 53562306a36Sopenharmony_ci dev_set_mtu(dev, ipoib_cm_max_mtu(dev)); 53662306a36Sopenharmony_ci netif_set_real_num_tx_queues(dev, 1); 53762306a36Sopenharmony_ci rtnl_unlock(); 53862306a36Sopenharmony_ci priv->tx_wr.wr.send_flags &= ~IB_SEND_IP_CSUM; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci ipoib_flush_paths(dev); 54162306a36Sopenharmony_ci return (!rtnl_trylock()) ? -EBUSY : 0; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (!strcmp(buf, "datagram\n")) { 54562306a36Sopenharmony_ci clear_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags); 54662306a36Sopenharmony_ci netdev_update_features(dev); 54762306a36Sopenharmony_ci dev_set_mtu(dev, min(priv->mcast_mtu, dev->mtu)); 54862306a36Sopenharmony_ci netif_set_real_num_tx_queues(dev, dev->num_tx_queues); 54962306a36Sopenharmony_ci rtnl_unlock(); 55062306a36Sopenharmony_ci ipoib_flush_paths(dev); 55162306a36Sopenharmony_ci return (!rtnl_trylock()) ? -EBUSY : 0; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci return -EINVAL; 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistruct ipoib_path *__path_find(struct net_device *dev, void *gid) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 56062306a36Sopenharmony_ci struct rb_node *n = priv->path_tree.rb_node; 56162306a36Sopenharmony_ci struct ipoib_path *path; 56262306a36Sopenharmony_ci int ret; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci while (n) { 56562306a36Sopenharmony_ci path = rb_entry(n, struct ipoib_path, rb_node); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci ret = memcmp(gid, path->pathrec.dgid.raw, 56862306a36Sopenharmony_ci sizeof (union ib_gid)); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (ret < 0) 57162306a36Sopenharmony_ci n = n->rb_left; 57262306a36Sopenharmony_ci else if (ret > 0) 57362306a36Sopenharmony_ci n = n->rb_right; 57462306a36Sopenharmony_ci else 57562306a36Sopenharmony_ci return path; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci return NULL; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic int __path_add(struct net_device *dev, struct ipoib_path *path) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 58462306a36Sopenharmony_ci struct rb_node **n = &priv->path_tree.rb_node; 58562306a36Sopenharmony_ci struct rb_node *pn = NULL; 58662306a36Sopenharmony_ci struct ipoib_path *tpath; 58762306a36Sopenharmony_ci int ret; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci while (*n) { 59062306a36Sopenharmony_ci pn = *n; 59162306a36Sopenharmony_ci tpath = rb_entry(pn, struct ipoib_path, rb_node); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci ret = memcmp(path->pathrec.dgid.raw, tpath->pathrec.dgid.raw, 59462306a36Sopenharmony_ci sizeof (union ib_gid)); 59562306a36Sopenharmony_ci if (ret < 0) 59662306a36Sopenharmony_ci n = &pn->rb_left; 59762306a36Sopenharmony_ci else if (ret > 0) 59862306a36Sopenharmony_ci n = &pn->rb_right; 59962306a36Sopenharmony_ci else 60062306a36Sopenharmony_ci return -EEXIST; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci rb_link_node(&path->rb_node, pn, n); 60462306a36Sopenharmony_ci rb_insert_color(&path->rb_node, &priv->path_tree); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci list_add_tail(&path->list, &priv->path_list); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci return 0; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic void path_free(struct net_device *dev, struct ipoib_path *path) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct sk_buff *skb; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci while ((skb = __skb_dequeue(&path->queue))) 61662306a36Sopenharmony_ci dev_kfree_skb_irq(skb); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci ipoib_dbg(ipoib_priv(dev), "%s\n", __func__); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* remove all neigh connected to this path */ 62162306a36Sopenharmony_ci ipoib_del_neighs_by_gid(dev, path->pathrec.dgid.raw); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (path->ah) 62462306a36Sopenharmony_ci ipoib_put_ah(path->ah); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci kfree(path); 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistruct ipoib_path_iter *ipoib_path_iter_init(struct net_device *dev) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci struct ipoib_path_iter *iter; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci iter = kmalloc(sizeof(*iter), GFP_KERNEL); 63662306a36Sopenharmony_ci if (!iter) 63762306a36Sopenharmony_ci return NULL; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci iter->dev = dev; 64062306a36Sopenharmony_ci memset(iter->path.pathrec.dgid.raw, 0, 16); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (ipoib_path_iter_next(iter)) { 64362306a36Sopenharmony_ci kfree(iter); 64462306a36Sopenharmony_ci return NULL; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci return iter; 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ciint ipoib_path_iter_next(struct ipoib_path_iter *iter) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(iter->dev); 65362306a36Sopenharmony_ci struct rb_node *n; 65462306a36Sopenharmony_ci struct ipoib_path *path; 65562306a36Sopenharmony_ci int ret = 1; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci spin_lock_irq(&priv->lock); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci n = rb_first(&priv->path_tree); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci while (n) { 66262306a36Sopenharmony_ci path = rb_entry(n, struct ipoib_path, rb_node); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (memcmp(iter->path.pathrec.dgid.raw, path->pathrec.dgid.raw, 66562306a36Sopenharmony_ci sizeof (union ib_gid)) < 0) { 66662306a36Sopenharmony_ci iter->path = *path; 66762306a36Sopenharmony_ci ret = 0; 66862306a36Sopenharmony_ci break; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci n = rb_next(n); 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci spin_unlock_irq(&priv->lock); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci return ret; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_civoid ipoib_path_iter_read(struct ipoib_path_iter *iter, 68062306a36Sopenharmony_ci struct ipoib_path *path) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci *path = iter->path; 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci#endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */ 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_civoid ipoib_mark_paths_invalid(struct net_device *dev) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 69062306a36Sopenharmony_ci struct ipoib_path *path, *tp; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci spin_lock_irq(&priv->lock); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci list_for_each_entry_safe(path, tp, &priv->path_list, list) { 69562306a36Sopenharmony_ci ipoib_dbg(priv, "mark path LID 0x%08x GID %pI6 invalid\n", 69662306a36Sopenharmony_ci be32_to_cpu(sa_path_get_dlid(&path->pathrec)), 69762306a36Sopenharmony_ci path->pathrec.dgid.raw); 69862306a36Sopenharmony_ci if (path->ah) 69962306a36Sopenharmony_ci path->ah->valid = 0; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci spin_unlock_irq(&priv->lock); 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistatic void push_pseudo_header(struct sk_buff *skb, const char *daddr) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci struct ipoib_pseudo_header *phdr; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci phdr = skb_push(skb, sizeof(*phdr)); 71062306a36Sopenharmony_ci memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_civoid ipoib_flush_paths(struct net_device *dev) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 71662306a36Sopenharmony_ci struct ipoib_path *path, *tp; 71762306a36Sopenharmony_ci LIST_HEAD(remove_list); 71862306a36Sopenharmony_ci unsigned long flags; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci netif_tx_lock_bh(dev); 72162306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci list_splice_init(&priv->path_list, &remove_list); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci list_for_each_entry(path, &remove_list, list) 72662306a36Sopenharmony_ci rb_erase(&path->rb_node, &priv->path_tree); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci list_for_each_entry_safe(path, tp, &remove_list, list) { 72962306a36Sopenharmony_ci if (path->query) 73062306a36Sopenharmony_ci ib_sa_cancel_query(path->query_id, path->query); 73162306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 73262306a36Sopenharmony_ci netif_tx_unlock_bh(dev); 73362306a36Sopenharmony_ci wait_for_completion(&path->done); 73462306a36Sopenharmony_ci path_free(dev, path); 73562306a36Sopenharmony_ci netif_tx_lock_bh(dev); 73662306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 74062306a36Sopenharmony_ci netif_tx_unlock_bh(dev); 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic void path_rec_completion(int status, 74462306a36Sopenharmony_ci struct sa_path_rec *pathrec, 74562306a36Sopenharmony_ci unsigned int num_prs, void *path_ptr) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct ipoib_path *path = path_ptr; 74862306a36Sopenharmony_ci struct net_device *dev = path->dev; 74962306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 75062306a36Sopenharmony_ci struct ipoib_ah *ah = NULL; 75162306a36Sopenharmony_ci struct ipoib_ah *old_ah = NULL; 75262306a36Sopenharmony_ci struct ipoib_neigh *neigh, *tn; 75362306a36Sopenharmony_ci struct sk_buff_head skqueue; 75462306a36Sopenharmony_ci struct sk_buff *skb; 75562306a36Sopenharmony_ci unsigned long flags; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (!status) 75862306a36Sopenharmony_ci ipoib_dbg(priv, "PathRec LID 0x%04x for GID %pI6\n", 75962306a36Sopenharmony_ci be32_to_cpu(sa_path_get_dlid(pathrec)), 76062306a36Sopenharmony_ci pathrec->dgid.raw); 76162306a36Sopenharmony_ci else 76262306a36Sopenharmony_ci ipoib_dbg(priv, "PathRec status %d for GID %pI6\n", 76362306a36Sopenharmony_ci status, path->pathrec.dgid.raw); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci skb_queue_head_init(&skqueue); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (!status) { 76862306a36Sopenharmony_ci struct rdma_ah_attr av; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (!ib_init_ah_attr_from_path(priv->ca, priv->port, 77162306a36Sopenharmony_ci pathrec, &av, NULL)) { 77262306a36Sopenharmony_ci ah = ipoib_create_ah(dev, priv->pd, &av); 77362306a36Sopenharmony_ci rdma_destroy_ah_attr(&av); 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(ah)) { 78062306a36Sopenharmony_ci /* 78162306a36Sopenharmony_ci * pathrec.dgid is used as the database key from the LLADDR, 78262306a36Sopenharmony_ci * it must remain unchanged even if the SA returns a different 78362306a36Sopenharmony_ci * GID to use in the AH. 78462306a36Sopenharmony_ci */ 78562306a36Sopenharmony_ci if (memcmp(pathrec->dgid.raw, path->pathrec.dgid.raw, 78662306a36Sopenharmony_ci sizeof(union ib_gid))) { 78762306a36Sopenharmony_ci ipoib_dbg( 78862306a36Sopenharmony_ci priv, 78962306a36Sopenharmony_ci "%s got PathRec for gid %pI6 while asked for %pI6\n", 79062306a36Sopenharmony_ci dev->name, pathrec->dgid.raw, 79162306a36Sopenharmony_ci path->pathrec.dgid.raw); 79262306a36Sopenharmony_ci memcpy(pathrec->dgid.raw, path->pathrec.dgid.raw, 79362306a36Sopenharmony_ci sizeof(union ib_gid)); 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci path->pathrec = *pathrec; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci old_ah = path->ah; 79962306a36Sopenharmony_ci path->ah = ah; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci ipoib_dbg(priv, "created address handle %p for LID 0x%04x, SL %d\n", 80262306a36Sopenharmony_ci ah, be32_to_cpu(sa_path_get_dlid(pathrec)), 80362306a36Sopenharmony_ci pathrec->sl); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci while ((skb = __skb_dequeue(&path->queue))) 80662306a36Sopenharmony_ci __skb_queue_tail(&skqueue, skb); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci list_for_each_entry_safe(neigh, tn, &path->neigh_list, list) { 80962306a36Sopenharmony_ci if (neigh->ah) { 81062306a36Sopenharmony_ci WARN_ON(neigh->ah != old_ah); 81162306a36Sopenharmony_ci /* 81262306a36Sopenharmony_ci * Dropping the ah reference inside 81362306a36Sopenharmony_ci * priv->lock is safe here, because we 81462306a36Sopenharmony_ci * will hold one more reference from 81562306a36Sopenharmony_ci * the original value of path->ah (ie 81662306a36Sopenharmony_ci * old_ah). 81762306a36Sopenharmony_ci */ 81862306a36Sopenharmony_ci ipoib_put_ah(neigh->ah); 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci kref_get(&path->ah->ref); 82162306a36Sopenharmony_ci neigh->ah = path->ah; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci if (ipoib_cm_enabled(dev, neigh->daddr)) { 82462306a36Sopenharmony_ci if (!ipoib_cm_get(neigh)) 82562306a36Sopenharmony_ci ipoib_cm_set(neigh, ipoib_cm_create_tx(dev, 82662306a36Sopenharmony_ci path, 82762306a36Sopenharmony_ci neigh)); 82862306a36Sopenharmony_ci if (!ipoib_cm_get(neigh)) { 82962306a36Sopenharmony_ci ipoib_neigh_free(neigh); 83062306a36Sopenharmony_ci continue; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci while ((skb = __skb_dequeue(&neigh->queue))) 83562306a36Sopenharmony_ci __skb_queue_tail(&skqueue, skb); 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci path->ah->valid = 1; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci path->query = NULL; 84162306a36Sopenharmony_ci complete(&path->done); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci if (IS_ERR_OR_NULL(ah)) 84662306a36Sopenharmony_ci ipoib_del_neighs_by_gid(dev, path->pathrec.dgid.raw); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if (old_ah) 84962306a36Sopenharmony_ci ipoib_put_ah(old_ah); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci while ((skb = __skb_dequeue(&skqueue))) { 85262306a36Sopenharmony_ci int ret; 85362306a36Sopenharmony_ci skb->dev = dev; 85462306a36Sopenharmony_ci ret = dev_queue_xmit(skb); 85562306a36Sopenharmony_ci if (ret) 85662306a36Sopenharmony_ci ipoib_warn(priv, "%s: dev_queue_xmit failed to re-queue packet, ret:%d\n", 85762306a36Sopenharmony_ci __func__, ret); 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic void init_path_rec(struct ipoib_dev_priv *priv, struct ipoib_path *path, 86262306a36Sopenharmony_ci void *gid) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci path->dev = priv->dev; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci if (rdma_cap_opa_ah(priv->ca, priv->port)) 86762306a36Sopenharmony_ci path->pathrec.rec_type = SA_PATH_REC_TYPE_OPA; 86862306a36Sopenharmony_ci else 86962306a36Sopenharmony_ci path->pathrec.rec_type = SA_PATH_REC_TYPE_IB; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci memcpy(path->pathrec.dgid.raw, gid, sizeof(union ib_gid)); 87262306a36Sopenharmony_ci path->pathrec.sgid = priv->local_gid; 87362306a36Sopenharmony_ci path->pathrec.pkey = cpu_to_be16(priv->pkey); 87462306a36Sopenharmony_ci path->pathrec.numb_path = 1; 87562306a36Sopenharmony_ci path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class; 87662306a36Sopenharmony_ci} 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_cistatic struct ipoib_path *path_rec_create(struct net_device *dev, void *gid) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 88162306a36Sopenharmony_ci struct ipoib_path *path; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci if (!priv->broadcast) 88462306a36Sopenharmony_ci return NULL; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci path = kzalloc(sizeof(*path), GFP_ATOMIC); 88762306a36Sopenharmony_ci if (!path) 88862306a36Sopenharmony_ci return NULL; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci skb_queue_head_init(&path->queue); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci INIT_LIST_HEAD(&path->neigh_list); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci init_path_rec(priv, path, gid); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci return path; 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cistatic int path_rec_start(struct net_device *dev, 90062306a36Sopenharmony_ci struct ipoib_path *path) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci ipoib_dbg(priv, "Start path record lookup for %pI6\n", 90562306a36Sopenharmony_ci path->pathrec.dgid.raw); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci init_completion(&path->done); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci path->query_id = 91062306a36Sopenharmony_ci ib_sa_path_rec_get(&ipoib_sa_client, priv->ca, priv->port, 91162306a36Sopenharmony_ci &path->pathrec, 91262306a36Sopenharmony_ci IB_SA_PATH_REC_DGID | 91362306a36Sopenharmony_ci IB_SA_PATH_REC_SGID | 91462306a36Sopenharmony_ci IB_SA_PATH_REC_NUMB_PATH | 91562306a36Sopenharmony_ci IB_SA_PATH_REC_TRAFFIC_CLASS | 91662306a36Sopenharmony_ci IB_SA_PATH_REC_PKEY, 91762306a36Sopenharmony_ci 1000, GFP_ATOMIC, 91862306a36Sopenharmony_ci path_rec_completion, 91962306a36Sopenharmony_ci path, &path->query); 92062306a36Sopenharmony_ci if (path->query_id < 0) { 92162306a36Sopenharmony_ci ipoib_warn(priv, "ib_sa_path_rec_get failed: %d\n", path->query_id); 92262306a36Sopenharmony_ci path->query = NULL; 92362306a36Sopenharmony_ci complete(&path->done); 92462306a36Sopenharmony_ci return path->query_id; 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci return 0; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_cistatic void neigh_refresh_path(struct ipoib_neigh *neigh, u8 *daddr, 93162306a36Sopenharmony_ci struct net_device *dev) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 93462306a36Sopenharmony_ci struct ipoib_path *path; 93562306a36Sopenharmony_ci unsigned long flags; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci path = __path_find(dev, daddr + 4); 94062306a36Sopenharmony_ci if (!path) 94162306a36Sopenharmony_ci goto out; 94262306a36Sopenharmony_ci if (!path->query) 94362306a36Sopenharmony_ci path_rec_start(dev, path); 94462306a36Sopenharmony_ciout: 94562306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic struct ipoib_neigh *neigh_add_path(struct sk_buff *skb, u8 *daddr, 94962306a36Sopenharmony_ci struct net_device *dev) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 95262306a36Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 95362306a36Sopenharmony_ci struct ipoib_path *path; 95462306a36Sopenharmony_ci struct ipoib_neigh *neigh; 95562306a36Sopenharmony_ci unsigned long flags; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 95862306a36Sopenharmony_ci neigh = ipoib_neigh_alloc(daddr, dev); 95962306a36Sopenharmony_ci if (!neigh) { 96062306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 96162306a36Sopenharmony_ci ++dev->stats.tx_dropped; 96262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 96362306a36Sopenharmony_ci return NULL; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci /* To avoid race condition, make sure that the 96762306a36Sopenharmony_ci * neigh will be added only once. 96862306a36Sopenharmony_ci */ 96962306a36Sopenharmony_ci if (unlikely(!list_empty(&neigh->list))) { 97062306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 97162306a36Sopenharmony_ci return neigh; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci path = __path_find(dev, daddr + 4); 97562306a36Sopenharmony_ci if (!path) { 97662306a36Sopenharmony_ci path = path_rec_create(dev, daddr + 4); 97762306a36Sopenharmony_ci if (!path) 97862306a36Sopenharmony_ci goto err_path; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci __path_add(dev, path); 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci list_add_tail(&neigh->list, &path->neigh_list); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci if (path->ah && path->ah->valid) { 98662306a36Sopenharmony_ci kref_get(&path->ah->ref); 98762306a36Sopenharmony_ci neigh->ah = path->ah; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (ipoib_cm_enabled(dev, neigh->daddr)) { 99062306a36Sopenharmony_ci if (!ipoib_cm_get(neigh)) 99162306a36Sopenharmony_ci ipoib_cm_set(neigh, ipoib_cm_create_tx(dev, path, neigh)); 99262306a36Sopenharmony_ci if (!ipoib_cm_get(neigh)) { 99362306a36Sopenharmony_ci ipoib_neigh_free(neigh); 99462306a36Sopenharmony_ci goto err_drop; 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci if (skb_queue_len(&neigh->queue) < 99762306a36Sopenharmony_ci IPOIB_MAX_PATH_REC_QUEUE) { 99862306a36Sopenharmony_ci push_pseudo_header(skb, neigh->daddr); 99962306a36Sopenharmony_ci __skb_queue_tail(&neigh->queue, skb); 100062306a36Sopenharmony_ci } else { 100162306a36Sopenharmony_ci ipoib_warn(priv, "queue length limit %d. Packet drop.\n", 100262306a36Sopenharmony_ci skb_queue_len(&neigh->queue)); 100362306a36Sopenharmony_ci goto err_drop; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci } else { 100662306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 100762306a36Sopenharmony_ci path->ah->last_send = rn->send(dev, skb, path->ah->ah, 100862306a36Sopenharmony_ci IPOIB_QPN(daddr)); 100962306a36Sopenharmony_ci ipoib_neigh_put(neigh); 101062306a36Sopenharmony_ci return NULL; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci } else { 101362306a36Sopenharmony_ci neigh->ah = NULL; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci if (!path->query && path_rec_start(dev, path)) 101662306a36Sopenharmony_ci goto err_path; 101762306a36Sopenharmony_ci if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { 101862306a36Sopenharmony_ci push_pseudo_header(skb, neigh->daddr); 101962306a36Sopenharmony_ci __skb_queue_tail(&neigh->queue, skb); 102062306a36Sopenharmony_ci } else { 102162306a36Sopenharmony_ci goto err_drop; 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 102662306a36Sopenharmony_ci ipoib_neigh_put(neigh); 102762306a36Sopenharmony_ci return NULL; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_cierr_path: 103062306a36Sopenharmony_ci ipoib_neigh_free(neigh); 103162306a36Sopenharmony_cierr_drop: 103262306a36Sopenharmony_ci ++dev->stats.tx_dropped; 103362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 103662306a36Sopenharmony_ci ipoib_neigh_put(neigh); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci return NULL; 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cistatic void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, 104262306a36Sopenharmony_ci struct ipoib_pseudo_header *phdr) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 104562306a36Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 104662306a36Sopenharmony_ci struct ipoib_path *path; 104762306a36Sopenharmony_ci unsigned long flags; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci /* no broadcast means that all paths are (going to be) not valid */ 105262306a36Sopenharmony_ci if (!priv->broadcast) 105362306a36Sopenharmony_ci goto drop_and_unlock; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci path = __path_find(dev, phdr->hwaddr + 4); 105662306a36Sopenharmony_ci if (!path || !path->ah || !path->ah->valid) { 105762306a36Sopenharmony_ci if (!path) { 105862306a36Sopenharmony_ci path = path_rec_create(dev, phdr->hwaddr + 4); 105962306a36Sopenharmony_ci if (!path) 106062306a36Sopenharmony_ci goto drop_and_unlock; 106162306a36Sopenharmony_ci __path_add(dev, path); 106262306a36Sopenharmony_ci } else { 106362306a36Sopenharmony_ci /* 106462306a36Sopenharmony_ci * make sure there are no changes in the existing 106562306a36Sopenharmony_ci * path record 106662306a36Sopenharmony_ci */ 106762306a36Sopenharmony_ci init_path_rec(priv, path, phdr->hwaddr + 4); 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci if (!path->query && path_rec_start(dev, path)) { 107062306a36Sopenharmony_ci goto drop_and_unlock; 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { 107462306a36Sopenharmony_ci push_pseudo_header(skb, phdr->hwaddr); 107562306a36Sopenharmony_ci __skb_queue_tail(&path->queue, skb); 107662306a36Sopenharmony_ci goto unlock; 107762306a36Sopenharmony_ci } else { 107862306a36Sopenharmony_ci goto drop_and_unlock; 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 108362306a36Sopenharmony_ci ipoib_dbg(priv, "Send unicast ARP to %08x\n", 108462306a36Sopenharmony_ci be32_to_cpu(sa_path_get_dlid(&path->pathrec))); 108562306a36Sopenharmony_ci path->ah->last_send = rn->send(dev, skb, path->ah->ah, 108662306a36Sopenharmony_ci IPOIB_QPN(phdr->hwaddr)); 108762306a36Sopenharmony_ci return; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_cidrop_and_unlock: 109062306a36Sopenharmony_ci ++dev->stats.tx_dropped; 109162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 109262306a36Sopenharmony_ciunlock: 109362306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic netdev_tx_t ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 109962306a36Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 110062306a36Sopenharmony_ci struct ipoib_neigh *neigh; 110162306a36Sopenharmony_ci struct ipoib_pseudo_header *phdr; 110262306a36Sopenharmony_ci struct ipoib_header *header; 110362306a36Sopenharmony_ci unsigned long flags; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci phdr = (struct ipoib_pseudo_header *) skb->data; 110662306a36Sopenharmony_ci skb_pull(skb, sizeof(*phdr)); 110762306a36Sopenharmony_ci header = (struct ipoib_header *) skb->data; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci if (unlikely(phdr->hwaddr[4] == 0xff)) { 111062306a36Sopenharmony_ci /* multicast, arrange "if" according to probability */ 111162306a36Sopenharmony_ci if ((header->proto != htons(ETH_P_IP)) && 111262306a36Sopenharmony_ci (header->proto != htons(ETH_P_IPV6)) && 111362306a36Sopenharmony_ci (header->proto != htons(ETH_P_ARP)) && 111462306a36Sopenharmony_ci (header->proto != htons(ETH_P_RARP)) && 111562306a36Sopenharmony_ci (header->proto != htons(ETH_P_TIPC))) { 111662306a36Sopenharmony_ci /* ethertype not supported by IPoIB */ 111762306a36Sopenharmony_ci ++dev->stats.tx_dropped; 111862306a36Sopenharmony_ci dev_kfree_skb_any(skb); 111962306a36Sopenharmony_ci return NETDEV_TX_OK; 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci /* Add in the P_Key for multicast*/ 112262306a36Sopenharmony_ci phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff; 112362306a36Sopenharmony_ci phdr->hwaddr[9] = priv->pkey & 0xff; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci neigh = ipoib_neigh_get(dev, phdr->hwaddr); 112662306a36Sopenharmony_ci if (likely(neigh)) 112762306a36Sopenharmony_ci goto send_using_neigh; 112862306a36Sopenharmony_ci ipoib_mcast_send(dev, phdr->hwaddr, skb); 112962306a36Sopenharmony_ci return NETDEV_TX_OK; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci /* unicast, arrange "switch" according to probability */ 113362306a36Sopenharmony_ci switch (header->proto) { 113462306a36Sopenharmony_ci case htons(ETH_P_IP): 113562306a36Sopenharmony_ci case htons(ETH_P_IPV6): 113662306a36Sopenharmony_ci case htons(ETH_P_TIPC): 113762306a36Sopenharmony_ci neigh = ipoib_neigh_get(dev, phdr->hwaddr); 113862306a36Sopenharmony_ci if (unlikely(!neigh)) { 113962306a36Sopenharmony_ci neigh = neigh_add_path(skb, phdr->hwaddr, dev); 114062306a36Sopenharmony_ci if (likely(!neigh)) 114162306a36Sopenharmony_ci return NETDEV_TX_OK; 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci break; 114462306a36Sopenharmony_ci case htons(ETH_P_ARP): 114562306a36Sopenharmony_ci case htons(ETH_P_RARP): 114662306a36Sopenharmony_ci /* for unicast ARP and RARP should always perform path find */ 114762306a36Sopenharmony_ci unicast_arp_send(skb, dev, phdr); 114862306a36Sopenharmony_ci return NETDEV_TX_OK; 114962306a36Sopenharmony_ci default: 115062306a36Sopenharmony_ci /* ethertype not supported by IPoIB */ 115162306a36Sopenharmony_ci ++dev->stats.tx_dropped; 115262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 115362306a36Sopenharmony_ci return NETDEV_TX_OK; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_cisend_using_neigh: 115762306a36Sopenharmony_ci /* note we now hold a ref to neigh */ 115862306a36Sopenharmony_ci if (ipoib_cm_get(neigh)) { 115962306a36Sopenharmony_ci if (ipoib_cm_up(neigh)) { 116062306a36Sopenharmony_ci ipoib_cm_send(dev, skb, ipoib_cm_get(neigh)); 116162306a36Sopenharmony_ci goto unref; 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci } else if (neigh->ah && neigh->ah->valid) { 116462306a36Sopenharmony_ci neigh->ah->last_send = rn->send(dev, skb, neigh->ah->ah, 116562306a36Sopenharmony_ci IPOIB_QPN(phdr->hwaddr)); 116662306a36Sopenharmony_ci goto unref; 116762306a36Sopenharmony_ci } else if (neigh->ah) { 116862306a36Sopenharmony_ci neigh_refresh_path(neigh, phdr->hwaddr, dev); 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { 117262306a36Sopenharmony_ci push_pseudo_header(skb, phdr->hwaddr); 117362306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 117462306a36Sopenharmony_ci __skb_queue_tail(&neigh->queue, skb); 117562306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 117662306a36Sopenharmony_ci } else { 117762306a36Sopenharmony_ci ++dev->stats.tx_dropped; 117862306a36Sopenharmony_ci dev_kfree_skb_any(skb); 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ciunref: 118262306a36Sopenharmony_ci ipoib_neigh_put(neigh); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci return NETDEV_TX_OK; 118562306a36Sopenharmony_ci} 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_cistatic void ipoib_timeout(struct net_device *dev, unsigned int txqueue) 118862306a36Sopenharmony_ci{ 118962306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 119062306a36Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if (rn->tx_timeout) { 119362306a36Sopenharmony_ci rn->tx_timeout(dev, txqueue); 119462306a36Sopenharmony_ci return; 119562306a36Sopenharmony_ci } 119662306a36Sopenharmony_ci ipoib_warn(priv, "transmit timeout: latency %d msecs\n", 119762306a36Sopenharmony_ci jiffies_to_msecs(jiffies - dev_trans_start(dev))); 119862306a36Sopenharmony_ci ipoib_warn(priv, 119962306a36Sopenharmony_ci "queue stopped %d, tx_head %u, tx_tail %u, global_tx_head %u, global_tx_tail %u\n", 120062306a36Sopenharmony_ci netif_queue_stopped(dev), priv->tx_head, priv->tx_tail, 120162306a36Sopenharmony_ci priv->global_tx_head, priv->global_tx_tail); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci /* XXX reset QP, etc. */ 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_cistatic int ipoib_hard_header(struct sk_buff *skb, 120762306a36Sopenharmony_ci struct net_device *dev, 120862306a36Sopenharmony_ci unsigned short type, 120962306a36Sopenharmony_ci const void *daddr, 121062306a36Sopenharmony_ci const void *saddr, 121162306a36Sopenharmony_ci unsigned int len) 121262306a36Sopenharmony_ci{ 121362306a36Sopenharmony_ci struct ipoib_header *header; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci header = skb_push(skb, sizeof(*header)); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci header->proto = htons(type); 121862306a36Sopenharmony_ci header->reserved = 0; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci /* 122162306a36Sopenharmony_ci * we don't rely on dst_entry structure, always stuff the 122262306a36Sopenharmony_ci * destination address into skb hard header so we can figure out where 122362306a36Sopenharmony_ci * to send the packet later. 122462306a36Sopenharmony_ci */ 122562306a36Sopenharmony_ci push_pseudo_header(skb, daddr); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci return IPOIB_HARD_LEN; 122862306a36Sopenharmony_ci} 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_cistatic void ipoib_set_mcast_list(struct net_device *dev) 123162306a36Sopenharmony_ci{ 123262306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) { 123562306a36Sopenharmony_ci ipoib_dbg(priv, "IPOIB_FLAG_OPER_UP not set"); 123662306a36Sopenharmony_ci return; 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci queue_work(priv->wq, &priv->restart_task); 124062306a36Sopenharmony_ci} 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_cistatic int ipoib_get_iflink(const struct net_device *dev) 124362306a36Sopenharmony_ci{ 124462306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci /* parent interface */ 124762306a36Sopenharmony_ci if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) 124862306a36Sopenharmony_ci return dev->ifindex; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci /* child/vlan interface */ 125162306a36Sopenharmony_ci return priv->parent->ifindex; 125262306a36Sopenharmony_ci} 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_cistatic u32 ipoib_addr_hash(struct ipoib_neigh_hash *htbl, u8 *daddr) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci /* 125762306a36Sopenharmony_ci * Use only the address parts that contributes to spreading 125862306a36Sopenharmony_ci * The subnet prefix is not used as one can not connect to 125962306a36Sopenharmony_ci * same remote port (GUID) using the same remote QPN via two 126062306a36Sopenharmony_ci * different subnets. 126162306a36Sopenharmony_ci */ 126262306a36Sopenharmony_ci /* qpn octets[1:4) & port GUID octets[12:20) */ 126362306a36Sopenharmony_ci u32 *d32 = (u32 *) daddr; 126462306a36Sopenharmony_ci u32 hv; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci hv = jhash_3words(d32[3], d32[4], IPOIB_QPN_MASK & d32[0], 0); 126762306a36Sopenharmony_ci return hv & htbl->mask; 126862306a36Sopenharmony_ci} 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_cistruct ipoib_neigh *ipoib_neigh_get(struct net_device *dev, u8 *daddr) 127162306a36Sopenharmony_ci{ 127262306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 127362306a36Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 127462306a36Sopenharmony_ci struct ipoib_neigh_hash *htbl; 127562306a36Sopenharmony_ci struct ipoib_neigh *neigh = NULL; 127662306a36Sopenharmony_ci u32 hash_val; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci rcu_read_lock_bh(); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci htbl = rcu_dereference_bh(ntbl->htbl); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci if (!htbl) 128362306a36Sopenharmony_ci goto out_unlock; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci hash_val = ipoib_addr_hash(htbl, daddr); 128662306a36Sopenharmony_ci for (neigh = rcu_dereference_bh(htbl->buckets[hash_val]); 128762306a36Sopenharmony_ci neigh != NULL; 128862306a36Sopenharmony_ci neigh = rcu_dereference_bh(neigh->hnext)) { 128962306a36Sopenharmony_ci if (memcmp(daddr, neigh->daddr, INFINIBAND_ALEN) == 0) { 129062306a36Sopenharmony_ci /* found, take one ref on behalf of the caller */ 129162306a36Sopenharmony_ci if (!refcount_inc_not_zero(&neigh->refcnt)) { 129262306a36Sopenharmony_ci /* deleted */ 129362306a36Sopenharmony_ci neigh = NULL; 129462306a36Sopenharmony_ci goto out_unlock; 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci if (likely(skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE)) 129862306a36Sopenharmony_ci neigh->alive = jiffies; 129962306a36Sopenharmony_ci goto out_unlock; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ciout_unlock: 130462306a36Sopenharmony_ci rcu_read_unlock_bh(); 130562306a36Sopenharmony_ci return neigh; 130662306a36Sopenharmony_ci} 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_cistatic void __ipoib_reap_neigh(struct ipoib_dev_priv *priv) 130962306a36Sopenharmony_ci{ 131062306a36Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 131162306a36Sopenharmony_ci struct ipoib_neigh_hash *htbl; 131262306a36Sopenharmony_ci unsigned long neigh_obsolete; 131362306a36Sopenharmony_ci unsigned long dt; 131462306a36Sopenharmony_ci unsigned long flags; 131562306a36Sopenharmony_ci int i; 131662306a36Sopenharmony_ci LIST_HEAD(remove_list); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci htbl = rcu_dereference_protected(ntbl->htbl, 132162306a36Sopenharmony_ci lockdep_is_held(&priv->lock)); 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci if (!htbl) 132462306a36Sopenharmony_ci goto out_unlock; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci /* neigh is obsolete if it was idle for two GC periods */ 132762306a36Sopenharmony_ci dt = 2 * arp_tbl.gc_interval; 132862306a36Sopenharmony_ci neigh_obsolete = jiffies - dt; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci for (i = 0; i < htbl->size; i++) { 133162306a36Sopenharmony_ci struct ipoib_neigh *neigh; 133262306a36Sopenharmony_ci struct ipoib_neigh __rcu **np = &htbl->buckets[i]; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci while ((neigh = rcu_dereference_protected(*np, 133562306a36Sopenharmony_ci lockdep_is_held(&priv->lock))) != NULL) { 133662306a36Sopenharmony_ci /* was the neigh idle for two GC periods */ 133762306a36Sopenharmony_ci if (time_after(neigh_obsolete, neigh->alive)) { 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci ipoib_check_and_add_mcast_sendonly(priv, neigh->daddr + 4, &remove_list); 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci rcu_assign_pointer(*np, 134262306a36Sopenharmony_ci rcu_dereference_protected(neigh->hnext, 134362306a36Sopenharmony_ci lockdep_is_held(&priv->lock))); 134462306a36Sopenharmony_ci /* remove from path/mc list */ 134562306a36Sopenharmony_ci list_del_init(&neigh->list); 134662306a36Sopenharmony_ci call_rcu(&neigh->rcu, ipoib_neigh_reclaim); 134762306a36Sopenharmony_ci } else { 134862306a36Sopenharmony_ci np = &neigh->hnext; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci } 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ciout_unlock: 135562306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 135662306a36Sopenharmony_ci ipoib_mcast_remove_list(&remove_list); 135762306a36Sopenharmony_ci} 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_cistatic void ipoib_reap_neigh(struct work_struct *work) 136062306a36Sopenharmony_ci{ 136162306a36Sopenharmony_ci struct ipoib_dev_priv *priv = 136262306a36Sopenharmony_ci container_of(work, struct ipoib_dev_priv, neigh_reap_task.work); 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci __ipoib_reap_neigh(priv); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci queue_delayed_work(priv->wq, &priv->neigh_reap_task, 136762306a36Sopenharmony_ci arp_tbl.gc_interval); 136862306a36Sopenharmony_ci} 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_cistatic struct ipoib_neigh *ipoib_neigh_ctor(u8 *daddr, 137262306a36Sopenharmony_ci struct net_device *dev) 137362306a36Sopenharmony_ci{ 137462306a36Sopenharmony_ci struct ipoib_neigh *neigh; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci neigh = kzalloc(sizeof(*neigh), GFP_ATOMIC); 137762306a36Sopenharmony_ci if (!neigh) 137862306a36Sopenharmony_ci return NULL; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci neigh->dev = dev; 138162306a36Sopenharmony_ci memcpy(&neigh->daddr, daddr, sizeof(neigh->daddr)); 138262306a36Sopenharmony_ci skb_queue_head_init(&neigh->queue); 138362306a36Sopenharmony_ci INIT_LIST_HEAD(&neigh->list); 138462306a36Sopenharmony_ci ipoib_cm_set(neigh, NULL); 138562306a36Sopenharmony_ci /* one ref on behalf of the caller */ 138662306a36Sopenharmony_ci refcount_set(&neigh->refcnt, 1); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci return neigh; 138962306a36Sopenharmony_ci} 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_cistruct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr, 139262306a36Sopenharmony_ci struct net_device *dev) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 139562306a36Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 139662306a36Sopenharmony_ci struct ipoib_neigh_hash *htbl; 139762306a36Sopenharmony_ci struct ipoib_neigh *neigh; 139862306a36Sopenharmony_ci u32 hash_val; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci htbl = rcu_dereference_protected(ntbl->htbl, 140162306a36Sopenharmony_ci lockdep_is_held(&priv->lock)); 140262306a36Sopenharmony_ci if (!htbl) { 140362306a36Sopenharmony_ci neigh = NULL; 140462306a36Sopenharmony_ci goto out_unlock; 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci /* need to add a new neigh, but maybe some other thread succeeded? 140862306a36Sopenharmony_ci * recalc hash, maybe hash resize took place so we do a search 140962306a36Sopenharmony_ci */ 141062306a36Sopenharmony_ci hash_val = ipoib_addr_hash(htbl, daddr); 141162306a36Sopenharmony_ci for (neigh = rcu_dereference_protected(htbl->buckets[hash_val], 141262306a36Sopenharmony_ci lockdep_is_held(&priv->lock)); 141362306a36Sopenharmony_ci neigh != NULL; 141462306a36Sopenharmony_ci neigh = rcu_dereference_protected(neigh->hnext, 141562306a36Sopenharmony_ci lockdep_is_held(&priv->lock))) { 141662306a36Sopenharmony_ci if (memcmp(daddr, neigh->daddr, INFINIBAND_ALEN) == 0) { 141762306a36Sopenharmony_ci /* found, take one ref on behalf of the caller */ 141862306a36Sopenharmony_ci if (!refcount_inc_not_zero(&neigh->refcnt)) { 141962306a36Sopenharmony_ci /* deleted */ 142062306a36Sopenharmony_ci neigh = NULL; 142162306a36Sopenharmony_ci break; 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci neigh->alive = jiffies; 142462306a36Sopenharmony_ci goto out_unlock; 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci neigh = ipoib_neigh_ctor(daddr, dev); 142962306a36Sopenharmony_ci if (!neigh) 143062306a36Sopenharmony_ci goto out_unlock; 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci /* one ref on behalf of the hash table */ 143362306a36Sopenharmony_ci refcount_inc(&neigh->refcnt); 143462306a36Sopenharmony_ci neigh->alive = jiffies; 143562306a36Sopenharmony_ci /* put in hash */ 143662306a36Sopenharmony_ci rcu_assign_pointer(neigh->hnext, 143762306a36Sopenharmony_ci rcu_dereference_protected(htbl->buckets[hash_val], 143862306a36Sopenharmony_ci lockdep_is_held(&priv->lock))); 143962306a36Sopenharmony_ci rcu_assign_pointer(htbl->buckets[hash_val], neigh); 144062306a36Sopenharmony_ci atomic_inc(&ntbl->entries); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ciout_unlock: 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci return neigh; 144562306a36Sopenharmony_ci} 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_civoid ipoib_neigh_dtor(struct ipoib_neigh *neigh) 144862306a36Sopenharmony_ci{ 144962306a36Sopenharmony_ci /* neigh reference count was dropprd to zero */ 145062306a36Sopenharmony_ci struct net_device *dev = neigh->dev; 145162306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 145262306a36Sopenharmony_ci struct sk_buff *skb; 145362306a36Sopenharmony_ci if (neigh->ah) 145462306a36Sopenharmony_ci ipoib_put_ah(neigh->ah); 145562306a36Sopenharmony_ci while ((skb = __skb_dequeue(&neigh->queue))) { 145662306a36Sopenharmony_ci ++dev->stats.tx_dropped; 145762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci if (ipoib_cm_get(neigh)) 146062306a36Sopenharmony_ci ipoib_cm_destroy_tx(ipoib_cm_get(neigh)); 146162306a36Sopenharmony_ci ipoib_dbg(ipoib_priv(dev), 146262306a36Sopenharmony_ci "neigh free for %06x %pI6\n", 146362306a36Sopenharmony_ci IPOIB_QPN(neigh->daddr), 146462306a36Sopenharmony_ci neigh->daddr + 4); 146562306a36Sopenharmony_ci kfree(neigh); 146662306a36Sopenharmony_ci if (atomic_dec_and_test(&priv->ntbl.entries)) { 146762306a36Sopenharmony_ci if (test_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags)) 146862306a36Sopenharmony_ci complete(&priv->ntbl.flushed); 146962306a36Sopenharmony_ci } 147062306a36Sopenharmony_ci} 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_cistatic void ipoib_neigh_reclaim(struct rcu_head *rp) 147362306a36Sopenharmony_ci{ 147462306a36Sopenharmony_ci /* Called as a result of removal from hash table */ 147562306a36Sopenharmony_ci struct ipoib_neigh *neigh = container_of(rp, struct ipoib_neigh, rcu); 147662306a36Sopenharmony_ci /* note TX context may hold another ref */ 147762306a36Sopenharmony_ci ipoib_neigh_put(neigh); 147862306a36Sopenharmony_ci} 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_civoid ipoib_neigh_free(struct ipoib_neigh *neigh) 148162306a36Sopenharmony_ci{ 148262306a36Sopenharmony_ci struct net_device *dev = neigh->dev; 148362306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 148462306a36Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 148562306a36Sopenharmony_ci struct ipoib_neigh_hash *htbl; 148662306a36Sopenharmony_ci struct ipoib_neigh __rcu **np; 148762306a36Sopenharmony_ci struct ipoib_neigh *n; 148862306a36Sopenharmony_ci u32 hash_val; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci htbl = rcu_dereference_protected(ntbl->htbl, 149162306a36Sopenharmony_ci lockdep_is_held(&priv->lock)); 149262306a36Sopenharmony_ci if (!htbl) 149362306a36Sopenharmony_ci return; 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci hash_val = ipoib_addr_hash(htbl, neigh->daddr); 149662306a36Sopenharmony_ci np = &htbl->buckets[hash_val]; 149762306a36Sopenharmony_ci for (n = rcu_dereference_protected(*np, 149862306a36Sopenharmony_ci lockdep_is_held(&priv->lock)); 149962306a36Sopenharmony_ci n != NULL; 150062306a36Sopenharmony_ci n = rcu_dereference_protected(*np, 150162306a36Sopenharmony_ci lockdep_is_held(&priv->lock))) { 150262306a36Sopenharmony_ci if (n == neigh) { 150362306a36Sopenharmony_ci /* found */ 150462306a36Sopenharmony_ci rcu_assign_pointer(*np, 150562306a36Sopenharmony_ci rcu_dereference_protected(neigh->hnext, 150662306a36Sopenharmony_ci lockdep_is_held(&priv->lock))); 150762306a36Sopenharmony_ci /* remove from parent list */ 150862306a36Sopenharmony_ci list_del_init(&neigh->list); 150962306a36Sopenharmony_ci call_rcu(&neigh->rcu, ipoib_neigh_reclaim); 151062306a36Sopenharmony_ci return; 151162306a36Sopenharmony_ci } else { 151262306a36Sopenharmony_ci np = &n->hnext; 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci } 151562306a36Sopenharmony_ci} 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_cistatic int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv) 151862306a36Sopenharmony_ci{ 151962306a36Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 152062306a36Sopenharmony_ci struct ipoib_neigh_hash *htbl; 152162306a36Sopenharmony_ci struct ipoib_neigh __rcu **buckets; 152262306a36Sopenharmony_ci u32 size; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci clear_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags); 152562306a36Sopenharmony_ci ntbl->htbl = NULL; 152662306a36Sopenharmony_ci htbl = kzalloc(sizeof(*htbl), GFP_KERNEL); 152762306a36Sopenharmony_ci if (!htbl) 152862306a36Sopenharmony_ci return -ENOMEM; 152962306a36Sopenharmony_ci size = roundup_pow_of_two(arp_tbl.gc_thresh3); 153062306a36Sopenharmony_ci buckets = kvcalloc(size, sizeof(*buckets), GFP_KERNEL); 153162306a36Sopenharmony_ci if (!buckets) { 153262306a36Sopenharmony_ci kfree(htbl); 153362306a36Sopenharmony_ci return -ENOMEM; 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci htbl->size = size; 153662306a36Sopenharmony_ci htbl->mask = (size - 1); 153762306a36Sopenharmony_ci htbl->buckets = buckets; 153862306a36Sopenharmony_ci RCU_INIT_POINTER(ntbl->htbl, htbl); 153962306a36Sopenharmony_ci htbl->ntbl = ntbl; 154062306a36Sopenharmony_ci atomic_set(&ntbl->entries, 0); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci /* start garbage collection */ 154362306a36Sopenharmony_ci queue_delayed_work(priv->wq, &priv->neigh_reap_task, 154462306a36Sopenharmony_ci arp_tbl.gc_interval); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci return 0; 154762306a36Sopenharmony_ci} 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_cistatic void neigh_hash_free_rcu(struct rcu_head *head) 155062306a36Sopenharmony_ci{ 155162306a36Sopenharmony_ci struct ipoib_neigh_hash *htbl = container_of(head, 155262306a36Sopenharmony_ci struct ipoib_neigh_hash, 155362306a36Sopenharmony_ci rcu); 155462306a36Sopenharmony_ci struct ipoib_neigh __rcu **buckets = htbl->buckets; 155562306a36Sopenharmony_ci struct ipoib_neigh_table *ntbl = htbl->ntbl; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci kvfree(buckets); 155862306a36Sopenharmony_ci kfree(htbl); 155962306a36Sopenharmony_ci complete(&ntbl->deleted); 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_civoid ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid) 156362306a36Sopenharmony_ci{ 156462306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 156562306a36Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 156662306a36Sopenharmony_ci struct ipoib_neigh_hash *htbl; 156762306a36Sopenharmony_ci unsigned long flags; 156862306a36Sopenharmony_ci int i; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci /* remove all neigh connected to a given path or mcast */ 157162306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci htbl = rcu_dereference_protected(ntbl->htbl, 157462306a36Sopenharmony_ci lockdep_is_held(&priv->lock)); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci if (!htbl) 157762306a36Sopenharmony_ci goto out_unlock; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci for (i = 0; i < htbl->size; i++) { 158062306a36Sopenharmony_ci struct ipoib_neigh *neigh; 158162306a36Sopenharmony_ci struct ipoib_neigh __rcu **np = &htbl->buckets[i]; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci while ((neigh = rcu_dereference_protected(*np, 158462306a36Sopenharmony_ci lockdep_is_held(&priv->lock))) != NULL) { 158562306a36Sopenharmony_ci /* delete neighs belong to this parent */ 158662306a36Sopenharmony_ci if (!memcmp(gid, neigh->daddr + 4, sizeof (union ib_gid))) { 158762306a36Sopenharmony_ci rcu_assign_pointer(*np, 158862306a36Sopenharmony_ci rcu_dereference_protected(neigh->hnext, 158962306a36Sopenharmony_ci lockdep_is_held(&priv->lock))); 159062306a36Sopenharmony_ci /* remove from parent list */ 159162306a36Sopenharmony_ci list_del_init(&neigh->list); 159262306a36Sopenharmony_ci call_rcu(&neigh->rcu, ipoib_neigh_reclaim); 159362306a36Sopenharmony_ci } else { 159462306a36Sopenharmony_ci np = &neigh->hnext; 159562306a36Sopenharmony_ci } 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci } 159862306a36Sopenharmony_ci } 159962306a36Sopenharmony_ciout_unlock: 160062306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 160162306a36Sopenharmony_ci} 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_cistatic void ipoib_flush_neighs(struct ipoib_dev_priv *priv) 160462306a36Sopenharmony_ci{ 160562306a36Sopenharmony_ci struct ipoib_neigh_table *ntbl = &priv->ntbl; 160662306a36Sopenharmony_ci struct ipoib_neigh_hash *htbl; 160762306a36Sopenharmony_ci unsigned long flags; 160862306a36Sopenharmony_ci int i, wait_flushed = 0; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci init_completion(&priv->ntbl.flushed); 161162306a36Sopenharmony_ci set_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags); 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci htbl = rcu_dereference_protected(ntbl->htbl, 161662306a36Sopenharmony_ci lockdep_is_held(&priv->lock)); 161762306a36Sopenharmony_ci if (!htbl) 161862306a36Sopenharmony_ci goto out_unlock; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci wait_flushed = atomic_read(&priv->ntbl.entries); 162162306a36Sopenharmony_ci if (!wait_flushed) 162262306a36Sopenharmony_ci goto free_htbl; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci for (i = 0; i < htbl->size; i++) { 162562306a36Sopenharmony_ci struct ipoib_neigh *neigh; 162662306a36Sopenharmony_ci struct ipoib_neigh __rcu **np = &htbl->buckets[i]; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci while ((neigh = rcu_dereference_protected(*np, 162962306a36Sopenharmony_ci lockdep_is_held(&priv->lock))) != NULL) { 163062306a36Sopenharmony_ci rcu_assign_pointer(*np, 163162306a36Sopenharmony_ci rcu_dereference_protected(neigh->hnext, 163262306a36Sopenharmony_ci lockdep_is_held(&priv->lock))); 163362306a36Sopenharmony_ci /* remove from path/mc list */ 163462306a36Sopenharmony_ci list_del_init(&neigh->list); 163562306a36Sopenharmony_ci call_rcu(&neigh->rcu, ipoib_neigh_reclaim); 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci } 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_cifree_htbl: 164062306a36Sopenharmony_ci rcu_assign_pointer(ntbl->htbl, NULL); 164162306a36Sopenharmony_ci call_rcu(&htbl->rcu, neigh_hash_free_rcu); 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ciout_unlock: 164462306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 164562306a36Sopenharmony_ci if (wait_flushed) 164662306a36Sopenharmony_ci wait_for_completion(&priv->ntbl.flushed); 164762306a36Sopenharmony_ci} 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_cistatic void ipoib_neigh_hash_uninit(struct net_device *dev) 165062306a36Sopenharmony_ci{ 165162306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci ipoib_dbg(priv, "%s\n", __func__); 165462306a36Sopenharmony_ci init_completion(&priv->ntbl.deleted); 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci cancel_delayed_work_sync(&priv->neigh_reap_task); 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci ipoib_flush_neighs(priv); 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci wait_for_completion(&priv->ntbl.deleted); 166162306a36Sopenharmony_ci} 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_cistatic void ipoib_napi_add(struct net_device *dev) 166462306a36Sopenharmony_ci{ 166562306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci netif_napi_add_weight(dev, &priv->recv_napi, ipoib_rx_poll, 166862306a36Sopenharmony_ci IPOIB_NUM_WC); 166962306a36Sopenharmony_ci netif_napi_add_weight(dev, &priv->send_napi, ipoib_tx_poll, 167062306a36Sopenharmony_ci MAX_SEND_CQE); 167162306a36Sopenharmony_ci} 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_cistatic void ipoib_napi_del(struct net_device *dev) 167462306a36Sopenharmony_ci{ 167562306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci netif_napi_del(&priv->recv_napi); 167862306a36Sopenharmony_ci netif_napi_del(&priv->send_napi); 167962306a36Sopenharmony_ci} 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_cistatic void ipoib_dev_uninit_default(struct net_device *dev) 168262306a36Sopenharmony_ci{ 168362306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci ipoib_transport_dev_cleanup(dev); 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci ipoib_napi_del(dev); 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci ipoib_cm_dev_cleanup(dev); 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci kfree(priv->rx_ring); 169262306a36Sopenharmony_ci vfree(priv->tx_ring); 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci priv->rx_ring = NULL; 169562306a36Sopenharmony_ci priv->tx_ring = NULL; 169662306a36Sopenharmony_ci} 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_cistatic int ipoib_dev_init_default(struct net_device *dev) 169962306a36Sopenharmony_ci{ 170062306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 170162306a36Sopenharmony_ci u8 addr_mod[3]; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci ipoib_napi_add(dev); 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci /* Allocate RX/TX "rings" to hold queued skbs */ 170662306a36Sopenharmony_ci priv->rx_ring = kcalloc(ipoib_recvq_size, 170762306a36Sopenharmony_ci sizeof(*priv->rx_ring), 170862306a36Sopenharmony_ci GFP_KERNEL); 170962306a36Sopenharmony_ci if (!priv->rx_ring) 171062306a36Sopenharmony_ci goto out; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci priv->tx_ring = vzalloc(array_size(ipoib_sendq_size, 171362306a36Sopenharmony_ci sizeof(*priv->tx_ring))); 171462306a36Sopenharmony_ci if (!priv->tx_ring) { 171562306a36Sopenharmony_ci pr_warn("%s: failed to allocate TX ring (%d entries)\n", 171662306a36Sopenharmony_ci priv->ca->name, ipoib_sendq_size); 171762306a36Sopenharmony_ci goto out_rx_ring_cleanup; 171862306a36Sopenharmony_ci } 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci /* priv->tx_head, tx_tail and global_tx_tail/head are already 0 */ 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci if (ipoib_transport_dev_init(dev, priv->ca)) { 172362306a36Sopenharmony_ci pr_warn("%s: ipoib_transport_dev_init failed\n", 172462306a36Sopenharmony_ci priv->ca->name); 172562306a36Sopenharmony_ci goto out_tx_ring_cleanup; 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci /* after qp created set dev address */ 172962306a36Sopenharmony_ci addr_mod[0] = (priv->qp->qp_num >> 16) & 0xff; 173062306a36Sopenharmony_ci addr_mod[1] = (priv->qp->qp_num >> 8) & 0xff; 173162306a36Sopenharmony_ci addr_mod[2] = (priv->qp->qp_num) & 0xff; 173262306a36Sopenharmony_ci dev_addr_mod(priv->dev, 1, addr_mod, sizeof(addr_mod)); 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci return 0; 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ciout_tx_ring_cleanup: 173762306a36Sopenharmony_ci vfree(priv->tx_ring); 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ciout_rx_ring_cleanup: 174062306a36Sopenharmony_ci kfree(priv->rx_ring); 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ciout: 174362306a36Sopenharmony_ci ipoib_napi_del(dev); 174462306a36Sopenharmony_ci return -ENOMEM; 174562306a36Sopenharmony_ci} 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_cistatic int ipoib_ioctl(struct net_device *dev, struct ifreq *ifr, 174862306a36Sopenharmony_ci int cmd) 174962306a36Sopenharmony_ci{ 175062306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci if (!priv->rn_ops->ndo_eth_ioctl) 175362306a36Sopenharmony_ci return -EOPNOTSUPP; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci return priv->rn_ops->ndo_eth_ioctl(dev, ifr, cmd); 175662306a36Sopenharmony_ci} 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_cistatic int ipoib_dev_init(struct net_device *dev) 175962306a36Sopenharmony_ci{ 176062306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 176162306a36Sopenharmony_ci int ret = -ENOMEM; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci priv->qp = NULL; 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci /* 176662306a36Sopenharmony_ci * the various IPoIB tasks assume they will never race against 176762306a36Sopenharmony_ci * themselves, so always use a single thread workqueue 176862306a36Sopenharmony_ci */ 176962306a36Sopenharmony_ci priv->wq = alloc_ordered_workqueue("ipoib_wq", WQ_MEM_RECLAIM); 177062306a36Sopenharmony_ci if (!priv->wq) { 177162306a36Sopenharmony_ci pr_warn("%s: failed to allocate device WQ\n", dev->name); 177262306a36Sopenharmony_ci goto out; 177362306a36Sopenharmony_ci } 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci /* create pd, which used both for control and datapath*/ 177662306a36Sopenharmony_ci priv->pd = ib_alloc_pd(priv->ca, 0); 177762306a36Sopenharmony_ci if (IS_ERR(priv->pd)) { 177862306a36Sopenharmony_ci pr_warn("%s: failed to allocate PD\n", priv->ca->name); 177962306a36Sopenharmony_ci goto clean_wq; 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci ret = priv->rn_ops->ndo_init(dev); 178362306a36Sopenharmony_ci if (ret) { 178462306a36Sopenharmony_ci pr_warn("%s failed to init HW resource\n", dev->name); 178562306a36Sopenharmony_ci goto out_free_pd; 178662306a36Sopenharmony_ci } 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci ret = ipoib_neigh_hash_init(priv); 178962306a36Sopenharmony_ci if (ret) { 179062306a36Sopenharmony_ci pr_warn("%s failed to init neigh hash\n", dev->name); 179162306a36Sopenharmony_ci goto out_dev_uninit; 179262306a36Sopenharmony_ci } 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci if (dev->flags & IFF_UP) { 179562306a36Sopenharmony_ci if (ipoib_ib_dev_open(dev)) { 179662306a36Sopenharmony_ci pr_warn("%s failed to open device\n", dev->name); 179762306a36Sopenharmony_ci ret = -ENODEV; 179862306a36Sopenharmony_ci goto out_hash_uninit; 179962306a36Sopenharmony_ci } 180062306a36Sopenharmony_ci } 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci return 0; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ciout_hash_uninit: 180562306a36Sopenharmony_ci ipoib_neigh_hash_uninit(dev); 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ciout_dev_uninit: 180862306a36Sopenharmony_ci ipoib_ib_dev_cleanup(dev); 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ciout_free_pd: 181162306a36Sopenharmony_ci if (priv->pd) { 181262306a36Sopenharmony_ci ib_dealloc_pd(priv->pd); 181362306a36Sopenharmony_ci priv->pd = NULL; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ciclean_wq: 181762306a36Sopenharmony_ci if (priv->wq) { 181862306a36Sopenharmony_ci destroy_workqueue(priv->wq); 181962306a36Sopenharmony_ci priv->wq = NULL; 182062306a36Sopenharmony_ci } 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ciout: 182362306a36Sopenharmony_ci return ret; 182462306a36Sopenharmony_ci} 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci/* 182762306a36Sopenharmony_ci * This must be called before doing an unregister_netdev on a parent device to 182862306a36Sopenharmony_ci * shutdown the IB event handler. 182962306a36Sopenharmony_ci */ 183062306a36Sopenharmony_cistatic void ipoib_parent_unregister_pre(struct net_device *ndev) 183162306a36Sopenharmony_ci{ 183262306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci /* 183562306a36Sopenharmony_ci * ipoib_set_mac checks netif_running before pushing work, clearing 183662306a36Sopenharmony_ci * running ensures the it will not add more work. 183762306a36Sopenharmony_ci */ 183862306a36Sopenharmony_ci rtnl_lock(); 183962306a36Sopenharmony_ci dev_change_flags(priv->dev, priv->dev->flags & ~IFF_UP, NULL); 184062306a36Sopenharmony_ci rtnl_unlock(); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci /* ipoib_event() cannot be running once this returns */ 184362306a36Sopenharmony_ci ib_unregister_event_handler(&priv->event_handler); 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci /* 184662306a36Sopenharmony_ci * Work on the queue grabs the rtnl lock, so this cannot be done while 184762306a36Sopenharmony_ci * also holding it. 184862306a36Sopenharmony_ci */ 184962306a36Sopenharmony_ci flush_workqueue(ipoib_workqueue); 185062306a36Sopenharmony_ci} 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_cistatic void ipoib_set_dev_features(struct ipoib_dev_priv *priv) 185362306a36Sopenharmony_ci{ 185462306a36Sopenharmony_ci priv->hca_caps = priv->ca->attrs.device_cap_flags; 185562306a36Sopenharmony_ci priv->kernel_caps = priv->ca->attrs.kernel_cap_flags; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci if (priv->hca_caps & IB_DEVICE_UD_IP_CSUM) { 185862306a36Sopenharmony_ci priv->dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci if (priv->kernel_caps & IBK_UD_TSO) 186162306a36Sopenharmony_ci priv->dev->hw_features |= NETIF_F_TSO; 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci priv->dev->features |= priv->dev->hw_features; 186462306a36Sopenharmony_ci } 186562306a36Sopenharmony_ci} 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_cistatic int ipoib_parent_init(struct net_device *ndev) 186862306a36Sopenharmony_ci{ 186962306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 187062306a36Sopenharmony_ci struct ib_port_attr attr; 187162306a36Sopenharmony_ci int result; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci result = ib_query_port(priv->ca, priv->port, &attr); 187462306a36Sopenharmony_ci if (result) { 187562306a36Sopenharmony_ci pr_warn("%s: ib_query_port %d failed\n", priv->ca->name, 187662306a36Sopenharmony_ci priv->port); 187762306a36Sopenharmony_ci return result; 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci priv->max_ib_mtu = rdma_mtu_from_attr(priv->ca, priv->port, &attr); 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci result = ib_query_pkey(priv->ca, priv->port, 0, &priv->pkey); 188262306a36Sopenharmony_ci if (result) { 188362306a36Sopenharmony_ci pr_warn("%s: ib_query_pkey port %d failed (ret = %d)\n", 188462306a36Sopenharmony_ci priv->ca->name, priv->port, result); 188562306a36Sopenharmony_ci return result; 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_ci result = rdma_query_gid(priv->ca, priv->port, 0, &priv->local_gid); 188962306a36Sopenharmony_ci if (result) { 189062306a36Sopenharmony_ci pr_warn("%s: rdma_query_gid port %d failed (ret = %d)\n", 189162306a36Sopenharmony_ci priv->ca->name, priv->port, result); 189262306a36Sopenharmony_ci return result; 189362306a36Sopenharmony_ci } 189462306a36Sopenharmony_ci dev_addr_mod(priv->dev, 4, priv->local_gid.raw, sizeof(union ib_gid)); 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci SET_NETDEV_DEV(priv->dev, priv->ca->dev.parent); 189762306a36Sopenharmony_ci priv->dev->dev_port = priv->port - 1; 189862306a36Sopenharmony_ci /* Let's set this one too for backwards compatibility. */ 189962306a36Sopenharmony_ci priv->dev->dev_id = priv->port - 1; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci return 0; 190262306a36Sopenharmony_ci} 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_cistatic void ipoib_child_init(struct net_device *ndev) 190562306a36Sopenharmony_ci{ 190662306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 190762306a36Sopenharmony_ci struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci priv->max_ib_mtu = ppriv->max_ib_mtu; 191062306a36Sopenharmony_ci set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags); 191162306a36Sopenharmony_ci if (memchr_inv(priv->dev->dev_addr, 0, INFINIBAND_ALEN)) 191262306a36Sopenharmony_ci memcpy(&priv->local_gid, priv->dev->dev_addr + 4, 191362306a36Sopenharmony_ci sizeof(priv->local_gid)); 191462306a36Sopenharmony_ci else { 191562306a36Sopenharmony_ci __dev_addr_set(priv->dev, ppriv->dev->dev_addr, 191662306a36Sopenharmony_ci INFINIBAND_ALEN); 191762306a36Sopenharmony_ci memcpy(&priv->local_gid, &ppriv->local_gid, 191862306a36Sopenharmony_ci sizeof(priv->local_gid)); 191962306a36Sopenharmony_ci } 192062306a36Sopenharmony_ci} 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_cistatic int ipoib_ndo_init(struct net_device *ndev) 192362306a36Sopenharmony_ci{ 192462306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 192562306a36Sopenharmony_ci int rc; 192662306a36Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(ndev); 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci if (priv->parent) { 192962306a36Sopenharmony_ci ipoib_child_init(ndev); 193062306a36Sopenharmony_ci } else { 193162306a36Sopenharmony_ci rc = ipoib_parent_init(ndev); 193262306a36Sopenharmony_ci if (rc) 193362306a36Sopenharmony_ci return rc; 193462306a36Sopenharmony_ci } 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci /* MTU will be reset when mcast join happens */ 193762306a36Sopenharmony_ci ndev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu); 193862306a36Sopenharmony_ci priv->mcast_mtu = priv->admin_mtu = ndev->mtu; 193962306a36Sopenharmony_ci rn->mtu = priv->mcast_mtu; 194062306a36Sopenharmony_ci ndev->max_mtu = IPOIB_CM_MTU; 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci ndev->neigh_priv_len = sizeof(struct ipoib_neigh); 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci /* 194562306a36Sopenharmony_ci * Set the full membership bit, so that we join the right 194662306a36Sopenharmony_ci * broadcast group, etc. 194762306a36Sopenharmony_ci */ 194862306a36Sopenharmony_ci priv->pkey |= 0x8000; 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci ndev->broadcast[8] = priv->pkey >> 8; 195162306a36Sopenharmony_ci ndev->broadcast[9] = priv->pkey & 0xff; 195262306a36Sopenharmony_ci set_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags); 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci ipoib_set_dev_features(priv); 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci rc = ipoib_dev_init(ndev); 195762306a36Sopenharmony_ci if (rc) { 195862306a36Sopenharmony_ci pr_warn("%s: failed to initialize device: %s port %d (ret = %d)\n", 195962306a36Sopenharmony_ci priv->ca->name, priv->dev->name, priv->port, rc); 196062306a36Sopenharmony_ci return rc; 196162306a36Sopenharmony_ci } 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci if (priv->parent) { 196462306a36Sopenharmony_ci struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent); 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci dev_hold(priv->parent); 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci down_write(&ppriv->vlan_rwsem); 196962306a36Sopenharmony_ci list_add_tail(&priv->list, &ppriv->child_intfs); 197062306a36Sopenharmony_ci up_write(&ppriv->vlan_rwsem); 197162306a36Sopenharmony_ci } 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci return 0; 197462306a36Sopenharmony_ci} 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_cistatic void ipoib_ndo_uninit(struct net_device *dev) 197762306a36Sopenharmony_ci{ 197862306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci ASSERT_RTNL(); 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci /* 198362306a36Sopenharmony_ci * ipoib_remove_one guarantees the children are removed before the 198462306a36Sopenharmony_ci * parent, and that is the only place where a parent can be removed. 198562306a36Sopenharmony_ci */ 198662306a36Sopenharmony_ci WARN_ON(!list_empty(&priv->child_intfs)); 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci if (priv->parent) { 198962306a36Sopenharmony_ci struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent); 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci down_write(&ppriv->vlan_rwsem); 199262306a36Sopenharmony_ci list_del(&priv->list); 199362306a36Sopenharmony_ci up_write(&ppriv->vlan_rwsem); 199462306a36Sopenharmony_ci } 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci ipoib_neigh_hash_uninit(dev); 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci ipoib_ib_dev_cleanup(dev); 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci /* no more works over the priv->wq */ 200162306a36Sopenharmony_ci if (priv->wq) { 200262306a36Sopenharmony_ci /* See ipoib_mcast_carrier_on_task() */ 200362306a36Sopenharmony_ci WARN_ON(test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)); 200462306a36Sopenharmony_ci destroy_workqueue(priv->wq); 200562306a36Sopenharmony_ci priv->wq = NULL; 200662306a36Sopenharmony_ci } 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci if (priv->parent) 200962306a36Sopenharmony_ci dev_put(priv->parent); 201062306a36Sopenharmony_ci} 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_cistatic int ipoib_set_vf_link_state(struct net_device *dev, int vf, int link_state) 201362306a36Sopenharmony_ci{ 201462306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci return ib_set_vf_link_state(priv->ca, vf, priv->port, link_state); 201762306a36Sopenharmony_ci} 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_cistatic int ipoib_get_vf_config(struct net_device *dev, int vf, 202062306a36Sopenharmony_ci struct ifla_vf_info *ivf) 202162306a36Sopenharmony_ci{ 202262306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 202362306a36Sopenharmony_ci int err; 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci err = ib_get_vf_config(priv->ca, vf, priv->port, ivf); 202662306a36Sopenharmony_ci if (err) 202762306a36Sopenharmony_ci return err; 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci ivf->vf = vf; 203062306a36Sopenharmony_ci memcpy(ivf->mac, dev->dev_addr, dev->addr_len); 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci return 0; 203362306a36Sopenharmony_ci} 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_cistatic int ipoib_set_vf_guid(struct net_device *dev, int vf, u64 guid, int type) 203662306a36Sopenharmony_ci{ 203762306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci if (type != IFLA_VF_IB_NODE_GUID && type != IFLA_VF_IB_PORT_GUID) 204062306a36Sopenharmony_ci return -EINVAL; 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci return ib_set_vf_guid(priv->ca, vf, priv->port, guid, type); 204362306a36Sopenharmony_ci} 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_cistatic int ipoib_get_vf_guid(struct net_device *dev, int vf, 204662306a36Sopenharmony_ci struct ifla_vf_guid *node_guid, 204762306a36Sopenharmony_ci struct ifla_vf_guid *port_guid) 204862306a36Sopenharmony_ci{ 204962306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci return ib_get_vf_guid(priv->ca, vf, priv->port, node_guid, port_guid); 205262306a36Sopenharmony_ci} 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_cistatic int ipoib_get_vf_stats(struct net_device *dev, int vf, 205562306a36Sopenharmony_ci struct ifla_vf_stats *vf_stats) 205662306a36Sopenharmony_ci{ 205762306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci return ib_get_vf_stats(priv->ca, vf, priv->port, vf_stats); 206062306a36Sopenharmony_ci} 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_cistatic const struct header_ops ipoib_header_ops = { 206362306a36Sopenharmony_ci .create = ipoib_hard_header, 206462306a36Sopenharmony_ci}; 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_cistatic const struct net_device_ops ipoib_netdev_ops_pf = { 206762306a36Sopenharmony_ci .ndo_init = ipoib_ndo_init, 206862306a36Sopenharmony_ci .ndo_uninit = ipoib_ndo_uninit, 206962306a36Sopenharmony_ci .ndo_open = ipoib_open, 207062306a36Sopenharmony_ci .ndo_stop = ipoib_stop, 207162306a36Sopenharmony_ci .ndo_change_mtu = ipoib_change_mtu, 207262306a36Sopenharmony_ci .ndo_fix_features = ipoib_fix_features, 207362306a36Sopenharmony_ci .ndo_start_xmit = ipoib_start_xmit, 207462306a36Sopenharmony_ci .ndo_tx_timeout = ipoib_timeout, 207562306a36Sopenharmony_ci .ndo_set_rx_mode = ipoib_set_mcast_list, 207662306a36Sopenharmony_ci .ndo_get_iflink = ipoib_get_iflink, 207762306a36Sopenharmony_ci .ndo_set_vf_link_state = ipoib_set_vf_link_state, 207862306a36Sopenharmony_ci .ndo_get_vf_config = ipoib_get_vf_config, 207962306a36Sopenharmony_ci .ndo_get_vf_stats = ipoib_get_vf_stats, 208062306a36Sopenharmony_ci .ndo_get_vf_guid = ipoib_get_vf_guid, 208162306a36Sopenharmony_ci .ndo_set_vf_guid = ipoib_set_vf_guid, 208262306a36Sopenharmony_ci .ndo_set_mac_address = ipoib_set_mac, 208362306a36Sopenharmony_ci .ndo_get_stats64 = ipoib_get_stats, 208462306a36Sopenharmony_ci .ndo_eth_ioctl = ipoib_ioctl, 208562306a36Sopenharmony_ci}; 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_cistatic const struct net_device_ops ipoib_netdev_ops_vf = { 208862306a36Sopenharmony_ci .ndo_init = ipoib_ndo_init, 208962306a36Sopenharmony_ci .ndo_uninit = ipoib_ndo_uninit, 209062306a36Sopenharmony_ci .ndo_open = ipoib_open, 209162306a36Sopenharmony_ci .ndo_stop = ipoib_stop, 209262306a36Sopenharmony_ci .ndo_change_mtu = ipoib_change_mtu, 209362306a36Sopenharmony_ci .ndo_fix_features = ipoib_fix_features, 209462306a36Sopenharmony_ci .ndo_start_xmit = ipoib_start_xmit, 209562306a36Sopenharmony_ci .ndo_tx_timeout = ipoib_timeout, 209662306a36Sopenharmony_ci .ndo_set_rx_mode = ipoib_set_mcast_list, 209762306a36Sopenharmony_ci .ndo_get_iflink = ipoib_get_iflink, 209862306a36Sopenharmony_ci .ndo_get_stats64 = ipoib_get_stats, 209962306a36Sopenharmony_ci .ndo_eth_ioctl = ipoib_ioctl, 210062306a36Sopenharmony_ci}; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_cistatic const struct net_device_ops ipoib_netdev_default_pf = { 210362306a36Sopenharmony_ci .ndo_init = ipoib_dev_init_default, 210462306a36Sopenharmony_ci .ndo_uninit = ipoib_dev_uninit_default, 210562306a36Sopenharmony_ci .ndo_open = ipoib_ib_dev_open_default, 210662306a36Sopenharmony_ci .ndo_stop = ipoib_ib_dev_stop_default, 210762306a36Sopenharmony_ci}; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_civoid ipoib_setup_common(struct net_device *dev) 211062306a36Sopenharmony_ci{ 211162306a36Sopenharmony_ci dev->header_ops = &ipoib_header_ops; 211262306a36Sopenharmony_ci dev->netdev_ops = &ipoib_netdev_default_pf; 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci ipoib_set_ethtool_ops(dev); 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci dev->watchdog_timeo = HZ; 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci dev->flags |= IFF_BROADCAST | IFF_MULTICAST; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci dev->hard_header_len = IPOIB_HARD_LEN; 212162306a36Sopenharmony_ci dev->addr_len = INFINIBAND_ALEN; 212262306a36Sopenharmony_ci dev->type = ARPHRD_INFINIBAND; 212362306a36Sopenharmony_ci dev->tx_queue_len = ipoib_sendq_size * 2; 212462306a36Sopenharmony_ci dev->features = (NETIF_F_VLAN_CHALLENGED | 212562306a36Sopenharmony_ci NETIF_F_HIGHDMA); 212662306a36Sopenharmony_ci netif_keep_dst(dev); 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN); 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci /* 213162306a36Sopenharmony_ci * unregister_netdev always frees the netdev, we use this mode 213262306a36Sopenharmony_ci * consistently to unify all the various unregister paths, including 213362306a36Sopenharmony_ci * those connected to rtnl_link_ops which require it. 213462306a36Sopenharmony_ci */ 213562306a36Sopenharmony_ci dev->needs_free_netdev = true; 213662306a36Sopenharmony_ci} 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_cistatic void ipoib_build_priv(struct net_device *dev) 213962306a36Sopenharmony_ci{ 214062306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci priv->dev = dev; 214362306a36Sopenharmony_ci spin_lock_init(&priv->lock); 214462306a36Sopenharmony_ci init_rwsem(&priv->vlan_rwsem); 214562306a36Sopenharmony_ci mutex_init(&priv->mcast_mutex); 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->path_list); 214862306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->child_intfs); 214962306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->dead_ahs); 215062306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->multicast_list); 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task); 215362306a36Sopenharmony_ci INIT_WORK(&priv->carrier_on_task, ipoib_mcast_carrier_on_task); 215462306a36Sopenharmony_ci INIT_WORK(&priv->flush_light, ipoib_ib_dev_flush_light); 215562306a36Sopenharmony_ci INIT_WORK(&priv->flush_normal, ipoib_ib_dev_flush_normal); 215662306a36Sopenharmony_ci INIT_WORK(&priv->flush_heavy, ipoib_ib_dev_flush_heavy); 215762306a36Sopenharmony_ci INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task); 215862306a36Sopenharmony_ci INIT_DELAYED_WORK(&priv->ah_reap_task, ipoib_reap_ah); 215962306a36Sopenharmony_ci INIT_DELAYED_WORK(&priv->neigh_reap_task, ipoib_reap_neigh); 216062306a36Sopenharmony_ci} 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_cistatic struct net_device *ipoib_alloc_netdev(struct ib_device *hca, u32 port, 216362306a36Sopenharmony_ci const char *name) 216462306a36Sopenharmony_ci{ 216562306a36Sopenharmony_ci struct net_device *dev; 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci dev = rdma_alloc_netdev(hca, port, RDMA_NETDEV_IPOIB, name, 216862306a36Sopenharmony_ci NET_NAME_UNKNOWN, ipoib_setup_common); 216962306a36Sopenharmony_ci if (!IS_ERR(dev) || PTR_ERR(dev) != -EOPNOTSUPP) 217062306a36Sopenharmony_ci return dev; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci dev = alloc_netdev(sizeof(struct rdma_netdev), name, NET_NAME_UNKNOWN, 217362306a36Sopenharmony_ci ipoib_setup_common); 217462306a36Sopenharmony_ci if (!dev) 217562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 217662306a36Sopenharmony_ci return dev; 217762306a36Sopenharmony_ci} 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ciint ipoib_intf_init(struct ib_device *hca, u32 port, const char *name, 218062306a36Sopenharmony_ci struct net_device *dev) 218162306a36Sopenharmony_ci{ 218262306a36Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 218362306a36Sopenharmony_ci struct ipoib_dev_priv *priv; 218462306a36Sopenharmony_ci int rc; 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci priv = kzalloc(sizeof(*priv), GFP_KERNEL); 218762306a36Sopenharmony_ci if (!priv) 218862306a36Sopenharmony_ci return -ENOMEM; 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci priv->ca = hca; 219162306a36Sopenharmony_ci priv->port = port; 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci rc = rdma_init_netdev(hca, port, RDMA_NETDEV_IPOIB, name, 219462306a36Sopenharmony_ci NET_NAME_UNKNOWN, ipoib_setup_common, dev); 219562306a36Sopenharmony_ci if (rc) { 219662306a36Sopenharmony_ci if (rc != -EOPNOTSUPP) 219762306a36Sopenharmony_ci goto out; 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci rn->send = ipoib_send; 220062306a36Sopenharmony_ci rn->attach_mcast = ipoib_mcast_attach; 220162306a36Sopenharmony_ci rn->detach_mcast = ipoib_mcast_detach; 220262306a36Sopenharmony_ci rn->hca = hca; 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci rc = netif_set_real_num_tx_queues(dev, 1); 220562306a36Sopenharmony_ci if (rc) 220662306a36Sopenharmony_ci goto out; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci rc = netif_set_real_num_rx_queues(dev, 1); 220962306a36Sopenharmony_ci if (rc) 221062306a36Sopenharmony_ci goto out; 221162306a36Sopenharmony_ci } 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci priv->rn_ops = dev->netdev_ops; 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci if (hca->attrs.kernel_cap_flags & IBK_VIRTUAL_FUNCTION) 221662306a36Sopenharmony_ci dev->netdev_ops = &ipoib_netdev_ops_vf; 221762306a36Sopenharmony_ci else 221862306a36Sopenharmony_ci dev->netdev_ops = &ipoib_netdev_ops_pf; 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci rn->clnt_priv = priv; 222162306a36Sopenharmony_ci /* 222262306a36Sopenharmony_ci * Only the child register_netdev flows can handle priv_destructor 222362306a36Sopenharmony_ci * being set, so we force it to NULL here and handle manually until it 222462306a36Sopenharmony_ci * is safe to turn on. 222562306a36Sopenharmony_ci */ 222662306a36Sopenharmony_ci priv->next_priv_destructor = dev->priv_destructor; 222762306a36Sopenharmony_ci dev->priv_destructor = NULL; 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci ipoib_build_priv(dev); 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci return 0; 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ciout: 223462306a36Sopenharmony_ci kfree(priv); 223562306a36Sopenharmony_ci return rc; 223662306a36Sopenharmony_ci} 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_cistruct net_device *ipoib_intf_alloc(struct ib_device *hca, u32 port, 223962306a36Sopenharmony_ci const char *name) 224062306a36Sopenharmony_ci{ 224162306a36Sopenharmony_ci struct net_device *dev; 224262306a36Sopenharmony_ci int rc; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci dev = ipoib_alloc_netdev(hca, port, name); 224562306a36Sopenharmony_ci if (IS_ERR(dev)) 224662306a36Sopenharmony_ci return dev; 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ci rc = ipoib_intf_init(hca, port, name, dev); 224962306a36Sopenharmony_ci if (rc) { 225062306a36Sopenharmony_ci free_netdev(dev); 225162306a36Sopenharmony_ci return ERR_PTR(rc); 225262306a36Sopenharmony_ci } 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci /* 225562306a36Sopenharmony_ci * Upon success the caller must ensure ipoib_intf_free is called or 225662306a36Sopenharmony_ci * register_netdevice succeed'd and priv_destructor is set to 225762306a36Sopenharmony_ci * ipoib_intf_free. 225862306a36Sopenharmony_ci */ 225962306a36Sopenharmony_ci return dev; 226062306a36Sopenharmony_ci} 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_civoid ipoib_intf_free(struct net_device *dev) 226362306a36Sopenharmony_ci{ 226462306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 226562306a36Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci dev->priv_destructor = priv->next_priv_destructor; 226862306a36Sopenharmony_ci if (dev->priv_destructor) 226962306a36Sopenharmony_ci dev->priv_destructor(dev); 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci /* 227262306a36Sopenharmony_ci * There are some error flows around register_netdev failing that may 227362306a36Sopenharmony_ci * attempt to call priv_destructor twice, prevent that from happening. 227462306a36Sopenharmony_ci */ 227562306a36Sopenharmony_ci dev->priv_destructor = NULL; 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci /* unregister/destroy is very complicated. Make bugs more obvious. */ 227862306a36Sopenharmony_ci rn->clnt_priv = NULL; 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci kfree(priv); 228162306a36Sopenharmony_ci} 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_cistatic ssize_t pkey_show(struct device *dev, struct device_attribute *attr, 228462306a36Sopenharmony_ci char *buf) 228562306a36Sopenharmony_ci{ 228662306a36Sopenharmony_ci struct net_device *ndev = to_net_dev(dev); 228762306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci return sysfs_emit(buf, "0x%04x\n", priv->pkey); 229062306a36Sopenharmony_ci} 229162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(pkey); 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_cistatic ssize_t umcast_show(struct device *dev, struct device_attribute *attr, 229462306a36Sopenharmony_ci char *buf) 229562306a36Sopenharmony_ci{ 229662306a36Sopenharmony_ci struct net_device *ndev = to_net_dev(dev); 229762306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", 230062306a36Sopenharmony_ci test_bit(IPOIB_FLAG_UMCAST, &priv->flags)); 230162306a36Sopenharmony_ci} 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_civoid ipoib_set_umcast(struct net_device *ndev, int umcast_val) 230462306a36Sopenharmony_ci{ 230562306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(ndev); 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci if (umcast_val > 0) { 230862306a36Sopenharmony_ci set_bit(IPOIB_FLAG_UMCAST, &priv->flags); 230962306a36Sopenharmony_ci ipoib_warn(priv, "ignoring multicast groups joined directly " 231062306a36Sopenharmony_ci "by userspace\n"); 231162306a36Sopenharmony_ci } else 231262306a36Sopenharmony_ci clear_bit(IPOIB_FLAG_UMCAST, &priv->flags); 231362306a36Sopenharmony_ci} 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_cistatic ssize_t umcast_store(struct device *dev, struct device_attribute *attr, 231662306a36Sopenharmony_ci const char *buf, size_t count) 231762306a36Sopenharmony_ci{ 231862306a36Sopenharmony_ci unsigned long umcast_val = simple_strtoul(buf, NULL, 0); 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci ipoib_set_umcast(to_net_dev(dev), umcast_val); 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci return count; 232362306a36Sopenharmony_ci} 232462306a36Sopenharmony_cistatic DEVICE_ATTR_RW(umcast); 232562306a36Sopenharmony_ci 232662306a36Sopenharmony_ciint ipoib_add_umcast_attr(struct net_device *dev) 232762306a36Sopenharmony_ci{ 232862306a36Sopenharmony_ci return device_create_file(&dev->dev, &dev_attr_umcast); 232962306a36Sopenharmony_ci} 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_cistatic void set_base_guid(struct ipoib_dev_priv *priv, union ib_gid *gid) 233262306a36Sopenharmony_ci{ 233362306a36Sopenharmony_ci struct ipoib_dev_priv *child_priv; 233462306a36Sopenharmony_ci struct net_device *netdev = priv->dev; 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci netif_addr_lock_bh(netdev); 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_ci memcpy(&priv->local_gid.global.interface_id, 233962306a36Sopenharmony_ci &gid->global.interface_id, 234062306a36Sopenharmony_ci sizeof(gid->global.interface_id)); 234162306a36Sopenharmony_ci dev_addr_mod(netdev, 4, (u8 *)&priv->local_gid, sizeof(priv->local_gid)); 234262306a36Sopenharmony_ci clear_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags); 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci netif_addr_unlock_bh(netdev); 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { 234762306a36Sopenharmony_ci down_read(&priv->vlan_rwsem); 234862306a36Sopenharmony_ci list_for_each_entry(child_priv, &priv->child_intfs, list) 234962306a36Sopenharmony_ci set_base_guid(child_priv, gid); 235062306a36Sopenharmony_ci up_read(&priv->vlan_rwsem); 235162306a36Sopenharmony_ci } 235262306a36Sopenharmony_ci} 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_cistatic int ipoib_check_lladdr(struct net_device *dev, 235562306a36Sopenharmony_ci struct sockaddr_storage *ss) 235662306a36Sopenharmony_ci{ 235762306a36Sopenharmony_ci union ib_gid *gid = (union ib_gid *)(ss->__data + 4); 235862306a36Sopenharmony_ci int ret = 0; 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci netif_addr_lock_bh(dev); 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci /* Make sure the QPN, reserved and subnet prefix match the current 236362306a36Sopenharmony_ci * lladdr, it also makes sure the lladdr is unicast. 236462306a36Sopenharmony_ci */ 236562306a36Sopenharmony_ci if (memcmp(dev->dev_addr, ss->__data, 236662306a36Sopenharmony_ci 4 + sizeof(gid->global.subnet_prefix)) || 236762306a36Sopenharmony_ci gid->global.interface_id == 0) 236862306a36Sopenharmony_ci ret = -EINVAL; 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci netif_addr_unlock_bh(dev); 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci return ret; 237362306a36Sopenharmony_ci} 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_cistatic int ipoib_set_mac(struct net_device *dev, void *addr) 237662306a36Sopenharmony_ci{ 237762306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 237862306a36Sopenharmony_ci struct sockaddr_storage *ss = addr; 237962306a36Sopenharmony_ci int ret; 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev)) 238262306a36Sopenharmony_ci return -EBUSY; 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci ret = ipoib_check_lladdr(dev, ss); 238562306a36Sopenharmony_ci if (ret) 238662306a36Sopenharmony_ci return ret; 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci set_base_guid(priv, (union ib_gid *)(ss->__data + 4)); 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci queue_work(ipoib_workqueue, &priv->flush_light); 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci return 0; 239362306a36Sopenharmony_ci} 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_cistatic ssize_t create_child_store(struct device *dev, 239662306a36Sopenharmony_ci struct device_attribute *attr, 239762306a36Sopenharmony_ci const char *buf, size_t count) 239862306a36Sopenharmony_ci{ 239962306a36Sopenharmony_ci int pkey; 240062306a36Sopenharmony_ci int ret; 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci if (sscanf(buf, "%i", &pkey) != 1) 240362306a36Sopenharmony_ci return -EINVAL; 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci if (pkey <= 0 || pkey > 0xffff || pkey == 0x8000) 240662306a36Sopenharmony_ci return -EINVAL; 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci ret = ipoib_vlan_add(to_net_dev(dev), pkey); 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci return ret ? ret : count; 241162306a36Sopenharmony_ci} 241262306a36Sopenharmony_cistatic DEVICE_ATTR_WO(create_child); 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_cistatic ssize_t delete_child_store(struct device *dev, 241562306a36Sopenharmony_ci struct device_attribute *attr, 241662306a36Sopenharmony_ci const char *buf, size_t count) 241762306a36Sopenharmony_ci{ 241862306a36Sopenharmony_ci int pkey; 241962306a36Sopenharmony_ci int ret; 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_ci if (sscanf(buf, "%i", &pkey) != 1) 242262306a36Sopenharmony_ci return -EINVAL; 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci if (pkey < 0 || pkey > 0xffff) 242562306a36Sopenharmony_ci return -EINVAL; 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci ret = ipoib_vlan_delete(to_net_dev(dev), pkey); 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci return ret ? ret : count; 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci} 243262306a36Sopenharmony_cistatic DEVICE_ATTR_WO(delete_child); 243362306a36Sopenharmony_ci 243462306a36Sopenharmony_ciint ipoib_add_pkey_attr(struct net_device *dev) 243562306a36Sopenharmony_ci{ 243662306a36Sopenharmony_ci return device_create_file(&dev->dev, &dev_attr_pkey); 243762306a36Sopenharmony_ci} 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci/* 244062306a36Sopenharmony_ci * We erroneously exposed the iface's port number in the dev_id 244162306a36Sopenharmony_ci * sysfs field long after dev_port was introduced for that purpose[1], 244262306a36Sopenharmony_ci * and we need to stop everyone from relying on that. 244362306a36Sopenharmony_ci * Let's overload the shower routine for the dev_id file here 244462306a36Sopenharmony_ci * to gently bring the issue up. 244562306a36Sopenharmony_ci * 244662306a36Sopenharmony_ci * [1] https://www.spinics.net/lists/netdev/msg272123.html 244762306a36Sopenharmony_ci */ 244862306a36Sopenharmony_cistatic ssize_t dev_id_show(struct device *dev, 244962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 245062306a36Sopenharmony_ci{ 245162306a36Sopenharmony_ci struct net_device *ndev = to_net_dev(dev); 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci /* 245462306a36Sopenharmony_ci * ndev->dev_port will be equal to 0 in old kernel prior to commit 245562306a36Sopenharmony_ci * 9b8b2a323008 ("IB/ipoib: Use dev_port to expose network interface 245662306a36Sopenharmony_ci * port numbers") Zero was chosen as special case for user space 245762306a36Sopenharmony_ci * applications to fallback and query dev_id to check if it has 245862306a36Sopenharmony_ci * different value or not. 245962306a36Sopenharmony_ci * 246062306a36Sopenharmony_ci * Don't print warning in such scenario. 246162306a36Sopenharmony_ci * 246262306a36Sopenharmony_ci * https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-net_id.c#L358 246362306a36Sopenharmony_ci */ 246462306a36Sopenharmony_ci if (ndev->dev_port && ndev->dev_id == ndev->dev_port) 246562306a36Sopenharmony_ci netdev_info_once(ndev, 246662306a36Sopenharmony_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", 246762306a36Sopenharmony_ci current->comm); 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci return sysfs_emit(buf, "%#x\n", ndev->dev_id); 247062306a36Sopenharmony_ci} 247162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(dev_id); 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_cistatic int ipoib_intercept_dev_id_attr(struct net_device *dev) 247462306a36Sopenharmony_ci{ 247562306a36Sopenharmony_ci device_remove_file(&dev->dev, &dev_attr_dev_id); 247662306a36Sopenharmony_ci return device_create_file(&dev->dev, &dev_attr_dev_id); 247762306a36Sopenharmony_ci} 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_cistatic struct net_device *ipoib_add_port(const char *format, 248062306a36Sopenharmony_ci struct ib_device *hca, u32 port) 248162306a36Sopenharmony_ci{ 248262306a36Sopenharmony_ci struct rtnl_link_ops *ops = ipoib_get_link_ops(); 248362306a36Sopenharmony_ci struct rdma_netdev_alloc_params params; 248462306a36Sopenharmony_ci struct ipoib_dev_priv *priv; 248562306a36Sopenharmony_ci struct net_device *ndev; 248662306a36Sopenharmony_ci int result; 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_ci ndev = ipoib_intf_alloc(hca, port, format); 248962306a36Sopenharmony_ci if (IS_ERR(ndev)) { 249062306a36Sopenharmony_ci pr_warn("%s, %d: ipoib_intf_alloc failed %ld\n", hca->name, port, 249162306a36Sopenharmony_ci PTR_ERR(ndev)); 249262306a36Sopenharmony_ci return ndev; 249362306a36Sopenharmony_ci } 249462306a36Sopenharmony_ci priv = ipoib_priv(ndev); 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci INIT_IB_EVENT_HANDLER(&priv->event_handler, 249762306a36Sopenharmony_ci priv->ca, ipoib_event); 249862306a36Sopenharmony_ci ib_register_event_handler(&priv->event_handler); 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci /* call event handler to ensure pkey in sync */ 250162306a36Sopenharmony_ci queue_work(ipoib_workqueue, &priv->flush_heavy); 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci ndev->rtnl_link_ops = ipoib_get_link_ops(); 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci result = register_netdev(ndev); 250662306a36Sopenharmony_ci if (result) { 250762306a36Sopenharmony_ci pr_warn("%s: couldn't register ipoib port %d; error %d\n", 250862306a36Sopenharmony_ci hca->name, port, result); 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci ipoib_parent_unregister_pre(ndev); 251162306a36Sopenharmony_ci ipoib_intf_free(ndev); 251262306a36Sopenharmony_ci free_netdev(ndev); 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci return ERR_PTR(result); 251562306a36Sopenharmony_ci } 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci if (hca->ops.rdma_netdev_get_params) { 251862306a36Sopenharmony_ci int rc = hca->ops.rdma_netdev_get_params(hca, port, 251962306a36Sopenharmony_ci RDMA_NETDEV_IPOIB, 252062306a36Sopenharmony_ci ¶ms); 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci if (!rc && ops->priv_size < params.sizeof_priv) 252362306a36Sopenharmony_ci ops->priv_size = params.sizeof_priv; 252462306a36Sopenharmony_ci } 252562306a36Sopenharmony_ci /* 252662306a36Sopenharmony_ci * We cannot set priv_destructor before register_netdev because we 252762306a36Sopenharmony_ci * need priv to be always valid during the error flow to execute 252862306a36Sopenharmony_ci * ipoib_parent_unregister_pre(). Instead handle it manually and only 252962306a36Sopenharmony_ci * enter priv_destructor mode once we are completely registered. 253062306a36Sopenharmony_ci */ 253162306a36Sopenharmony_ci ndev->priv_destructor = ipoib_intf_free; 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ci if (ipoib_intercept_dev_id_attr(ndev)) 253462306a36Sopenharmony_ci goto sysfs_failed; 253562306a36Sopenharmony_ci if (ipoib_cm_add_mode_attr(ndev)) 253662306a36Sopenharmony_ci goto sysfs_failed; 253762306a36Sopenharmony_ci if (ipoib_add_pkey_attr(ndev)) 253862306a36Sopenharmony_ci goto sysfs_failed; 253962306a36Sopenharmony_ci if (ipoib_add_umcast_attr(ndev)) 254062306a36Sopenharmony_ci goto sysfs_failed; 254162306a36Sopenharmony_ci if (device_create_file(&ndev->dev, &dev_attr_create_child)) 254262306a36Sopenharmony_ci goto sysfs_failed; 254362306a36Sopenharmony_ci if (device_create_file(&ndev->dev, &dev_attr_delete_child)) 254462306a36Sopenharmony_ci goto sysfs_failed; 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci return ndev; 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_cisysfs_failed: 254962306a36Sopenharmony_ci ipoib_parent_unregister_pre(ndev); 255062306a36Sopenharmony_ci unregister_netdev(ndev); 255162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 255262306a36Sopenharmony_ci} 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_cistatic int ipoib_add_one(struct ib_device *device) 255562306a36Sopenharmony_ci{ 255662306a36Sopenharmony_ci struct list_head *dev_list; 255762306a36Sopenharmony_ci struct net_device *dev; 255862306a36Sopenharmony_ci struct ipoib_dev_priv *priv; 255962306a36Sopenharmony_ci unsigned int p; 256062306a36Sopenharmony_ci int count = 0; 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci dev_list = kmalloc(sizeof(*dev_list), GFP_KERNEL); 256362306a36Sopenharmony_ci if (!dev_list) 256462306a36Sopenharmony_ci return -ENOMEM; 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci INIT_LIST_HEAD(dev_list); 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci rdma_for_each_port (device, p) { 256962306a36Sopenharmony_ci if (!rdma_protocol_ib(device, p)) 257062306a36Sopenharmony_ci continue; 257162306a36Sopenharmony_ci dev = ipoib_add_port("ib%d", device, p); 257262306a36Sopenharmony_ci if (!IS_ERR(dev)) { 257362306a36Sopenharmony_ci priv = ipoib_priv(dev); 257462306a36Sopenharmony_ci list_add_tail(&priv->list, dev_list); 257562306a36Sopenharmony_ci count++; 257662306a36Sopenharmony_ci } 257762306a36Sopenharmony_ci } 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci if (!count) { 258062306a36Sopenharmony_ci kfree(dev_list); 258162306a36Sopenharmony_ci return -EOPNOTSUPP; 258262306a36Sopenharmony_ci } 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci ib_set_client_data(device, &ipoib_client, dev_list); 258562306a36Sopenharmony_ci return 0; 258662306a36Sopenharmony_ci} 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_cistatic void ipoib_remove_one(struct ib_device *device, void *client_data) 258962306a36Sopenharmony_ci{ 259062306a36Sopenharmony_ci struct ipoib_dev_priv *priv, *tmp, *cpriv, *tcpriv; 259162306a36Sopenharmony_ci struct list_head *dev_list = client_data; 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci list_for_each_entry_safe(priv, tmp, dev_list, list) { 259462306a36Sopenharmony_ci LIST_HEAD(head); 259562306a36Sopenharmony_ci ipoib_parent_unregister_pre(priv->dev); 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci rtnl_lock(); 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci list_for_each_entry_safe(cpriv, tcpriv, &priv->child_intfs, 260062306a36Sopenharmony_ci list) 260162306a36Sopenharmony_ci unregister_netdevice_queue(cpriv->dev, &head); 260262306a36Sopenharmony_ci unregister_netdevice_queue(priv->dev, &head); 260362306a36Sopenharmony_ci unregister_netdevice_many(&head); 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci rtnl_unlock(); 260662306a36Sopenharmony_ci } 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_ci kfree(dev_list); 260962306a36Sopenharmony_ci} 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 261262306a36Sopenharmony_cistatic struct notifier_block ipoib_netdev_notifier = { 261362306a36Sopenharmony_ci .notifier_call = ipoib_netdev_event, 261462306a36Sopenharmony_ci}; 261562306a36Sopenharmony_ci#endif 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_cistatic int __init ipoib_init_module(void) 261862306a36Sopenharmony_ci{ 261962306a36Sopenharmony_ci int ret; 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci ipoib_recvq_size = roundup_pow_of_two(ipoib_recvq_size); 262262306a36Sopenharmony_ci ipoib_recvq_size = min(ipoib_recvq_size, IPOIB_MAX_QUEUE_SIZE); 262362306a36Sopenharmony_ci ipoib_recvq_size = max(ipoib_recvq_size, IPOIB_MIN_QUEUE_SIZE); 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_ci ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size); 262662306a36Sopenharmony_ci ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE); 262762306a36Sopenharmony_ci ipoib_sendq_size = max3(ipoib_sendq_size, 2 * MAX_SEND_CQE, IPOIB_MIN_QUEUE_SIZE); 262862306a36Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_CM 262962306a36Sopenharmony_ci ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP); 263062306a36Sopenharmony_ci ipoib_max_conn_qp = max(ipoib_max_conn_qp, 0); 263162306a36Sopenharmony_ci#endif 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_ci /* 263462306a36Sopenharmony_ci * When copying small received packets, we only copy from the 263562306a36Sopenharmony_ci * linear data part of the SKB, so we rely on this condition. 263662306a36Sopenharmony_ci */ 263762306a36Sopenharmony_ci BUILD_BUG_ON(IPOIB_CM_COPYBREAK > IPOIB_CM_HEAD_SIZE); 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci ipoib_register_debugfs(); 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci /* 264262306a36Sopenharmony_ci * We create a global workqueue here that is used for all flush 264362306a36Sopenharmony_ci * operations. However, if you attempt to flush a workqueue 264462306a36Sopenharmony_ci * from a task on that same workqueue, it deadlocks the system. 264562306a36Sopenharmony_ci * We want to be able to flush the tasks associated with a 264662306a36Sopenharmony_ci * specific net device, so we also create a workqueue for each 264762306a36Sopenharmony_ci * netdevice. We queue up the tasks for that device only on 264862306a36Sopenharmony_ci * its private workqueue, and we only queue up flush events 264962306a36Sopenharmony_ci * on our global flush workqueue. This avoids the deadlocks. 265062306a36Sopenharmony_ci */ 265162306a36Sopenharmony_ci ipoib_workqueue = alloc_ordered_workqueue("ipoib_flush", 0); 265262306a36Sopenharmony_ci if (!ipoib_workqueue) { 265362306a36Sopenharmony_ci ret = -ENOMEM; 265462306a36Sopenharmony_ci goto err_fs; 265562306a36Sopenharmony_ci } 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ci ib_sa_register_client(&ipoib_sa_client); 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_ci ret = ib_register_client(&ipoib_client); 266062306a36Sopenharmony_ci if (ret) 266162306a36Sopenharmony_ci goto err_sa; 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci ret = ipoib_netlink_init(); 266462306a36Sopenharmony_ci if (ret) 266562306a36Sopenharmony_ci goto err_client; 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 266862306a36Sopenharmony_ci register_netdevice_notifier(&ipoib_netdev_notifier); 266962306a36Sopenharmony_ci#endif 267062306a36Sopenharmony_ci return 0; 267162306a36Sopenharmony_ci 267262306a36Sopenharmony_cierr_client: 267362306a36Sopenharmony_ci ib_unregister_client(&ipoib_client); 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_cierr_sa: 267662306a36Sopenharmony_ci ib_sa_unregister_client(&ipoib_sa_client); 267762306a36Sopenharmony_ci destroy_workqueue(ipoib_workqueue); 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_cierr_fs: 268062306a36Sopenharmony_ci ipoib_unregister_debugfs(); 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci return ret; 268362306a36Sopenharmony_ci} 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_cistatic void __exit ipoib_cleanup_module(void) 268662306a36Sopenharmony_ci{ 268762306a36Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 268862306a36Sopenharmony_ci unregister_netdevice_notifier(&ipoib_netdev_notifier); 268962306a36Sopenharmony_ci#endif 269062306a36Sopenharmony_ci ipoib_netlink_fini(); 269162306a36Sopenharmony_ci ib_unregister_client(&ipoib_client); 269262306a36Sopenharmony_ci ib_sa_unregister_client(&ipoib_sa_client); 269362306a36Sopenharmony_ci ipoib_unregister_debugfs(); 269462306a36Sopenharmony_ci destroy_workqueue(ipoib_workqueue); 269562306a36Sopenharmony_ci} 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_cimodule_init(ipoib_init_module); 269862306a36Sopenharmony_cimodule_exit(ipoib_cleanup_module); 2699