162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2004 Topspin Communications.  All rights reserved.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This software is available to you under a choice of one of two
562306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
862306a36Sopenharmony_ci * OpenIB.org BSD license below:
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1162306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1262306a36Sopenharmony_ci *     conditions are met:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1562306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1662306a36Sopenharmony_ci *        disclaimer.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
1962306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2062306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2162306a36Sopenharmony_ci *        provided with the distribution.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3062306a36Sopenharmony_ci * SOFTWARE.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <linux/sched/signal.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include <linux/init.h>
3662306a36Sopenharmony_ci#include <linux/seq_file.h>
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include <linux/uaccess.h>
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#include "ipoib.h"
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic ssize_t parent_show(struct device *d, struct device_attribute *attr,
4362306a36Sopenharmony_ci			   char *buf)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	struct net_device *dev = to_net_dev(d);
4662306a36Sopenharmony_ci	struct ipoib_dev_priv *priv = ipoib_priv(dev);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", priv->parent->name);
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(parent);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic bool is_child_unique(struct ipoib_dev_priv *ppriv,
5362306a36Sopenharmony_ci			    struct ipoib_dev_priv *priv)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct ipoib_dev_priv *tpriv;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	ASSERT_RTNL();
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/*
6062306a36Sopenharmony_ci	 * Since the legacy sysfs interface uses pkey for deletion it cannot
6162306a36Sopenharmony_ci	 * support more than one interface with the same pkey, it creates
6262306a36Sopenharmony_ci	 * ambiguity.  The RTNL interface deletes using the netdev so it does
6362306a36Sopenharmony_ci	 * not have a problem to support duplicated pkeys.
6462306a36Sopenharmony_ci	 */
6562306a36Sopenharmony_ci	if (priv->child_type != IPOIB_LEGACY_CHILD)
6662306a36Sopenharmony_ci		return true;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/*
6962306a36Sopenharmony_ci	 * First ensure this isn't a duplicate. We check the parent device and
7062306a36Sopenharmony_ci	 * then all of the legacy child interfaces to make sure the Pkey
7162306a36Sopenharmony_ci	 * doesn't match.
7262306a36Sopenharmony_ci	 */
7362306a36Sopenharmony_ci	if (ppriv->pkey == priv->pkey)
7462306a36Sopenharmony_ci		return false;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	list_for_each_entry(tpriv, &ppriv->child_intfs, list) {
7762306a36Sopenharmony_ci		if (tpriv->pkey == priv->pkey &&
7862306a36Sopenharmony_ci		    tpriv->child_type == IPOIB_LEGACY_CHILD)
7962306a36Sopenharmony_ci			return false;
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return true;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/*
8662306a36Sopenharmony_ci * NOTE: If this function fails then the priv->dev will remain valid, however
8762306a36Sopenharmony_ci * priv will have been freed and must not be touched by caller in the error
8862306a36Sopenharmony_ci * case.
8962306a36Sopenharmony_ci *
9062306a36Sopenharmony_ci * If (ndev->reg_state == NETREG_UNINITIALIZED) then it is up to the caller to
9162306a36Sopenharmony_ci * free the net_device (just as rtnl_newlink does) otherwise the net_device
9262306a36Sopenharmony_ci * will be freed when the rtnl is unlocked.
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_ciint __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv,
9562306a36Sopenharmony_ci		     u16 pkey, int type)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	struct net_device *ndev = priv->dev;
9862306a36Sopenharmony_ci	int result;
9962306a36Sopenharmony_ci	struct rdma_netdev *rn = netdev_priv(ndev);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	ASSERT_RTNL();
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	/*
10462306a36Sopenharmony_ci	 * We do not need to touch priv if register_netdevice fails, so just
10562306a36Sopenharmony_ci	 * always use this flow.
10662306a36Sopenharmony_ci	 */
10762306a36Sopenharmony_ci	ndev->priv_destructor = ipoib_intf_free;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/*
11062306a36Sopenharmony_ci	 * Racing with unregister of the parent must be prevented by the
11162306a36Sopenharmony_ci	 * caller.
11262306a36Sopenharmony_ci	 */
11362306a36Sopenharmony_ci	WARN_ON(ppriv->dev->reg_state != NETREG_REGISTERED);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (pkey == 0 || pkey == 0x8000) {
11662306a36Sopenharmony_ci		result = -EINVAL;
11762306a36Sopenharmony_ci		goto out_early;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	rn->mtu = priv->mcast_mtu;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	priv->parent = ppriv->dev;
12362306a36Sopenharmony_ci	priv->pkey = pkey;
12462306a36Sopenharmony_ci	priv->child_type = type;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (!is_child_unique(ppriv, priv)) {
12762306a36Sopenharmony_ci		result = -ENOTUNIQ;
12862306a36Sopenharmony_ci		goto out_early;
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	result = register_netdevice(ndev);
13262306a36Sopenharmony_ci	if (result) {
13362306a36Sopenharmony_ci		ipoib_warn(priv, "failed to initialize; error %i", result);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci		/*
13662306a36Sopenharmony_ci		 * register_netdevice sometimes calls priv_destructor,
13762306a36Sopenharmony_ci		 * sometimes not. Make sure it was done.
13862306a36Sopenharmony_ci		 */
13962306a36Sopenharmony_ci		goto out_early;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* RTNL childs don't need proprietary sysfs entries */
14362306a36Sopenharmony_ci	if (type == IPOIB_LEGACY_CHILD) {
14462306a36Sopenharmony_ci		if (ipoib_cm_add_mode_attr(ndev))
14562306a36Sopenharmony_ci			goto sysfs_failed;
14662306a36Sopenharmony_ci		if (ipoib_add_pkey_attr(ndev))
14762306a36Sopenharmony_ci			goto sysfs_failed;
14862306a36Sopenharmony_ci		if (ipoib_add_umcast_attr(ndev))
14962306a36Sopenharmony_ci			goto sysfs_failed;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		if (device_create_file(&ndev->dev, &dev_attr_parent))
15262306a36Sopenharmony_ci			goto sysfs_failed;
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	return 0;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cisysfs_failed:
15862306a36Sopenharmony_ci	unregister_netdevice(priv->dev);
15962306a36Sopenharmony_ci	return -ENOMEM;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ciout_early:
16262306a36Sopenharmony_ci	if (ndev->priv_destructor)
16362306a36Sopenharmony_ci		ndev->priv_destructor(ndev);
16462306a36Sopenharmony_ci	return result;
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ciint ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct ipoib_dev_priv *ppriv, *priv;
17062306a36Sopenharmony_ci	char intf_name[IFNAMSIZ];
17162306a36Sopenharmony_ci	struct net_device *ndev;
17262306a36Sopenharmony_ci	int result;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	if (!capable(CAP_NET_ADMIN))
17562306a36Sopenharmony_ci		return -EPERM;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	if (!rtnl_trylock())
17862306a36Sopenharmony_ci		return restart_syscall();
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	if (pdev->reg_state != NETREG_REGISTERED) {
18162306a36Sopenharmony_ci		rtnl_unlock();
18262306a36Sopenharmony_ci		return -EPERM;
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	ppriv = ipoib_priv(pdev);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	snprintf(intf_name, sizeof(intf_name), "%s.%04x",
18862306a36Sopenharmony_ci		 ppriv->dev->name, pkey);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	ndev = ipoib_intf_alloc(ppriv->ca, ppriv->port, intf_name);
19162306a36Sopenharmony_ci	if (IS_ERR(ndev)) {
19262306a36Sopenharmony_ci		result = PTR_ERR(ndev);
19362306a36Sopenharmony_ci		goto out;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci	priv = ipoib_priv(ndev);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	ndev->rtnl_link_ops = ipoib_get_link_ops();
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	result = __ipoib_vlan_add(ppriv, priv, pkey, IPOIB_LEGACY_CHILD);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (result && ndev->reg_state == NETREG_UNINITIALIZED)
20262306a36Sopenharmony_ci		free_netdev(ndev);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ciout:
20562306a36Sopenharmony_ci	rtnl_unlock();
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	return result;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistruct ipoib_vlan_delete_work {
21162306a36Sopenharmony_ci	struct work_struct work;
21262306a36Sopenharmony_ci	struct net_device *dev;
21362306a36Sopenharmony_ci};
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci/*
21662306a36Sopenharmony_ci * sysfs callbacks of a netdevice cannot obtain the rtnl lock as
21762306a36Sopenharmony_ci * unregister_netdev ultimately deletes the sysfs files while holding the rtnl
21862306a36Sopenharmony_ci * lock. This deadlocks the system.
21962306a36Sopenharmony_ci *
22062306a36Sopenharmony_ci * A callback can use rtnl_trylock to avoid the deadlock but it cannot call
22162306a36Sopenharmony_ci * unregister_netdev as that internally takes and releases the rtnl_lock.  So
22262306a36Sopenharmony_ci * instead we find the netdev to unregister and then do the actual unregister
22362306a36Sopenharmony_ci * from the global work queue where we can obtain the rtnl_lock safely.
22462306a36Sopenharmony_ci */
22562306a36Sopenharmony_cistatic void ipoib_vlan_delete_task(struct work_struct *work)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct ipoib_vlan_delete_work *pwork =
22862306a36Sopenharmony_ci		container_of(work, struct ipoib_vlan_delete_work, work);
22962306a36Sopenharmony_ci	struct net_device *dev = pwork->dev;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	rtnl_lock();
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	/* Unregistering tasks can race with another task or parent removal */
23462306a36Sopenharmony_ci	if (dev->reg_state == NETREG_REGISTERED) {
23562306a36Sopenharmony_ci		struct ipoib_dev_priv *priv = ipoib_priv(dev);
23662306a36Sopenharmony_ci		struct ipoib_dev_priv *ppriv = ipoib_priv(priv->parent);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		ipoib_dbg(ppriv, "delete child vlan %s\n", dev->name);
23962306a36Sopenharmony_ci		unregister_netdevice(dev);
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	rtnl_unlock();
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	kfree(pwork);
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ciint ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	struct ipoib_dev_priv *ppriv, *priv, *tpriv;
25062306a36Sopenharmony_ci	int rc;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (!capable(CAP_NET_ADMIN))
25362306a36Sopenharmony_ci		return -EPERM;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (!rtnl_trylock())
25662306a36Sopenharmony_ci		return restart_syscall();
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	if (pdev->reg_state != NETREG_REGISTERED) {
25962306a36Sopenharmony_ci		rtnl_unlock();
26062306a36Sopenharmony_ci		return -EPERM;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	ppriv = ipoib_priv(pdev);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	rc = -ENODEV;
26662306a36Sopenharmony_ci	list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
26762306a36Sopenharmony_ci		if (priv->pkey == pkey &&
26862306a36Sopenharmony_ci		    priv->child_type == IPOIB_LEGACY_CHILD) {
26962306a36Sopenharmony_ci			struct ipoib_vlan_delete_work *work;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci			work = kmalloc(sizeof(*work), GFP_KERNEL);
27262306a36Sopenharmony_ci			if (!work) {
27362306a36Sopenharmony_ci				rc = -ENOMEM;
27462306a36Sopenharmony_ci				goto out;
27562306a36Sopenharmony_ci			}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci			down_write(&ppriv->vlan_rwsem);
27862306a36Sopenharmony_ci			list_del_init(&priv->list);
27962306a36Sopenharmony_ci			up_write(&ppriv->vlan_rwsem);
28062306a36Sopenharmony_ci			work->dev = priv->dev;
28162306a36Sopenharmony_ci			INIT_WORK(&work->work, ipoib_vlan_delete_task);
28262306a36Sopenharmony_ci			queue_work(ipoib_workqueue, &work->work);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci			rc = 0;
28562306a36Sopenharmony_ci			break;
28662306a36Sopenharmony_ci		}
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ciout:
29062306a36Sopenharmony_ci	rtnl_unlock();
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	return rc;
29362306a36Sopenharmony_ci}
294