162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
362306a36Sopenharmony_ci * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This software is available to you under a choice of one of two
662306a36Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
762306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
862306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the
962306a36Sopenharmony_ci * OpenIB.org BSD license below:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
1262306a36Sopenharmony_ci *     without modification, are permitted provided that the following
1362306a36Sopenharmony_ci *     conditions are met:
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci *      - Redistributions of source code must retain the above
1662306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
1762306a36Sopenharmony_ci *        disclaimer.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
2062306a36Sopenharmony_ci *        copyright notice, this list of conditions and the following
2162306a36Sopenharmony_ci *        disclaimer in the documentation and/or other materials
2262306a36Sopenharmony_ci *        provided with the distribution.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2562306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2662306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2762306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2862306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2962306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3062306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3162306a36Sopenharmony_ci * SOFTWARE.
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include <linux/module.h>
3562306a36Sopenharmony_ci#include <linux/init.h>
3662306a36Sopenharmony_ci#include <linux/slab.h>
3762306a36Sopenharmony_ci#include <linux/errno.h>
3862306a36Sopenharmony_ci#include <linux/netdevice.h>
3962306a36Sopenharmony_ci#include <linux/inetdevice.h>
4062306a36Sopenharmony_ci#include <linux/rtnetlink.h>
4162306a36Sopenharmony_ci#include <linux/if_vlan.h>
4262306a36Sopenharmony_ci#include <linux/sched/mm.h>
4362306a36Sopenharmony_ci#include <linux/sched/task.h>
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#include <net/ipv6.h>
4662306a36Sopenharmony_ci#include <net/addrconf.h>
4762306a36Sopenharmony_ci#include <net/devlink.h>
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#include <rdma/ib_smi.h>
5062306a36Sopenharmony_ci#include <rdma/ib_user_verbs.h>
5162306a36Sopenharmony_ci#include <rdma/ib_addr.h>
5262306a36Sopenharmony_ci#include <rdma/ib_cache.h>
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#include <net/bonding.h>
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#include <linux/mlx4/driver.h>
5762306a36Sopenharmony_ci#include <linux/mlx4/cmd.h>
5862306a36Sopenharmony_ci#include <linux/mlx4/qp.h>
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#include "mlx4_ib.h"
6162306a36Sopenharmony_ci#include <rdma/mlx4-abi.h>
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define DRV_NAME	MLX4_IB_DRV_NAME
6462306a36Sopenharmony_ci#define DRV_VERSION	"4.0-0"
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define MLX4_IB_FLOW_MAX_PRIO 0xFFF
6762306a36Sopenharmony_ci#define MLX4_IB_FLOW_QPN_MASK 0xFFFFFF
6862306a36Sopenharmony_ci#define MLX4_IB_CARD_REV_A0   0xA0
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciMODULE_AUTHOR("Roland Dreier");
7162306a36Sopenharmony_ciMODULE_DESCRIPTION("Mellanox ConnectX HCA InfiniBand driver");
7262306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ciint mlx4_ib_sm_guid_assign = 0;
7562306a36Sopenharmony_cimodule_param_named(sm_guid_assign, mlx4_ib_sm_guid_assign, int, 0444);
7662306a36Sopenharmony_ciMODULE_PARM_DESC(sm_guid_assign, "Enable SM alias_GUID assignment if sm_guid_assign > 0 (Default: 0)");
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic const char mlx4_ib_version[] =
7962306a36Sopenharmony_ci	DRV_NAME ": Mellanox ConnectX InfiniBand driver v"
8062306a36Sopenharmony_ci	DRV_VERSION "\n";
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init);
8362306a36Sopenharmony_cistatic enum rdma_link_layer mlx4_ib_port_link_layer(struct ib_device *device,
8462306a36Sopenharmony_ci						    u32 port_num);
8562306a36Sopenharmony_cistatic int mlx4_ib_event(struct notifier_block *this, unsigned long event,
8662306a36Sopenharmony_ci			 void *param);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic struct workqueue_struct *wq;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic int check_flow_steering_support(struct mlx4_dev *dev)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	int eth_num_ports = 0;
9362306a36Sopenharmony_ci	int ib_num_ports = 0;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	int dmfs = dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	if (dmfs) {
9862306a36Sopenharmony_ci		int i;
9962306a36Sopenharmony_ci		mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
10062306a36Sopenharmony_ci			eth_num_ports++;
10162306a36Sopenharmony_ci		mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
10262306a36Sopenharmony_ci			ib_num_ports++;
10362306a36Sopenharmony_ci		dmfs &= (!ib_num_ports ||
10462306a36Sopenharmony_ci			 (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DMFS_IPOIB)) &&
10562306a36Sopenharmony_ci			(!eth_num_ports ||
10662306a36Sopenharmony_ci			 (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FS_EN));
10762306a36Sopenharmony_ci		if (ib_num_ports && mlx4_is_mfunc(dev)) {
10862306a36Sopenharmony_ci			pr_warn("Device managed flow steering is unavailable for IB port in multifunction env.\n");
10962306a36Sopenharmony_ci			dmfs = 0;
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci	return dmfs;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic int num_ib_ports(struct mlx4_dev *dev)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	int ib_ports = 0;
11862306a36Sopenharmony_ci	int i;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
12162306a36Sopenharmony_ci		ib_ports++;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	return ib_ports;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic struct net_device *mlx4_ib_get_netdev(struct ib_device *device,
12762306a36Sopenharmony_ci					     u32 port_num)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct mlx4_ib_dev *ibdev = to_mdev(device);
13062306a36Sopenharmony_ci	struct net_device *dev, *ret = NULL;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	rcu_read_lock();
13362306a36Sopenharmony_ci	for_each_netdev_rcu(&init_net, dev) {
13462306a36Sopenharmony_ci		if (dev->dev.parent != ibdev->ib_dev.dev.parent ||
13562306a36Sopenharmony_ci		    dev->dev_port + 1 != port_num)
13662306a36Sopenharmony_ci			continue;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci		if (mlx4_is_bonded(ibdev->dev)) {
13962306a36Sopenharmony_ci			struct net_device *upper;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci			upper = netdev_master_upper_dev_get_rcu(dev);
14262306a36Sopenharmony_ci			if (upper) {
14362306a36Sopenharmony_ci				struct net_device *active;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci				active = bond_option_active_slave_get_rcu(netdev_priv(upper));
14662306a36Sopenharmony_ci				if (active)
14762306a36Sopenharmony_ci					dev = active;
14862306a36Sopenharmony_ci			}
14962306a36Sopenharmony_ci		}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		dev_hold(dev);
15262306a36Sopenharmony_ci		ret = dev;
15362306a36Sopenharmony_ci		break;
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	rcu_read_unlock();
15762306a36Sopenharmony_ci	return ret;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int mlx4_ib_update_gids_v1(struct gid_entry *gids,
16162306a36Sopenharmony_ci				  struct mlx4_ib_dev *ibdev,
16262306a36Sopenharmony_ci				  u32 port_num)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
16562306a36Sopenharmony_ci	int err;
16662306a36Sopenharmony_ci	struct mlx4_dev *dev = ibdev->dev;
16762306a36Sopenharmony_ci	int i;
16862306a36Sopenharmony_ci	union ib_gid *gid_tbl;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
17162306a36Sopenharmony_ci	if (IS_ERR(mailbox))
17262306a36Sopenharmony_ci		return -ENOMEM;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	gid_tbl = mailbox->buf;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	for (i = 0; i < MLX4_MAX_PORT_GIDS; ++i)
17762306a36Sopenharmony_ci		memcpy(&gid_tbl[i], &gids[i].gid, sizeof(union ib_gid));
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	err = mlx4_cmd(dev, mailbox->dma,
18062306a36Sopenharmony_ci		       MLX4_SET_PORT_GID_TABLE << 8 | port_num,
18162306a36Sopenharmony_ci		       1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
18262306a36Sopenharmony_ci		       MLX4_CMD_WRAPPED);
18362306a36Sopenharmony_ci	if (mlx4_is_bonded(dev))
18462306a36Sopenharmony_ci		err += mlx4_cmd(dev, mailbox->dma,
18562306a36Sopenharmony_ci				MLX4_SET_PORT_GID_TABLE << 8 | 2,
18662306a36Sopenharmony_ci				1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
18762306a36Sopenharmony_ci				MLX4_CMD_WRAPPED);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
19062306a36Sopenharmony_ci	return err;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic int mlx4_ib_update_gids_v1_v2(struct gid_entry *gids,
19462306a36Sopenharmony_ci				     struct mlx4_ib_dev *ibdev,
19562306a36Sopenharmony_ci				     u32 port_num)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
19862306a36Sopenharmony_ci	int err;
19962306a36Sopenharmony_ci	struct mlx4_dev *dev = ibdev->dev;
20062306a36Sopenharmony_ci	int i;
20162306a36Sopenharmony_ci	struct {
20262306a36Sopenharmony_ci		union ib_gid	gid;
20362306a36Sopenharmony_ci		__be32		rsrvd1[2];
20462306a36Sopenharmony_ci		__be16		rsrvd2;
20562306a36Sopenharmony_ci		u8		type;
20662306a36Sopenharmony_ci		u8		version;
20762306a36Sopenharmony_ci		__be32		rsrvd3;
20862306a36Sopenharmony_ci	} *gid_tbl;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev);
21162306a36Sopenharmony_ci	if (IS_ERR(mailbox))
21262306a36Sopenharmony_ci		return -ENOMEM;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	gid_tbl = mailbox->buf;
21562306a36Sopenharmony_ci	for (i = 0; i < MLX4_MAX_PORT_GIDS; ++i) {
21662306a36Sopenharmony_ci		memcpy(&gid_tbl[i].gid, &gids[i].gid, sizeof(union ib_gid));
21762306a36Sopenharmony_ci		if (gids[i].gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP) {
21862306a36Sopenharmony_ci			gid_tbl[i].version = 2;
21962306a36Sopenharmony_ci			if (!ipv6_addr_v4mapped((struct in6_addr *)&gids[i].gid))
22062306a36Sopenharmony_ci				gid_tbl[i].type = 1;
22162306a36Sopenharmony_ci		}
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	err = mlx4_cmd(dev, mailbox->dma,
22562306a36Sopenharmony_ci		       MLX4_SET_PORT_ROCE_ADDR << 8 | port_num,
22662306a36Sopenharmony_ci		       1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
22762306a36Sopenharmony_ci		       MLX4_CMD_WRAPPED);
22862306a36Sopenharmony_ci	if (mlx4_is_bonded(dev))
22962306a36Sopenharmony_ci		err += mlx4_cmd(dev, mailbox->dma,
23062306a36Sopenharmony_ci				MLX4_SET_PORT_ROCE_ADDR << 8 | 2,
23162306a36Sopenharmony_ci				1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
23262306a36Sopenharmony_ci				MLX4_CMD_WRAPPED);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev, mailbox);
23562306a36Sopenharmony_ci	return err;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic int mlx4_ib_update_gids(struct gid_entry *gids,
23962306a36Sopenharmony_ci			       struct mlx4_ib_dev *ibdev,
24062306a36Sopenharmony_ci			       u32 port_num)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	if (ibdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2)
24362306a36Sopenharmony_ci		return mlx4_ib_update_gids_v1_v2(gids, ibdev, port_num);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return mlx4_ib_update_gids_v1(gids, ibdev, port_num);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic void free_gid_entry(struct gid_entry *entry)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	memset(&entry->gid, 0, sizeof(entry->gid));
25162306a36Sopenharmony_ci	kfree(entry->ctx);
25262306a36Sopenharmony_ci	entry->ctx = NULL;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic int mlx4_ib_add_gid(const struct ib_gid_attr *attr, void **context)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct mlx4_ib_dev *ibdev = to_mdev(attr->device);
25862306a36Sopenharmony_ci	struct mlx4_ib_iboe *iboe = &ibdev->iboe;
25962306a36Sopenharmony_ci	struct mlx4_port_gid_table   *port_gid_table;
26062306a36Sopenharmony_ci	int free = -1, found = -1;
26162306a36Sopenharmony_ci	int ret = 0;
26262306a36Sopenharmony_ci	int hw_update = 0;
26362306a36Sopenharmony_ci	int i;
26462306a36Sopenharmony_ci	struct gid_entry *gids;
26562306a36Sopenharmony_ci	u16 vlan_id = 0xffff;
26662306a36Sopenharmony_ci	u8 mac[ETH_ALEN];
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (!rdma_cap_roce_gid_table(attr->device, attr->port_num))
26962306a36Sopenharmony_ci		return -EINVAL;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (attr->port_num > MLX4_MAX_PORTS)
27262306a36Sopenharmony_ci		return -EINVAL;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (!context)
27562306a36Sopenharmony_ci		return -EINVAL;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	ret = rdma_read_gid_l2_fields(attr, &vlan_id, &mac[0]);
27862306a36Sopenharmony_ci	if (ret)
27962306a36Sopenharmony_ci		return ret;
28062306a36Sopenharmony_ci	port_gid_table = &iboe->gids[attr->port_num - 1];
28162306a36Sopenharmony_ci	spin_lock_bh(&iboe->lock);
28262306a36Sopenharmony_ci	for (i = 0; i < MLX4_MAX_PORT_GIDS; ++i) {
28362306a36Sopenharmony_ci		if (!memcmp(&port_gid_table->gids[i].gid,
28462306a36Sopenharmony_ci			    &attr->gid, sizeof(attr->gid)) &&
28562306a36Sopenharmony_ci		    port_gid_table->gids[i].gid_type == attr->gid_type &&
28662306a36Sopenharmony_ci		    port_gid_table->gids[i].vlan_id == vlan_id)  {
28762306a36Sopenharmony_ci			found = i;
28862306a36Sopenharmony_ci			break;
28962306a36Sopenharmony_ci		}
29062306a36Sopenharmony_ci		if (free < 0 && rdma_is_zero_gid(&port_gid_table->gids[i].gid))
29162306a36Sopenharmony_ci			free = i; /* HW has space */
29262306a36Sopenharmony_ci	}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (found < 0) {
29562306a36Sopenharmony_ci		if (free < 0) {
29662306a36Sopenharmony_ci			ret = -ENOSPC;
29762306a36Sopenharmony_ci		} else {
29862306a36Sopenharmony_ci			port_gid_table->gids[free].ctx = kmalloc(sizeof(*port_gid_table->gids[free].ctx), GFP_ATOMIC);
29962306a36Sopenharmony_ci			if (!port_gid_table->gids[free].ctx) {
30062306a36Sopenharmony_ci				ret = -ENOMEM;
30162306a36Sopenharmony_ci			} else {
30262306a36Sopenharmony_ci				*context = port_gid_table->gids[free].ctx;
30362306a36Sopenharmony_ci				port_gid_table->gids[free].gid = attr->gid;
30462306a36Sopenharmony_ci				port_gid_table->gids[free].gid_type = attr->gid_type;
30562306a36Sopenharmony_ci				port_gid_table->gids[free].vlan_id = vlan_id;
30662306a36Sopenharmony_ci				port_gid_table->gids[free].ctx->real_index = free;
30762306a36Sopenharmony_ci				port_gid_table->gids[free].ctx->refcount = 1;
30862306a36Sopenharmony_ci				hw_update = 1;
30962306a36Sopenharmony_ci			}
31062306a36Sopenharmony_ci		}
31162306a36Sopenharmony_ci	} else {
31262306a36Sopenharmony_ci		struct gid_cache_context *ctx = port_gid_table->gids[found].ctx;
31362306a36Sopenharmony_ci		*context = ctx;
31462306a36Sopenharmony_ci		ctx->refcount++;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci	if (!ret && hw_update) {
31762306a36Sopenharmony_ci		gids = kmalloc_array(MLX4_MAX_PORT_GIDS, sizeof(*gids),
31862306a36Sopenharmony_ci				     GFP_ATOMIC);
31962306a36Sopenharmony_ci		if (!gids) {
32062306a36Sopenharmony_ci			ret = -ENOMEM;
32162306a36Sopenharmony_ci			*context = NULL;
32262306a36Sopenharmony_ci			free_gid_entry(&port_gid_table->gids[free]);
32362306a36Sopenharmony_ci		} else {
32462306a36Sopenharmony_ci			for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) {
32562306a36Sopenharmony_ci				memcpy(&gids[i].gid, &port_gid_table->gids[i].gid, sizeof(union ib_gid));
32662306a36Sopenharmony_ci				gids[i].gid_type = port_gid_table->gids[i].gid_type;
32762306a36Sopenharmony_ci			}
32862306a36Sopenharmony_ci		}
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci	spin_unlock_bh(&iboe->lock);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (!ret && hw_update) {
33362306a36Sopenharmony_ci		ret = mlx4_ib_update_gids(gids, ibdev, attr->port_num);
33462306a36Sopenharmony_ci		if (ret) {
33562306a36Sopenharmony_ci			spin_lock_bh(&iboe->lock);
33662306a36Sopenharmony_ci			*context = NULL;
33762306a36Sopenharmony_ci			free_gid_entry(&port_gid_table->gids[free]);
33862306a36Sopenharmony_ci			spin_unlock_bh(&iboe->lock);
33962306a36Sopenharmony_ci		}
34062306a36Sopenharmony_ci		kfree(gids);
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	return ret;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic int mlx4_ib_del_gid(const struct ib_gid_attr *attr, void **context)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct gid_cache_context *ctx = *context;
34962306a36Sopenharmony_ci	struct mlx4_ib_dev *ibdev = to_mdev(attr->device);
35062306a36Sopenharmony_ci	struct mlx4_ib_iboe *iboe = &ibdev->iboe;
35162306a36Sopenharmony_ci	struct mlx4_port_gid_table   *port_gid_table;
35262306a36Sopenharmony_ci	int ret = 0;
35362306a36Sopenharmony_ci	int hw_update = 0;
35462306a36Sopenharmony_ci	struct gid_entry *gids;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (!rdma_cap_roce_gid_table(attr->device, attr->port_num))
35762306a36Sopenharmony_ci		return -EINVAL;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (attr->port_num > MLX4_MAX_PORTS)
36062306a36Sopenharmony_ci		return -EINVAL;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	port_gid_table = &iboe->gids[attr->port_num - 1];
36362306a36Sopenharmony_ci	spin_lock_bh(&iboe->lock);
36462306a36Sopenharmony_ci	if (ctx) {
36562306a36Sopenharmony_ci		ctx->refcount--;
36662306a36Sopenharmony_ci		if (!ctx->refcount) {
36762306a36Sopenharmony_ci			unsigned int real_index = ctx->real_index;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci			free_gid_entry(&port_gid_table->gids[real_index]);
37062306a36Sopenharmony_ci			hw_update = 1;
37162306a36Sopenharmony_ci		}
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci	if (!ret && hw_update) {
37462306a36Sopenharmony_ci		int i;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci		gids = kmalloc_array(MLX4_MAX_PORT_GIDS, sizeof(*gids),
37762306a36Sopenharmony_ci				     GFP_ATOMIC);
37862306a36Sopenharmony_ci		if (!gids) {
37962306a36Sopenharmony_ci			ret = -ENOMEM;
38062306a36Sopenharmony_ci		} else {
38162306a36Sopenharmony_ci			for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) {
38262306a36Sopenharmony_ci				memcpy(&gids[i].gid,
38362306a36Sopenharmony_ci				       &port_gid_table->gids[i].gid,
38462306a36Sopenharmony_ci				       sizeof(union ib_gid));
38562306a36Sopenharmony_ci				gids[i].gid_type =
38662306a36Sopenharmony_ci				    port_gid_table->gids[i].gid_type;
38762306a36Sopenharmony_ci			}
38862306a36Sopenharmony_ci		}
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci	spin_unlock_bh(&iboe->lock);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (!ret && hw_update) {
39362306a36Sopenharmony_ci		ret = mlx4_ib_update_gids(gids, ibdev, attr->port_num);
39462306a36Sopenharmony_ci		kfree(gids);
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci	return ret;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ciint mlx4_ib_gid_index_to_real_index(struct mlx4_ib_dev *ibdev,
40062306a36Sopenharmony_ci				    const struct ib_gid_attr *attr)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	struct mlx4_ib_iboe *iboe = &ibdev->iboe;
40362306a36Sopenharmony_ci	struct gid_cache_context *ctx = NULL;
40462306a36Sopenharmony_ci	struct mlx4_port_gid_table   *port_gid_table;
40562306a36Sopenharmony_ci	int real_index = -EINVAL;
40662306a36Sopenharmony_ci	int i;
40762306a36Sopenharmony_ci	unsigned long flags;
40862306a36Sopenharmony_ci	u32 port_num = attr->port_num;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	if (port_num > MLX4_MAX_PORTS)
41162306a36Sopenharmony_ci		return -EINVAL;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (mlx4_is_bonded(ibdev->dev))
41462306a36Sopenharmony_ci		port_num = 1;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (!rdma_cap_roce_gid_table(&ibdev->ib_dev, port_num))
41762306a36Sopenharmony_ci		return attr->index;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	spin_lock_irqsave(&iboe->lock, flags);
42062306a36Sopenharmony_ci	port_gid_table = &iboe->gids[port_num - 1];
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	for (i = 0; i < MLX4_MAX_PORT_GIDS; ++i)
42362306a36Sopenharmony_ci		if (!memcmp(&port_gid_table->gids[i].gid,
42462306a36Sopenharmony_ci			    &attr->gid, sizeof(attr->gid)) &&
42562306a36Sopenharmony_ci		    attr->gid_type == port_gid_table->gids[i].gid_type) {
42662306a36Sopenharmony_ci			ctx = port_gid_table->gids[i].ctx;
42762306a36Sopenharmony_ci			break;
42862306a36Sopenharmony_ci		}
42962306a36Sopenharmony_ci	if (ctx)
43062306a36Sopenharmony_ci		real_index = ctx->real_index;
43162306a36Sopenharmony_ci	spin_unlock_irqrestore(&iboe->lock, flags);
43262306a36Sopenharmony_ci	return real_index;
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic int mlx4_ib_query_device(struct ib_device *ibdev,
43662306a36Sopenharmony_ci				struct ib_device_attr *props,
43762306a36Sopenharmony_ci				struct ib_udata *uhw)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(ibdev);
44062306a36Sopenharmony_ci	struct ib_smp *in_mad;
44162306a36Sopenharmony_ci	struct ib_smp *out_mad;
44262306a36Sopenharmony_ci	int err;
44362306a36Sopenharmony_ci	int have_ib_ports;
44462306a36Sopenharmony_ci	struct mlx4_uverbs_ex_query_device cmd;
44562306a36Sopenharmony_ci	struct mlx4_uverbs_ex_query_device_resp resp = {};
44662306a36Sopenharmony_ci	struct mlx4_clock_params clock_params;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (uhw->inlen) {
44962306a36Sopenharmony_ci		if (uhw->inlen < sizeof(cmd))
45062306a36Sopenharmony_ci			return -EINVAL;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci		err = ib_copy_from_udata(&cmd, uhw, sizeof(cmd));
45362306a36Sopenharmony_ci		if (err)
45462306a36Sopenharmony_ci			return err;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci		if (cmd.comp_mask)
45762306a36Sopenharmony_ci			return -EINVAL;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		if (cmd.reserved)
46062306a36Sopenharmony_ci			return -EINVAL;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	resp.response_length = offsetof(typeof(resp), response_length) +
46462306a36Sopenharmony_ci		sizeof(resp.response_length);
46562306a36Sopenharmony_ci	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
46662306a36Sopenharmony_ci	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
46762306a36Sopenharmony_ci	err = -ENOMEM;
46862306a36Sopenharmony_ci	if (!in_mad || !out_mad)
46962306a36Sopenharmony_ci		goto out;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	ib_init_query_mad(in_mad);
47262306a36Sopenharmony_ci	in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	err = mlx4_MAD_IFC(to_mdev(ibdev), MLX4_MAD_IFC_IGNORE_KEYS,
47562306a36Sopenharmony_ci			   1, NULL, NULL, in_mad, out_mad);
47662306a36Sopenharmony_ci	if (err)
47762306a36Sopenharmony_ci		goto out;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	memset(props, 0, sizeof *props);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	have_ib_ports = num_ib_ports(dev->dev);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	props->fw_ver = dev->dev->caps.fw_ver;
48462306a36Sopenharmony_ci	props->device_cap_flags    = IB_DEVICE_CHANGE_PHY_PORT |
48562306a36Sopenharmony_ci		IB_DEVICE_PORT_ACTIVE_EVENT		|
48662306a36Sopenharmony_ci		IB_DEVICE_SYS_IMAGE_GUID		|
48762306a36Sopenharmony_ci		IB_DEVICE_RC_RNR_NAK_GEN;
48862306a36Sopenharmony_ci	props->kernel_cap_flags = IBK_BLOCK_MULTICAST_LOOPBACK;
48962306a36Sopenharmony_ci	if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_BAD_PKEY_CNTR)
49062306a36Sopenharmony_ci		props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;
49162306a36Sopenharmony_ci	if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_BAD_QKEY_CNTR)
49262306a36Sopenharmony_ci		props->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR;
49362306a36Sopenharmony_ci	if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_APM && have_ib_ports)
49462306a36Sopenharmony_ci		props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;
49562306a36Sopenharmony_ci	if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_UD_AV_PORT)
49662306a36Sopenharmony_ci		props->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE;
49762306a36Sopenharmony_ci	if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_IPOIB_CSUM)
49862306a36Sopenharmony_ci		props->device_cap_flags |= IB_DEVICE_UD_IP_CSUM;
49962306a36Sopenharmony_ci	if (dev->dev->caps.max_gso_sz &&
50062306a36Sopenharmony_ci	    (dev->dev->rev_id != MLX4_IB_CARD_REV_A0) &&
50162306a36Sopenharmony_ci	    (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_BLH))
50262306a36Sopenharmony_ci		props->kernel_cap_flags |= IBK_UD_TSO;
50362306a36Sopenharmony_ci	if (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_RESERVED_LKEY)
50462306a36Sopenharmony_ci		props->kernel_cap_flags |= IBK_LOCAL_DMA_LKEY;
50562306a36Sopenharmony_ci	if ((dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_LOCAL_INV) &&
50662306a36Sopenharmony_ci	    (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_REMOTE_INV) &&
50762306a36Sopenharmony_ci	    (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_FAST_REG_WR))
50862306a36Sopenharmony_ci		props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
50962306a36Sopenharmony_ci	if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC)
51062306a36Sopenharmony_ci		props->device_cap_flags |= IB_DEVICE_XRC;
51162306a36Sopenharmony_ci	if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_MEM_WINDOW)
51262306a36Sopenharmony_ci		props->device_cap_flags |= IB_DEVICE_MEM_WINDOW;
51362306a36Sopenharmony_ci	if (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_TYPE_2_WIN) {
51462306a36Sopenharmony_ci		if (dev->dev->caps.bmme_flags & MLX4_BMME_FLAG_WIN_TYPE_2B)
51562306a36Sopenharmony_ci			props->device_cap_flags |= IB_DEVICE_MEM_WINDOW_TYPE_2B;
51662306a36Sopenharmony_ci		else
51762306a36Sopenharmony_ci			props->device_cap_flags |= IB_DEVICE_MEM_WINDOW_TYPE_2A;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci	if (dev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED)
52062306a36Sopenharmony_ci		props->device_cap_flags |= IB_DEVICE_MANAGED_FLOW_STEERING;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	props->device_cap_flags |= IB_DEVICE_RAW_IP_CSUM;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	props->vendor_id	   = be32_to_cpup((__be32 *) (out_mad->data + 36)) &
52562306a36Sopenharmony_ci		0xffffff;
52662306a36Sopenharmony_ci	props->vendor_part_id	   = dev->dev->persist->pdev->device;
52762306a36Sopenharmony_ci	props->hw_ver		   = be32_to_cpup((__be32 *) (out_mad->data + 32));
52862306a36Sopenharmony_ci	memcpy(&props->sys_image_guid, out_mad->data +	4, 8);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	props->max_mr_size	   = ~0ull;
53162306a36Sopenharmony_ci	props->page_size_cap	   = dev->dev->caps.page_size_cap;
53262306a36Sopenharmony_ci	props->max_qp		   = dev->dev->quotas.qp;
53362306a36Sopenharmony_ci	props->max_qp_wr	   = dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE;
53462306a36Sopenharmony_ci	props->max_send_sge =
53562306a36Sopenharmony_ci		min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg);
53662306a36Sopenharmony_ci	props->max_recv_sge =
53762306a36Sopenharmony_ci		min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg);
53862306a36Sopenharmony_ci	props->max_sge_rd = MLX4_MAX_SGE_RD;
53962306a36Sopenharmony_ci	props->max_cq		   = dev->dev->quotas.cq;
54062306a36Sopenharmony_ci	props->max_cqe		   = dev->dev->caps.max_cqes;
54162306a36Sopenharmony_ci	props->max_mr		   = dev->dev->quotas.mpt;
54262306a36Sopenharmony_ci	props->max_pd		   = dev->dev->caps.num_pds - dev->dev->caps.reserved_pds;
54362306a36Sopenharmony_ci	props->max_qp_rd_atom	   = dev->dev->caps.max_qp_dest_rdma;
54462306a36Sopenharmony_ci	props->max_qp_init_rd_atom = dev->dev->caps.max_qp_init_rdma;
54562306a36Sopenharmony_ci	props->max_res_rd_atom	   = props->max_qp_rd_atom * props->max_qp;
54662306a36Sopenharmony_ci	props->max_srq		   = dev->dev->quotas.srq;
54762306a36Sopenharmony_ci	props->max_srq_wr	   = dev->dev->caps.max_srq_wqes - 1;
54862306a36Sopenharmony_ci	props->max_srq_sge	   = dev->dev->caps.max_srq_sge;
54962306a36Sopenharmony_ci	props->max_fast_reg_page_list_len = MLX4_MAX_FAST_REG_PAGES;
55062306a36Sopenharmony_ci	props->local_ca_ack_delay  = dev->dev->caps.local_ca_ack_delay;
55162306a36Sopenharmony_ci	props->atomic_cap	   = dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_ATOMIC ?
55262306a36Sopenharmony_ci		IB_ATOMIC_HCA : IB_ATOMIC_NONE;
55362306a36Sopenharmony_ci	props->masked_atomic_cap   = props->atomic_cap;
55462306a36Sopenharmony_ci	props->max_pkeys	   = dev->dev->caps.pkey_table_len[1];
55562306a36Sopenharmony_ci	props->max_mcast_grp	   = dev->dev->caps.num_mgms + dev->dev->caps.num_amgms;
55662306a36Sopenharmony_ci	props->max_mcast_qp_attach = dev->dev->caps.num_qp_per_mgm;
55762306a36Sopenharmony_ci	props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
55862306a36Sopenharmony_ci					   props->max_mcast_grp;
55962306a36Sopenharmony_ci	props->hca_core_clock = dev->dev->caps.hca_core_clock * 1000UL;
56062306a36Sopenharmony_ci	props->timestamp_mask = 0xFFFFFFFFFFFFULL;
56162306a36Sopenharmony_ci	props->max_ah = INT_MAX;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (mlx4_ib_port_link_layer(ibdev, 1) == IB_LINK_LAYER_ETHERNET ||
56462306a36Sopenharmony_ci	    mlx4_ib_port_link_layer(ibdev, 2) == IB_LINK_LAYER_ETHERNET) {
56562306a36Sopenharmony_ci		if (dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS) {
56662306a36Sopenharmony_ci			props->rss_caps.max_rwq_indirection_tables =
56762306a36Sopenharmony_ci				props->max_qp;
56862306a36Sopenharmony_ci			props->rss_caps.max_rwq_indirection_table_size =
56962306a36Sopenharmony_ci				dev->dev->caps.max_rss_tbl_sz;
57062306a36Sopenharmony_ci			props->rss_caps.supported_qpts = 1 << IB_QPT_RAW_PACKET;
57162306a36Sopenharmony_ci			props->max_wq_type_rq = props->max_qp;
57262306a36Sopenharmony_ci		}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci		if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP)
57562306a36Sopenharmony_ci			props->raw_packet_caps |= IB_RAW_PACKET_CAP_SCATTER_FCS;
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	props->cq_caps.max_cq_moderation_count = MLX4_MAX_CQ_COUNT;
57962306a36Sopenharmony_ci	props->cq_caps.max_cq_moderation_period = MLX4_MAX_CQ_PERIOD;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	if (uhw->outlen >= resp.response_length + sizeof(resp.hca_core_clock_offset)) {
58262306a36Sopenharmony_ci		resp.response_length += sizeof(resp.hca_core_clock_offset);
58362306a36Sopenharmony_ci		if (!mlx4_get_internal_clock_params(dev->dev, &clock_params)) {
58462306a36Sopenharmony_ci			resp.comp_mask |= MLX4_IB_QUERY_DEV_RESP_MASK_CORE_CLOCK_OFFSET;
58562306a36Sopenharmony_ci			resp.hca_core_clock_offset = clock_params.offset % PAGE_SIZE;
58662306a36Sopenharmony_ci		}
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	if (uhw->outlen >= resp.response_length +
59062306a36Sopenharmony_ci	    sizeof(resp.max_inl_recv_sz)) {
59162306a36Sopenharmony_ci		resp.response_length += sizeof(resp.max_inl_recv_sz);
59262306a36Sopenharmony_ci		resp.max_inl_recv_sz  = dev->dev->caps.max_rq_sg *
59362306a36Sopenharmony_ci			sizeof(struct mlx4_wqe_data_seg);
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	if (offsetofend(typeof(resp), rss_caps) <= uhw->outlen) {
59762306a36Sopenharmony_ci		if (props->rss_caps.supported_qpts) {
59862306a36Sopenharmony_ci			resp.rss_caps.rx_hash_function =
59962306a36Sopenharmony_ci				MLX4_IB_RX_HASH_FUNC_TOEPLITZ;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci			resp.rss_caps.rx_hash_fields_mask =
60262306a36Sopenharmony_ci				MLX4_IB_RX_HASH_SRC_IPV4 |
60362306a36Sopenharmony_ci				MLX4_IB_RX_HASH_DST_IPV4 |
60462306a36Sopenharmony_ci				MLX4_IB_RX_HASH_SRC_IPV6 |
60562306a36Sopenharmony_ci				MLX4_IB_RX_HASH_DST_IPV6 |
60662306a36Sopenharmony_ci				MLX4_IB_RX_HASH_SRC_PORT_TCP |
60762306a36Sopenharmony_ci				MLX4_IB_RX_HASH_DST_PORT_TCP |
60862306a36Sopenharmony_ci				MLX4_IB_RX_HASH_SRC_PORT_UDP |
60962306a36Sopenharmony_ci				MLX4_IB_RX_HASH_DST_PORT_UDP;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci			if (dev->dev->caps.tunnel_offload_mode ==
61262306a36Sopenharmony_ci			    MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
61362306a36Sopenharmony_ci				resp.rss_caps.rx_hash_fields_mask |=
61462306a36Sopenharmony_ci					MLX4_IB_RX_HASH_INNER;
61562306a36Sopenharmony_ci		}
61662306a36Sopenharmony_ci		resp.response_length = offsetof(typeof(resp), rss_caps) +
61762306a36Sopenharmony_ci				       sizeof(resp.rss_caps);
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	if (offsetofend(typeof(resp), tso_caps) <= uhw->outlen) {
62162306a36Sopenharmony_ci		if (dev->dev->caps.max_gso_sz &&
62262306a36Sopenharmony_ci		    ((mlx4_ib_port_link_layer(ibdev, 1) ==
62362306a36Sopenharmony_ci		    IB_LINK_LAYER_ETHERNET) ||
62462306a36Sopenharmony_ci		    (mlx4_ib_port_link_layer(ibdev, 2) ==
62562306a36Sopenharmony_ci		    IB_LINK_LAYER_ETHERNET))) {
62662306a36Sopenharmony_ci			resp.tso_caps.max_tso = dev->dev->caps.max_gso_sz;
62762306a36Sopenharmony_ci			resp.tso_caps.supported_qpts |=
62862306a36Sopenharmony_ci				1 << IB_QPT_RAW_PACKET;
62962306a36Sopenharmony_ci		}
63062306a36Sopenharmony_ci		resp.response_length = offsetof(typeof(resp), tso_caps) +
63162306a36Sopenharmony_ci				       sizeof(resp.tso_caps);
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	if (uhw->outlen) {
63562306a36Sopenharmony_ci		err = ib_copy_to_udata(uhw, &resp, resp.response_length);
63662306a36Sopenharmony_ci		if (err)
63762306a36Sopenharmony_ci			goto out;
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ciout:
64062306a36Sopenharmony_ci	kfree(in_mad);
64162306a36Sopenharmony_ci	kfree(out_mad);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	return err;
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistatic enum rdma_link_layer
64762306a36Sopenharmony_cimlx4_ib_port_link_layer(struct ib_device *device, u32 port_num)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	struct mlx4_dev *dev = to_mdev(device)->dev;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	return dev->caps.port_mask[port_num] == MLX4_PORT_TYPE_IB ?
65262306a36Sopenharmony_ci		IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET;
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic int ib_link_query_port(struct ib_device *ibdev, u32 port,
65662306a36Sopenharmony_ci			      struct ib_port_attr *props, int netw_view)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	struct ib_smp *in_mad;
65962306a36Sopenharmony_ci	struct ib_smp *out_mad;
66062306a36Sopenharmony_ci	int ext_active_speed;
66162306a36Sopenharmony_ci	int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS;
66262306a36Sopenharmony_ci	int err = -ENOMEM;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
66562306a36Sopenharmony_ci	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
66662306a36Sopenharmony_ci	if (!in_mad || !out_mad)
66762306a36Sopenharmony_ci		goto out;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	ib_init_query_mad(in_mad);
67062306a36Sopenharmony_ci	in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
67162306a36Sopenharmony_ci	in_mad->attr_mod = cpu_to_be32(port);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	if (mlx4_is_mfunc(to_mdev(ibdev)->dev) && netw_view)
67462306a36Sopenharmony_ci		mad_ifc_flags |= MLX4_MAD_IFC_NET_VIEW;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	err = mlx4_MAD_IFC(to_mdev(ibdev), mad_ifc_flags, port, NULL, NULL,
67762306a36Sopenharmony_ci				in_mad, out_mad);
67862306a36Sopenharmony_ci	if (err)
67962306a36Sopenharmony_ci		goto out;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	props->lid		= be16_to_cpup((__be16 *) (out_mad->data + 16));
68362306a36Sopenharmony_ci	props->lmc		= out_mad->data[34] & 0x7;
68462306a36Sopenharmony_ci	props->sm_lid		= be16_to_cpup((__be16 *) (out_mad->data + 18));
68562306a36Sopenharmony_ci	props->sm_sl		= out_mad->data[36] & 0xf;
68662306a36Sopenharmony_ci	props->state		= out_mad->data[32] & 0xf;
68762306a36Sopenharmony_ci	props->phys_state	= out_mad->data[33] >> 4;
68862306a36Sopenharmony_ci	props->port_cap_flags	= be32_to_cpup((__be32 *) (out_mad->data + 20));
68962306a36Sopenharmony_ci	if (netw_view)
69062306a36Sopenharmony_ci		props->gid_tbl_len = out_mad->data[50];
69162306a36Sopenharmony_ci	else
69262306a36Sopenharmony_ci		props->gid_tbl_len = to_mdev(ibdev)->dev->caps.gid_table_len[port];
69362306a36Sopenharmony_ci	props->max_msg_sz	= to_mdev(ibdev)->dev->caps.max_msg_sz;
69462306a36Sopenharmony_ci	props->pkey_tbl_len	= to_mdev(ibdev)->dev->caps.pkey_table_len[port];
69562306a36Sopenharmony_ci	props->bad_pkey_cntr	= be16_to_cpup((__be16 *) (out_mad->data + 46));
69662306a36Sopenharmony_ci	props->qkey_viol_cntr	= be16_to_cpup((__be16 *) (out_mad->data + 48));
69762306a36Sopenharmony_ci	props->active_width	= out_mad->data[31] & 0xf;
69862306a36Sopenharmony_ci	props->active_speed	= out_mad->data[35] >> 4;
69962306a36Sopenharmony_ci	props->max_mtu		= out_mad->data[41] & 0xf;
70062306a36Sopenharmony_ci	props->active_mtu	= out_mad->data[36] >> 4;
70162306a36Sopenharmony_ci	props->subnet_timeout	= out_mad->data[51] & 0x1f;
70262306a36Sopenharmony_ci	props->max_vl_num	= out_mad->data[37] >> 4;
70362306a36Sopenharmony_ci	props->init_type_reply	= out_mad->data[41] >> 4;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	/* Check if extended speeds (EDR/FDR/...) are supported */
70662306a36Sopenharmony_ci	if (props->port_cap_flags & IB_PORT_EXTENDED_SPEEDS_SUP) {
70762306a36Sopenharmony_ci		ext_active_speed = out_mad->data[62] >> 4;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		switch (ext_active_speed) {
71062306a36Sopenharmony_ci		case 1:
71162306a36Sopenharmony_ci			props->active_speed = IB_SPEED_FDR;
71262306a36Sopenharmony_ci			break;
71362306a36Sopenharmony_ci		case 2:
71462306a36Sopenharmony_ci			props->active_speed = IB_SPEED_EDR;
71562306a36Sopenharmony_ci			break;
71662306a36Sopenharmony_ci		}
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	/* If reported active speed is QDR, check if is FDR-10 */
72062306a36Sopenharmony_ci	if (props->active_speed == IB_SPEED_QDR) {
72162306a36Sopenharmony_ci		ib_init_query_mad(in_mad);
72262306a36Sopenharmony_ci		in_mad->attr_id = MLX4_ATTR_EXTENDED_PORT_INFO;
72362306a36Sopenharmony_ci		in_mad->attr_mod = cpu_to_be32(port);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci		err = mlx4_MAD_IFC(to_mdev(ibdev), mad_ifc_flags, port,
72662306a36Sopenharmony_ci				   NULL, NULL, in_mad, out_mad);
72762306a36Sopenharmony_ci		if (err)
72862306a36Sopenharmony_ci			goto out;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci		/* Checking LinkSpeedActive for FDR-10 */
73162306a36Sopenharmony_ci		if (out_mad->data[15] & 0x1)
73262306a36Sopenharmony_ci			props->active_speed = IB_SPEED_FDR10;
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	/* Avoid wrong speed value returned by FW if the IB link is down. */
73662306a36Sopenharmony_ci	if (props->state == IB_PORT_DOWN)
73762306a36Sopenharmony_ci		 props->active_speed = IB_SPEED_SDR;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ciout:
74062306a36Sopenharmony_ci	kfree(in_mad);
74162306a36Sopenharmony_ci	kfree(out_mad);
74262306a36Sopenharmony_ci	return err;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic u8 state_to_phys_state(enum ib_port_state state)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	return state == IB_PORT_ACTIVE ?
74862306a36Sopenharmony_ci		IB_PORT_PHYS_STATE_LINK_UP : IB_PORT_PHYS_STATE_DISABLED;
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_cistatic int eth_link_query_port(struct ib_device *ibdev, u32 port,
75262306a36Sopenharmony_ci			       struct ib_port_attr *props)
75362306a36Sopenharmony_ci{
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	struct mlx4_ib_dev *mdev = to_mdev(ibdev);
75662306a36Sopenharmony_ci	struct mlx4_ib_iboe *iboe = &mdev->iboe;
75762306a36Sopenharmony_ci	struct net_device *ndev;
75862306a36Sopenharmony_ci	enum ib_mtu tmp;
75962306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
76062306a36Sopenharmony_ci	int err = 0;
76162306a36Sopenharmony_ci	int is_bonded = mlx4_is_bonded(mdev->dev);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(mdev->dev);
76462306a36Sopenharmony_ci	if (IS_ERR(mailbox))
76562306a36Sopenharmony_ci		return PTR_ERR(mailbox);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, port, 0,
76862306a36Sopenharmony_ci			   MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B,
76962306a36Sopenharmony_ci			   MLX4_CMD_WRAPPED);
77062306a36Sopenharmony_ci	if (err)
77162306a36Sopenharmony_ci		goto out;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	props->active_width	=  (((u8 *)mailbox->buf)[5] == 0x40) ||
77462306a36Sopenharmony_ci				   (((u8 *)mailbox->buf)[5] == 0x20 /*56Gb*/) ?
77562306a36Sopenharmony_ci					   IB_WIDTH_4X : IB_WIDTH_1X;
77662306a36Sopenharmony_ci	props->active_speed	=  (((u8 *)mailbox->buf)[5] == 0x20 /*56Gb*/) ?
77762306a36Sopenharmony_ci					   IB_SPEED_FDR : IB_SPEED_QDR;
77862306a36Sopenharmony_ci	props->port_cap_flags	= IB_PORT_CM_SUP;
77962306a36Sopenharmony_ci	props->ip_gids = true;
78062306a36Sopenharmony_ci	props->gid_tbl_len	= mdev->dev->caps.gid_table_len[port];
78162306a36Sopenharmony_ci	props->max_msg_sz	= mdev->dev->caps.max_msg_sz;
78262306a36Sopenharmony_ci	if (mdev->dev->caps.pkey_table_len[port])
78362306a36Sopenharmony_ci		props->pkey_tbl_len = 1;
78462306a36Sopenharmony_ci	props->max_mtu		= IB_MTU_4096;
78562306a36Sopenharmony_ci	props->max_vl_num	= 2;
78662306a36Sopenharmony_ci	props->state		= IB_PORT_DOWN;
78762306a36Sopenharmony_ci	props->phys_state	= state_to_phys_state(props->state);
78862306a36Sopenharmony_ci	props->active_mtu	= IB_MTU_256;
78962306a36Sopenharmony_ci	spin_lock_bh(&iboe->lock);
79062306a36Sopenharmony_ci	ndev = iboe->netdevs[port - 1];
79162306a36Sopenharmony_ci	if (ndev && is_bonded) {
79262306a36Sopenharmony_ci		rcu_read_lock(); /* required to get upper dev */
79362306a36Sopenharmony_ci		ndev = netdev_master_upper_dev_get_rcu(ndev);
79462306a36Sopenharmony_ci		rcu_read_unlock();
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci	if (!ndev)
79762306a36Sopenharmony_ci		goto out_unlock;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	tmp = iboe_get_mtu(ndev->mtu);
80062306a36Sopenharmony_ci	props->active_mtu = tmp ? min(props->max_mtu, tmp) : IB_MTU_256;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	props->state		= (netif_running(ndev) && netif_carrier_ok(ndev)) ?
80362306a36Sopenharmony_ci					IB_PORT_ACTIVE : IB_PORT_DOWN;
80462306a36Sopenharmony_ci	props->phys_state	= state_to_phys_state(props->state);
80562306a36Sopenharmony_ciout_unlock:
80662306a36Sopenharmony_ci	spin_unlock_bh(&iboe->lock);
80762306a36Sopenharmony_ciout:
80862306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(mdev->dev, mailbox);
80962306a36Sopenharmony_ci	return err;
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ciint __mlx4_ib_query_port(struct ib_device *ibdev, u32 port,
81362306a36Sopenharmony_ci			 struct ib_port_attr *props, int netw_view)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	int err;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	/* props being zeroed by the caller, avoid zeroing it here */
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	err = mlx4_ib_port_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND ?
82062306a36Sopenharmony_ci		ib_link_query_port(ibdev, port, props, netw_view) :
82162306a36Sopenharmony_ci				eth_link_query_port(ibdev, port, props);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	return err;
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cistatic int mlx4_ib_query_port(struct ib_device *ibdev, u32 port,
82762306a36Sopenharmony_ci			      struct ib_port_attr *props)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	/* returns host view */
83062306a36Sopenharmony_ci	return __mlx4_ib_query_port(ibdev, port, props, 0);
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ciint __mlx4_ib_query_gid(struct ib_device *ibdev, u32 port, int index,
83462306a36Sopenharmony_ci			union ib_gid *gid, int netw_view)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	struct ib_smp *in_mad;
83762306a36Sopenharmony_ci	struct ib_smp *out_mad;
83862306a36Sopenharmony_ci	int err = -ENOMEM;
83962306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(ibdev);
84062306a36Sopenharmony_ci	int clear = 0;
84162306a36Sopenharmony_ci	int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
84462306a36Sopenharmony_ci	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
84562306a36Sopenharmony_ci	if (!in_mad || !out_mad)
84662306a36Sopenharmony_ci		goto out;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	ib_init_query_mad(in_mad);
84962306a36Sopenharmony_ci	in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
85062306a36Sopenharmony_ci	in_mad->attr_mod = cpu_to_be32(port);
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	if (mlx4_is_mfunc(dev->dev) && netw_view)
85362306a36Sopenharmony_ci		mad_ifc_flags |= MLX4_MAD_IFC_NET_VIEW;
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	err = mlx4_MAD_IFC(dev, mad_ifc_flags, port, NULL, NULL, in_mad, out_mad);
85662306a36Sopenharmony_ci	if (err)
85762306a36Sopenharmony_ci		goto out;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	memcpy(gid->raw, out_mad->data + 8, 8);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	if (mlx4_is_mfunc(dev->dev) && !netw_view) {
86262306a36Sopenharmony_ci		if (index) {
86362306a36Sopenharmony_ci			/* For any index > 0, return the null guid */
86462306a36Sopenharmony_ci			err = 0;
86562306a36Sopenharmony_ci			clear = 1;
86662306a36Sopenharmony_ci			goto out;
86762306a36Sopenharmony_ci		}
86862306a36Sopenharmony_ci	}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	ib_init_query_mad(in_mad);
87162306a36Sopenharmony_ci	in_mad->attr_id  = IB_SMP_ATTR_GUID_INFO;
87262306a36Sopenharmony_ci	in_mad->attr_mod = cpu_to_be32(index / 8);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	err = mlx4_MAD_IFC(dev, mad_ifc_flags, port,
87562306a36Sopenharmony_ci			   NULL, NULL, in_mad, out_mad);
87662306a36Sopenharmony_ci	if (err)
87762306a36Sopenharmony_ci		goto out;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	memcpy(gid->raw + 8, out_mad->data + (index % 8) * 8, 8);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ciout:
88262306a36Sopenharmony_ci	if (clear)
88362306a36Sopenharmony_ci		memset(gid->raw + 8, 0, 8);
88462306a36Sopenharmony_ci	kfree(in_mad);
88562306a36Sopenharmony_ci	kfree(out_mad);
88662306a36Sopenharmony_ci	return err;
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic int mlx4_ib_query_gid(struct ib_device *ibdev, u32 port, int index,
89062306a36Sopenharmony_ci			     union ib_gid *gid)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	if (rdma_protocol_ib(ibdev, port))
89362306a36Sopenharmony_ci		return __mlx4_ib_query_gid(ibdev, port, index, gid, 0);
89462306a36Sopenharmony_ci	return 0;
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_cistatic int mlx4_ib_query_sl2vl(struct ib_device *ibdev, u32 port,
89862306a36Sopenharmony_ci			       u64 *sl2vl_tbl)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	union sl2vl_tbl_to_u64 sl2vl64;
90162306a36Sopenharmony_ci	struct ib_smp *in_mad;
90262306a36Sopenharmony_ci	struct ib_smp *out_mad;
90362306a36Sopenharmony_ci	int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS;
90462306a36Sopenharmony_ci	int err = -ENOMEM;
90562306a36Sopenharmony_ci	int jj;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	if (mlx4_is_slave(to_mdev(ibdev)->dev)) {
90862306a36Sopenharmony_ci		*sl2vl_tbl = 0;
90962306a36Sopenharmony_ci		return 0;
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	in_mad  = kzalloc(sizeof(*in_mad), GFP_KERNEL);
91362306a36Sopenharmony_ci	out_mad = kmalloc(sizeof(*out_mad), GFP_KERNEL);
91462306a36Sopenharmony_ci	if (!in_mad || !out_mad)
91562306a36Sopenharmony_ci		goto out;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	ib_init_query_mad(in_mad);
91862306a36Sopenharmony_ci	in_mad->attr_id  = IB_SMP_ATTR_SL_TO_VL_TABLE;
91962306a36Sopenharmony_ci	in_mad->attr_mod = 0;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	if (mlx4_is_mfunc(to_mdev(ibdev)->dev))
92262306a36Sopenharmony_ci		mad_ifc_flags |= MLX4_MAD_IFC_NET_VIEW;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	err = mlx4_MAD_IFC(to_mdev(ibdev), mad_ifc_flags, port, NULL, NULL,
92562306a36Sopenharmony_ci			   in_mad, out_mad);
92662306a36Sopenharmony_ci	if (err)
92762306a36Sopenharmony_ci		goto out;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	for (jj = 0; jj < 8; jj++)
93062306a36Sopenharmony_ci		sl2vl64.sl8[jj] = ((struct ib_smp *)out_mad)->data[jj];
93162306a36Sopenharmony_ci	*sl2vl_tbl = sl2vl64.sl64;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ciout:
93462306a36Sopenharmony_ci	kfree(in_mad);
93562306a36Sopenharmony_ci	kfree(out_mad);
93662306a36Sopenharmony_ci	return err;
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cistatic void mlx4_init_sl2vl_tbl(struct mlx4_ib_dev *mdev)
94062306a36Sopenharmony_ci{
94162306a36Sopenharmony_ci	u64 sl2vl;
94262306a36Sopenharmony_ci	int i;
94362306a36Sopenharmony_ci	int err;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	for (i = 1; i <= mdev->dev->caps.num_ports; i++) {
94662306a36Sopenharmony_ci		if (mdev->dev->caps.port_type[i] == MLX4_PORT_TYPE_ETH)
94762306a36Sopenharmony_ci			continue;
94862306a36Sopenharmony_ci		err = mlx4_ib_query_sl2vl(&mdev->ib_dev, i, &sl2vl);
94962306a36Sopenharmony_ci		if (err) {
95062306a36Sopenharmony_ci			pr_err("Unable to get default sl to vl mapping for port %d.  Using all zeroes (%d)\n",
95162306a36Sopenharmony_ci			       i, err);
95262306a36Sopenharmony_ci			sl2vl = 0;
95362306a36Sopenharmony_ci		}
95462306a36Sopenharmony_ci		atomic64_set(&mdev->sl2vl[i - 1], sl2vl);
95562306a36Sopenharmony_ci	}
95662306a36Sopenharmony_ci}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ciint __mlx4_ib_query_pkey(struct ib_device *ibdev, u32 port, u16 index,
95962306a36Sopenharmony_ci			 u16 *pkey, int netw_view)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	struct ib_smp *in_mad;
96262306a36Sopenharmony_ci	struct ib_smp *out_mad;
96362306a36Sopenharmony_ci	int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS;
96462306a36Sopenharmony_ci	int err = -ENOMEM;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
96762306a36Sopenharmony_ci	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
96862306a36Sopenharmony_ci	if (!in_mad || !out_mad)
96962306a36Sopenharmony_ci		goto out;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	ib_init_query_mad(in_mad);
97262306a36Sopenharmony_ci	in_mad->attr_id  = IB_SMP_ATTR_PKEY_TABLE;
97362306a36Sopenharmony_ci	in_mad->attr_mod = cpu_to_be32(index / 32);
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (mlx4_is_mfunc(to_mdev(ibdev)->dev) && netw_view)
97662306a36Sopenharmony_ci		mad_ifc_flags |= MLX4_MAD_IFC_NET_VIEW;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	err = mlx4_MAD_IFC(to_mdev(ibdev), mad_ifc_flags, port, NULL, NULL,
97962306a36Sopenharmony_ci			   in_mad, out_mad);
98062306a36Sopenharmony_ci	if (err)
98162306a36Sopenharmony_ci		goto out;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	*pkey = be16_to_cpu(((__be16 *) out_mad->data)[index % 32]);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ciout:
98662306a36Sopenharmony_ci	kfree(in_mad);
98762306a36Sopenharmony_ci	kfree(out_mad);
98862306a36Sopenharmony_ci	return err;
98962306a36Sopenharmony_ci}
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_cistatic int mlx4_ib_query_pkey(struct ib_device *ibdev, u32 port, u16 index,
99262306a36Sopenharmony_ci			      u16 *pkey)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	return __mlx4_ib_query_pkey(ibdev, port, index, pkey, 0);
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
99862306a36Sopenharmony_ci				 struct ib_device_modify *props)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
100162306a36Sopenharmony_ci	unsigned long flags;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
100462306a36Sopenharmony_ci		return -EOPNOTSUPP;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	if (!(mask & IB_DEVICE_MODIFY_NODE_DESC))
100762306a36Sopenharmony_ci		return 0;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	if (mlx4_is_slave(to_mdev(ibdev)->dev))
101062306a36Sopenharmony_ci		return -EOPNOTSUPP;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	spin_lock_irqsave(&to_mdev(ibdev)->sm_lock, flags);
101362306a36Sopenharmony_ci	memcpy(ibdev->node_desc, props->node_desc, IB_DEVICE_NODE_DESC_MAX);
101462306a36Sopenharmony_ci	spin_unlock_irqrestore(&to_mdev(ibdev)->sm_lock, flags);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	/*
101762306a36Sopenharmony_ci	 * If possible, pass node desc to FW, so it can generate
101862306a36Sopenharmony_ci	 * a 144 trap.  If cmd fails, just ignore.
101962306a36Sopenharmony_ci	 */
102062306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(to_mdev(ibdev)->dev);
102162306a36Sopenharmony_ci	if (IS_ERR(mailbox))
102262306a36Sopenharmony_ci		return 0;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	memcpy(mailbox->buf, props->node_desc, IB_DEVICE_NODE_DESC_MAX);
102562306a36Sopenharmony_ci	mlx4_cmd(to_mdev(ibdev)->dev, mailbox->dma, 1, 0,
102662306a36Sopenharmony_ci		 MLX4_CMD_SET_NODE, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(to_mdev(ibdev)->dev, mailbox);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	return 0;
103162306a36Sopenharmony_ci}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_cistatic int mlx4_ib_SET_PORT(struct mlx4_ib_dev *dev, u32 port,
103462306a36Sopenharmony_ci			    int reset_qkey_viols, u32 cap_mask)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
103762306a36Sopenharmony_ci	int err;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(dev->dev);
104062306a36Sopenharmony_ci	if (IS_ERR(mailbox))
104162306a36Sopenharmony_ci		return PTR_ERR(mailbox);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	if (dev->dev->flags & MLX4_FLAG_OLD_PORT_CMDS) {
104462306a36Sopenharmony_ci		*(u8 *) mailbox->buf	     = !!reset_qkey_viols << 6;
104562306a36Sopenharmony_ci		((__be32 *) mailbox->buf)[2] = cpu_to_be32(cap_mask);
104662306a36Sopenharmony_ci	} else {
104762306a36Sopenharmony_ci		((u8 *) mailbox->buf)[3]     = !!reset_qkey_viols;
104862306a36Sopenharmony_ci		((__be32 *) mailbox->buf)[1] = cpu_to_be32(cap_mask);
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	err = mlx4_cmd(dev->dev, mailbox->dma, port, MLX4_SET_PORT_IB_OPCODE,
105262306a36Sopenharmony_ci		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
105362306a36Sopenharmony_ci		       MLX4_CMD_WRAPPED);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(dev->dev, mailbox);
105662306a36Sopenharmony_ci	return err;
105762306a36Sopenharmony_ci}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_cistatic int mlx4_ib_modify_port(struct ib_device *ibdev, u32 port, int mask,
106062306a36Sopenharmony_ci			       struct ib_port_modify *props)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	struct mlx4_ib_dev *mdev = to_mdev(ibdev);
106362306a36Sopenharmony_ci	u8 is_eth = mdev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH;
106462306a36Sopenharmony_ci	struct ib_port_attr attr;
106562306a36Sopenharmony_ci	u32 cap_mask;
106662306a36Sopenharmony_ci	int err;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	/* return OK if this is RoCE. CM calls ib_modify_port() regardless
106962306a36Sopenharmony_ci	 * of whether port link layer is ETH or IB. For ETH ports, qkey
107062306a36Sopenharmony_ci	 * violations and port capabilities are not meaningful.
107162306a36Sopenharmony_ci	 */
107262306a36Sopenharmony_ci	if (is_eth)
107362306a36Sopenharmony_ci		return 0;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	mutex_lock(&mdev->cap_mask_mutex);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	err = ib_query_port(ibdev, port, &attr);
107862306a36Sopenharmony_ci	if (err)
107962306a36Sopenharmony_ci		goto out;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	cap_mask = (attr.port_cap_flags | props->set_port_cap_mask) &
108262306a36Sopenharmony_ci		~props->clr_port_cap_mask;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	err = mlx4_ib_SET_PORT(mdev, port,
108562306a36Sopenharmony_ci			       !!(mask & IB_PORT_RESET_QKEY_CNTR),
108662306a36Sopenharmony_ci			       cap_mask);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ciout:
108962306a36Sopenharmony_ci	mutex_unlock(&to_mdev(ibdev)->cap_mask_mutex);
109062306a36Sopenharmony_ci	return err;
109162306a36Sopenharmony_ci}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_cistatic int mlx4_ib_alloc_ucontext(struct ib_ucontext *uctx,
109462306a36Sopenharmony_ci				  struct ib_udata *udata)
109562306a36Sopenharmony_ci{
109662306a36Sopenharmony_ci	struct ib_device *ibdev = uctx->device;
109762306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(ibdev);
109862306a36Sopenharmony_ci	struct mlx4_ib_ucontext *context = to_mucontext(uctx);
109962306a36Sopenharmony_ci	struct mlx4_ib_alloc_ucontext_resp_v3 resp_v3;
110062306a36Sopenharmony_ci	struct mlx4_ib_alloc_ucontext_resp resp;
110162306a36Sopenharmony_ci	int err;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	if (!dev->ib_active)
110462306a36Sopenharmony_ci		return -EAGAIN;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	if (ibdev->ops.uverbs_abi_ver ==
110762306a36Sopenharmony_ci	    MLX4_IB_UVERBS_NO_DEV_CAPS_ABI_VERSION) {
110862306a36Sopenharmony_ci		resp_v3.qp_tab_size      = dev->dev->caps.num_qps;
110962306a36Sopenharmony_ci		resp_v3.bf_reg_size      = dev->dev->caps.bf_reg_size;
111062306a36Sopenharmony_ci		resp_v3.bf_regs_per_page = dev->dev->caps.bf_regs_per_page;
111162306a36Sopenharmony_ci	} else {
111262306a36Sopenharmony_ci		resp.dev_caps	      = dev->dev->caps.userspace_caps;
111362306a36Sopenharmony_ci		resp.qp_tab_size      = dev->dev->caps.num_qps;
111462306a36Sopenharmony_ci		resp.bf_reg_size      = dev->dev->caps.bf_reg_size;
111562306a36Sopenharmony_ci		resp.bf_regs_per_page = dev->dev->caps.bf_regs_per_page;
111662306a36Sopenharmony_ci		resp.cqe_size	      = dev->dev->caps.cqe_size;
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	err = mlx4_uar_alloc(to_mdev(ibdev)->dev, &context->uar);
112062306a36Sopenharmony_ci	if (err)
112162306a36Sopenharmony_ci		return err;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	INIT_LIST_HEAD(&context->db_page_list);
112462306a36Sopenharmony_ci	mutex_init(&context->db_page_mutex);
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	INIT_LIST_HEAD(&context->wqn_ranges_list);
112762306a36Sopenharmony_ci	mutex_init(&context->wqn_ranges_mutex);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	if (ibdev->ops.uverbs_abi_ver == MLX4_IB_UVERBS_NO_DEV_CAPS_ABI_VERSION)
113062306a36Sopenharmony_ci		err = ib_copy_to_udata(udata, &resp_v3, sizeof(resp_v3));
113162306a36Sopenharmony_ci	else
113262306a36Sopenharmony_ci		err = ib_copy_to_udata(udata, &resp, sizeof(resp));
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	if (err) {
113562306a36Sopenharmony_ci		mlx4_uar_free(to_mdev(ibdev)->dev, &context->uar);
113662306a36Sopenharmony_ci		return -EFAULT;
113762306a36Sopenharmony_ci	}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	return err;
114062306a36Sopenharmony_ci}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_cistatic void mlx4_ib_dealloc_ucontext(struct ib_ucontext *ibcontext)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	struct mlx4_ib_ucontext *context = to_mucontext(ibcontext);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	mlx4_uar_free(to_mdev(ibcontext->device)->dev, &context->uar);
114762306a36Sopenharmony_ci}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_cistatic void mlx4_ib_disassociate_ucontext(struct ib_ucontext *ibcontext)
115062306a36Sopenharmony_ci{
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_cistatic int mlx4_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
115462306a36Sopenharmony_ci{
115562306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(context->device);
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	switch (vma->vm_pgoff) {
115862306a36Sopenharmony_ci	case 0:
115962306a36Sopenharmony_ci		return rdma_user_mmap_io(context, vma,
116062306a36Sopenharmony_ci					 to_mucontext(context)->uar.pfn,
116162306a36Sopenharmony_ci					 PAGE_SIZE,
116262306a36Sopenharmony_ci					 pgprot_noncached(vma->vm_page_prot),
116362306a36Sopenharmony_ci					 NULL);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	case 1:
116662306a36Sopenharmony_ci		if (dev->dev->caps.bf_reg_size == 0)
116762306a36Sopenharmony_ci			return -EINVAL;
116862306a36Sopenharmony_ci		return rdma_user_mmap_io(
116962306a36Sopenharmony_ci			context, vma,
117062306a36Sopenharmony_ci			to_mucontext(context)->uar.pfn +
117162306a36Sopenharmony_ci				dev->dev->caps.num_uars,
117262306a36Sopenharmony_ci			PAGE_SIZE, pgprot_writecombine(vma->vm_page_prot),
117362306a36Sopenharmony_ci			NULL);
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	case 3: {
117662306a36Sopenharmony_ci		struct mlx4_clock_params params;
117762306a36Sopenharmony_ci		int ret;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci		ret = mlx4_get_internal_clock_params(dev->dev, &params);
118062306a36Sopenharmony_ci		if (ret)
118162306a36Sopenharmony_ci			return ret;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci		return rdma_user_mmap_io(
118462306a36Sopenharmony_ci			context, vma,
118562306a36Sopenharmony_ci			(pci_resource_start(dev->dev->persist->pdev,
118662306a36Sopenharmony_ci					    params.bar) +
118762306a36Sopenharmony_ci			 params.offset) >>
118862306a36Sopenharmony_ci				PAGE_SHIFT,
118962306a36Sopenharmony_ci			PAGE_SIZE, pgprot_noncached(vma->vm_page_prot),
119062306a36Sopenharmony_ci			NULL);
119162306a36Sopenharmony_ci	}
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	default:
119462306a36Sopenharmony_ci		return -EINVAL;
119562306a36Sopenharmony_ci	}
119662306a36Sopenharmony_ci}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_cistatic int mlx4_ib_alloc_pd(struct ib_pd *ibpd, struct ib_udata *udata)
119962306a36Sopenharmony_ci{
120062306a36Sopenharmony_ci	struct mlx4_ib_pd *pd = to_mpd(ibpd);
120162306a36Sopenharmony_ci	struct ib_device *ibdev = ibpd->device;
120262306a36Sopenharmony_ci	int err;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	err = mlx4_pd_alloc(to_mdev(ibdev)->dev, &pd->pdn);
120562306a36Sopenharmony_ci	if (err)
120662306a36Sopenharmony_ci		return err;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	if (udata && ib_copy_to_udata(udata, &pd->pdn, sizeof(__u32))) {
120962306a36Sopenharmony_ci		mlx4_pd_free(to_mdev(ibdev)->dev, pd->pdn);
121062306a36Sopenharmony_ci		return -EFAULT;
121162306a36Sopenharmony_ci	}
121262306a36Sopenharmony_ci	return 0;
121362306a36Sopenharmony_ci}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cistatic int mlx4_ib_dealloc_pd(struct ib_pd *pd, struct ib_udata *udata)
121662306a36Sopenharmony_ci{
121762306a36Sopenharmony_ci	mlx4_pd_free(to_mdev(pd->device)->dev, to_mpd(pd)->pdn);
121862306a36Sopenharmony_ci	return 0;
121962306a36Sopenharmony_ci}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_cistatic int mlx4_ib_alloc_xrcd(struct ib_xrcd *ibxrcd, struct ib_udata *udata)
122262306a36Sopenharmony_ci{
122362306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(ibxrcd->device);
122462306a36Sopenharmony_ci	struct mlx4_ib_xrcd *xrcd = to_mxrcd(ibxrcd);
122562306a36Sopenharmony_ci	struct ib_cq_init_attr cq_attr = {};
122662306a36Sopenharmony_ci	int err;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	if (!(dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC))
122962306a36Sopenharmony_ci		return -EOPNOTSUPP;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	err = mlx4_xrcd_alloc(dev->dev, &xrcd->xrcdn);
123262306a36Sopenharmony_ci	if (err)
123362306a36Sopenharmony_ci		return err;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	xrcd->pd = ib_alloc_pd(ibxrcd->device, 0);
123662306a36Sopenharmony_ci	if (IS_ERR(xrcd->pd)) {
123762306a36Sopenharmony_ci		err = PTR_ERR(xrcd->pd);
123862306a36Sopenharmony_ci		goto err2;
123962306a36Sopenharmony_ci	}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	cq_attr.cqe = 1;
124262306a36Sopenharmony_ci	xrcd->cq = ib_create_cq(ibxrcd->device, NULL, NULL, xrcd, &cq_attr);
124362306a36Sopenharmony_ci	if (IS_ERR(xrcd->cq)) {
124462306a36Sopenharmony_ci		err = PTR_ERR(xrcd->cq);
124562306a36Sopenharmony_ci		goto err3;
124662306a36Sopenharmony_ci	}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	return 0;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_cierr3:
125162306a36Sopenharmony_ci	ib_dealloc_pd(xrcd->pd);
125262306a36Sopenharmony_cierr2:
125362306a36Sopenharmony_ci	mlx4_xrcd_free(dev->dev, xrcd->xrcdn);
125462306a36Sopenharmony_ci	return err;
125562306a36Sopenharmony_ci}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_cistatic int mlx4_ib_dealloc_xrcd(struct ib_xrcd *xrcd, struct ib_udata *udata)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	ib_destroy_cq(to_mxrcd(xrcd)->cq);
126062306a36Sopenharmony_ci	ib_dealloc_pd(to_mxrcd(xrcd)->pd);
126162306a36Sopenharmony_ci	mlx4_xrcd_free(to_mdev(xrcd->device)->dev, to_mxrcd(xrcd)->xrcdn);
126262306a36Sopenharmony_ci	return 0;
126362306a36Sopenharmony_ci}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_cistatic int add_gid_entry(struct ib_qp *ibqp, union ib_gid *gid)
126662306a36Sopenharmony_ci{
126762306a36Sopenharmony_ci	struct mlx4_ib_qp *mqp = to_mqp(ibqp);
126862306a36Sopenharmony_ci	struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
126962306a36Sopenharmony_ci	struct mlx4_ib_gid_entry *ge;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	ge = kzalloc(sizeof *ge, GFP_KERNEL);
127262306a36Sopenharmony_ci	if (!ge)
127362306a36Sopenharmony_ci		return -ENOMEM;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	ge->gid = *gid;
127662306a36Sopenharmony_ci	if (mlx4_ib_add_mc(mdev, mqp, gid)) {
127762306a36Sopenharmony_ci		ge->port = mqp->port;
127862306a36Sopenharmony_ci		ge->added = 1;
127962306a36Sopenharmony_ci	}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	mutex_lock(&mqp->mutex);
128262306a36Sopenharmony_ci	list_add_tail(&ge->list, &mqp->gid_list);
128362306a36Sopenharmony_ci	mutex_unlock(&mqp->mutex);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	return 0;
128662306a36Sopenharmony_ci}
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_cistatic void mlx4_ib_delete_counters_table(struct mlx4_ib_dev *ibdev,
128962306a36Sopenharmony_ci					  struct mlx4_ib_counters *ctr_table)
129062306a36Sopenharmony_ci{
129162306a36Sopenharmony_ci	struct counter_index *counter, *tmp_count;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	mutex_lock(&ctr_table->mutex);
129462306a36Sopenharmony_ci	list_for_each_entry_safe(counter, tmp_count, &ctr_table->counters_list,
129562306a36Sopenharmony_ci				 list) {
129662306a36Sopenharmony_ci		if (counter->allocated)
129762306a36Sopenharmony_ci			mlx4_counter_free(ibdev->dev, counter->index);
129862306a36Sopenharmony_ci		list_del(&counter->list);
129962306a36Sopenharmony_ci		kfree(counter);
130062306a36Sopenharmony_ci	}
130162306a36Sopenharmony_ci	mutex_unlock(&ctr_table->mutex);
130262306a36Sopenharmony_ci}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ciint mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
130562306a36Sopenharmony_ci		   union ib_gid *gid)
130662306a36Sopenharmony_ci{
130762306a36Sopenharmony_ci	struct net_device *ndev;
130862306a36Sopenharmony_ci	int ret = 0;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	if (!mqp->port)
131162306a36Sopenharmony_ci		return 0;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	spin_lock_bh(&mdev->iboe.lock);
131462306a36Sopenharmony_ci	ndev = mdev->iboe.netdevs[mqp->port - 1];
131562306a36Sopenharmony_ci	dev_hold(ndev);
131662306a36Sopenharmony_ci	spin_unlock_bh(&mdev->iboe.lock);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	if (ndev) {
131962306a36Sopenharmony_ci		ret = 1;
132062306a36Sopenharmony_ci		dev_put(ndev);
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	return ret;
132462306a36Sopenharmony_ci}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_cistruct mlx4_ib_steering {
132762306a36Sopenharmony_ci	struct list_head list;
132862306a36Sopenharmony_ci	struct mlx4_flow_reg_id reg_id;
132962306a36Sopenharmony_ci	union ib_gid gid;
133062306a36Sopenharmony_ci};
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci#define LAST_ETH_FIELD vlan_tag
133362306a36Sopenharmony_ci#define LAST_IB_FIELD sl
133462306a36Sopenharmony_ci#define LAST_IPV4_FIELD dst_ip
133562306a36Sopenharmony_ci#define LAST_TCP_UDP_FIELD src_port
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci/* Field is the last supported field */
133862306a36Sopenharmony_ci#define FIELDS_NOT_SUPPORTED(filter, field)\
133962306a36Sopenharmony_ci	memchr_inv((void *)&filter.field  +\
134062306a36Sopenharmony_ci		   sizeof(filter.field), 0,\
134162306a36Sopenharmony_ci		   sizeof(filter) -\
134262306a36Sopenharmony_ci		   offsetof(typeof(filter), field) -\
134362306a36Sopenharmony_ci		   sizeof(filter.field))
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_cistatic int parse_flow_attr(struct mlx4_dev *dev,
134662306a36Sopenharmony_ci			   u32 qp_num,
134762306a36Sopenharmony_ci			   union ib_flow_spec *ib_spec,
134862306a36Sopenharmony_ci			   struct _rule_hw *mlx4_spec)
134962306a36Sopenharmony_ci{
135062306a36Sopenharmony_ci	enum mlx4_net_trans_rule_id type;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	switch (ib_spec->type) {
135362306a36Sopenharmony_ci	case IB_FLOW_SPEC_ETH:
135462306a36Sopenharmony_ci		if (FIELDS_NOT_SUPPORTED(ib_spec->eth.mask, LAST_ETH_FIELD))
135562306a36Sopenharmony_ci			return -ENOTSUPP;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci		type = MLX4_NET_TRANS_RULE_ID_ETH;
135862306a36Sopenharmony_ci		memcpy(mlx4_spec->eth.dst_mac, ib_spec->eth.val.dst_mac,
135962306a36Sopenharmony_ci		       ETH_ALEN);
136062306a36Sopenharmony_ci		memcpy(mlx4_spec->eth.dst_mac_msk, ib_spec->eth.mask.dst_mac,
136162306a36Sopenharmony_ci		       ETH_ALEN);
136262306a36Sopenharmony_ci		mlx4_spec->eth.vlan_tag = ib_spec->eth.val.vlan_tag;
136362306a36Sopenharmony_ci		mlx4_spec->eth.vlan_tag_msk = ib_spec->eth.mask.vlan_tag;
136462306a36Sopenharmony_ci		break;
136562306a36Sopenharmony_ci	case IB_FLOW_SPEC_IB:
136662306a36Sopenharmony_ci		if (FIELDS_NOT_SUPPORTED(ib_spec->ib.mask, LAST_IB_FIELD))
136762306a36Sopenharmony_ci			return -ENOTSUPP;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci		type = MLX4_NET_TRANS_RULE_ID_IB;
137062306a36Sopenharmony_ci		mlx4_spec->ib.l3_qpn =
137162306a36Sopenharmony_ci			cpu_to_be32(qp_num);
137262306a36Sopenharmony_ci		mlx4_spec->ib.qpn_mask =
137362306a36Sopenharmony_ci			cpu_to_be32(MLX4_IB_FLOW_QPN_MASK);
137462306a36Sopenharmony_ci		break;
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	case IB_FLOW_SPEC_IPV4:
137862306a36Sopenharmony_ci		if (FIELDS_NOT_SUPPORTED(ib_spec->ipv4.mask, LAST_IPV4_FIELD))
137962306a36Sopenharmony_ci			return -ENOTSUPP;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci		type = MLX4_NET_TRANS_RULE_ID_IPV4;
138262306a36Sopenharmony_ci		mlx4_spec->ipv4.src_ip = ib_spec->ipv4.val.src_ip;
138362306a36Sopenharmony_ci		mlx4_spec->ipv4.src_ip_msk = ib_spec->ipv4.mask.src_ip;
138462306a36Sopenharmony_ci		mlx4_spec->ipv4.dst_ip = ib_spec->ipv4.val.dst_ip;
138562306a36Sopenharmony_ci		mlx4_spec->ipv4.dst_ip_msk = ib_spec->ipv4.mask.dst_ip;
138662306a36Sopenharmony_ci		break;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	case IB_FLOW_SPEC_TCP:
138962306a36Sopenharmony_ci	case IB_FLOW_SPEC_UDP:
139062306a36Sopenharmony_ci		if (FIELDS_NOT_SUPPORTED(ib_spec->tcp_udp.mask, LAST_TCP_UDP_FIELD))
139162306a36Sopenharmony_ci			return -ENOTSUPP;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci		type = ib_spec->type == IB_FLOW_SPEC_TCP ?
139462306a36Sopenharmony_ci					MLX4_NET_TRANS_RULE_ID_TCP :
139562306a36Sopenharmony_ci					MLX4_NET_TRANS_RULE_ID_UDP;
139662306a36Sopenharmony_ci		mlx4_spec->tcp_udp.dst_port = ib_spec->tcp_udp.val.dst_port;
139762306a36Sopenharmony_ci		mlx4_spec->tcp_udp.dst_port_msk = ib_spec->tcp_udp.mask.dst_port;
139862306a36Sopenharmony_ci		mlx4_spec->tcp_udp.src_port = ib_spec->tcp_udp.val.src_port;
139962306a36Sopenharmony_ci		mlx4_spec->tcp_udp.src_port_msk = ib_spec->tcp_udp.mask.src_port;
140062306a36Sopenharmony_ci		break;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	default:
140362306a36Sopenharmony_ci		return -EINVAL;
140462306a36Sopenharmony_ci	}
140562306a36Sopenharmony_ci	if (mlx4_map_sw_to_hw_steering_id(dev, type) < 0 ||
140662306a36Sopenharmony_ci	    mlx4_hw_rule_sz(dev, type) < 0)
140762306a36Sopenharmony_ci		return -EINVAL;
140862306a36Sopenharmony_ci	mlx4_spec->id = cpu_to_be16(mlx4_map_sw_to_hw_steering_id(dev, type));
140962306a36Sopenharmony_ci	mlx4_spec->size = mlx4_hw_rule_sz(dev, type) >> 2;
141062306a36Sopenharmony_ci	return mlx4_hw_rule_sz(dev, type);
141162306a36Sopenharmony_ci}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_cistruct default_rules {
141462306a36Sopenharmony_ci	__u32 mandatory_fields[IB_FLOW_SPEC_SUPPORT_LAYERS];
141562306a36Sopenharmony_ci	__u32 mandatory_not_fields[IB_FLOW_SPEC_SUPPORT_LAYERS];
141662306a36Sopenharmony_ci	__u32 rules_create_list[IB_FLOW_SPEC_SUPPORT_LAYERS];
141762306a36Sopenharmony_ci	__u8  link_layer;
141862306a36Sopenharmony_ci};
141962306a36Sopenharmony_cistatic const struct default_rules default_table[] = {
142062306a36Sopenharmony_ci	{
142162306a36Sopenharmony_ci		.mandatory_fields = {IB_FLOW_SPEC_IPV4},
142262306a36Sopenharmony_ci		.mandatory_not_fields = {IB_FLOW_SPEC_ETH},
142362306a36Sopenharmony_ci		.rules_create_list = {IB_FLOW_SPEC_IB},
142462306a36Sopenharmony_ci		.link_layer = IB_LINK_LAYER_INFINIBAND
142562306a36Sopenharmony_ci	}
142662306a36Sopenharmony_ci};
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_cistatic int __mlx4_ib_default_rules_match(struct ib_qp *qp,
142962306a36Sopenharmony_ci					 struct ib_flow_attr *flow_attr)
143062306a36Sopenharmony_ci{
143162306a36Sopenharmony_ci	int i, j, k;
143262306a36Sopenharmony_ci	void *ib_flow;
143362306a36Sopenharmony_ci	const struct default_rules *pdefault_rules = default_table;
143462306a36Sopenharmony_ci	u8 link_layer = rdma_port_get_link_layer(qp->device, flow_attr->port);
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(default_table); i++, pdefault_rules++) {
143762306a36Sopenharmony_ci		__u32 field_types[IB_FLOW_SPEC_SUPPORT_LAYERS];
143862306a36Sopenharmony_ci		memset(&field_types, 0, sizeof(field_types));
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci		if (link_layer != pdefault_rules->link_layer)
144162306a36Sopenharmony_ci			continue;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci		ib_flow = flow_attr + 1;
144462306a36Sopenharmony_ci		/* we assume the specs are sorted */
144562306a36Sopenharmony_ci		for (j = 0, k = 0; k < IB_FLOW_SPEC_SUPPORT_LAYERS &&
144662306a36Sopenharmony_ci		     j < flow_attr->num_of_specs; k++) {
144762306a36Sopenharmony_ci			union ib_flow_spec *current_flow =
144862306a36Sopenharmony_ci				(union ib_flow_spec *)ib_flow;
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci			/* same layer but different type */
145162306a36Sopenharmony_ci			if (((current_flow->type & IB_FLOW_SPEC_LAYER_MASK) ==
145262306a36Sopenharmony_ci			     (pdefault_rules->mandatory_fields[k] &
145362306a36Sopenharmony_ci			      IB_FLOW_SPEC_LAYER_MASK)) &&
145462306a36Sopenharmony_ci			    (current_flow->type !=
145562306a36Sopenharmony_ci			     pdefault_rules->mandatory_fields[k]))
145662306a36Sopenharmony_ci				goto out;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci			/* same layer, try match next one */
145962306a36Sopenharmony_ci			if (current_flow->type ==
146062306a36Sopenharmony_ci			    pdefault_rules->mandatory_fields[k]) {
146162306a36Sopenharmony_ci				j++;
146262306a36Sopenharmony_ci				ib_flow +=
146362306a36Sopenharmony_ci					((union ib_flow_spec *)ib_flow)->size;
146462306a36Sopenharmony_ci			}
146562306a36Sopenharmony_ci		}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci		ib_flow = flow_attr + 1;
146862306a36Sopenharmony_ci		for (j = 0; j < flow_attr->num_of_specs;
146962306a36Sopenharmony_ci		     j++, ib_flow += ((union ib_flow_spec *)ib_flow)->size)
147062306a36Sopenharmony_ci			for (k = 0; k < IB_FLOW_SPEC_SUPPORT_LAYERS; k++)
147162306a36Sopenharmony_ci				/* same layer and same type */
147262306a36Sopenharmony_ci				if (((union ib_flow_spec *)ib_flow)->type ==
147362306a36Sopenharmony_ci				    pdefault_rules->mandatory_not_fields[k])
147462306a36Sopenharmony_ci					goto out;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci		return i;
147762306a36Sopenharmony_ci	}
147862306a36Sopenharmony_ciout:
147962306a36Sopenharmony_ci	return -1;
148062306a36Sopenharmony_ci}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_cistatic int __mlx4_ib_create_default_rules(
148362306a36Sopenharmony_ci		struct mlx4_ib_dev *mdev,
148462306a36Sopenharmony_ci		struct ib_qp *qp,
148562306a36Sopenharmony_ci		const struct default_rules *pdefault_rules,
148662306a36Sopenharmony_ci		struct _rule_hw *mlx4_spec) {
148762306a36Sopenharmony_ci	int size = 0;
148862306a36Sopenharmony_ci	int i;
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pdefault_rules->rules_create_list); i++) {
149162306a36Sopenharmony_ci		union ib_flow_spec ib_spec = {};
149262306a36Sopenharmony_ci		int ret;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci		switch (pdefault_rules->rules_create_list[i]) {
149562306a36Sopenharmony_ci		case 0:
149662306a36Sopenharmony_ci			/* no rule */
149762306a36Sopenharmony_ci			continue;
149862306a36Sopenharmony_ci		case IB_FLOW_SPEC_IB:
149962306a36Sopenharmony_ci			ib_spec.type = IB_FLOW_SPEC_IB;
150062306a36Sopenharmony_ci			ib_spec.size = sizeof(struct ib_flow_spec_ib);
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci			break;
150362306a36Sopenharmony_ci		default:
150462306a36Sopenharmony_ci			/* invalid rule */
150562306a36Sopenharmony_ci			return -EINVAL;
150662306a36Sopenharmony_ci		}
150762306a36Sopenharmony_ci		/* We must put empty rule, qpn is being ignored */
150862306a36Sopenharmony_ci		ret = parse_flow_attr(mdev->dev, 0, &ib_spec,
150962306a36Sopenharmony_ci				      mlx4_spec);
151062306a36Sopenharmony_ci		if (ret < 0) {
151162306a36Sopenharmony_ci			pr_info("invalid parsing\n");
151262306a36Sopenharmony_ci			return -EINVAL;
151362306a36Sopenharmony_ci		}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci		mlx4_spec = (void *)mlx4_spec + ret;
151662306a36Sopenharmony_ci		size += ret;
151762306a36Sopenharmony_ci	}
151862306a36Sopenharmony_ci	return size;
151962306a36Sopenharmony_ci}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_cistatic int __mlx4_ib_create_flow(struct ib_qp *qp, struct ib_flow_attr *flow_attr,
152262306a36Sopenharmony_ci			  int domain,
152362306a36Sopenharmony_ci			  enum mlx4_net_trans_promisc_mode flow_type,
152462306a36Sopenharmony_ci			  u64 *reg_id)
152562306a36Sopenharmony_ci{
152662306a36Sopenharmony_ci	int ret, i;
152762306a36Sopenharmony_ci	int size = 0;
152862306a36Sopenharmony_ci	void *ib_flow;
152962306a36Sopenharmony_ci	struct mlx4_ib_dev *mdev = to_mdev(qp->device);
153062306a36Sopenharmony_ci	struct mlx4_cmd_mailbox *mailbox;
153162306a36Sopenharmony_ci	struct mlx4_net_trans_rule_hw_ctrl *ctrl;
153262306a36Sopenharmony_ci	int default_flow;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	if (flow_attr->priority > MLX4_IB_FLOW_MAX_PRIO) {
153562306a36Sopenharmony_ci		pr_err("Invalid priority value %d\n", flow_attr->priority);
153662306a36Sopenharmony_ci		return -EINVAL;
153762306a36Sopenharmony_ci	}
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	if (mlx4_map_sw_to_hw_steering_mode(mdev->dev, flow_type) < 0)
154062306a36Sopenharmony_ci		return -EINVAL;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	mailbox = mlx4_alloc_cmd_mailbox(mdev->dev);
154362306a36Sopenharmony_ci	if (IS_ERR(mailbox))
154462306a36Sopenharmony_ci		return PTR_ERR(mailbox);
154562306a36Sopenharmony_ci	ctrl = mailbox->buf;
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	ctrl->prio = cpu_to_be16(domain | flow_attr->priority);
154862306a36Sopenharmony_ci	ctrl->type = mlx4_map_sw_to_hw_steering_mode(mdev->dev, flow_type);
154962306a36Sopenharmony_ci	ctrl->port = flow_attr->port;
155062306a36Sopenharmony_ci	ctrl->qpn = cpu_to_be32(qp->qp_num);
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	ib_flow = flow_attr + 1;
155362306a36Sopenharmony_ci	size += sizeof(struct mlx4_net_trans_rule_hw_ctrl);
155462306a36Sopenharmony_ci	/* Add default flows */
155562306a36Sopenharmony_ci	default_flow = __mlx4_ib_default_rules_match(qp, flow_attr);
155662306a36Sopenharmony_ci	if (default_flow >= 0) {
155762306a36Sopenharmony_ci		ret = __mlx4_ib_create_default_rules(
155862306a36Sopenharmony_ci				mdev, qp, default_table + default_flow,
155962306a36Sopenharmony_ci				mailbox->buf + size);
156062306a36Sopenharmony_ci		if (ret < 0) {
156162306a36Sopenharmony_ci			mlx4_free_cmd_mailbox(mdev->dev, mailbox);
156262306a36Sopenharmony_ci			return -EINVAL;
156362306a36Sopenharmony_ci		}
156462306a36Sopenharmony_ci		size += ret;
156562306a36Sopenharmony_ci	}
156662306a36Sopenharmony_ci	for (i = 0; i < flow_attr->num_of_specs; i++) {
156762306a36Sopenharmony_ci		ret = parse_flow_attr(mdev->dev, qp->qp_num, ib_flow,
156862306a36Sopenharmony_ci				      mailbox->buf + size);
156962306a36Sopenharmony_ci		if (ret < 0) {
157062306a36Sopenharmony_ci			mlx4_free_cmd_mailbox(mdev->dev, mailbox);
157162306a36Sopenharmony_ci			return -EINVAL;
157262306a36Sopenharmony_ci		}
157362306a36Sopenharmony_ci		ib_flow += ((union ib_flow_spec *) ib_flow)->size;
157462306a36Sopenharmony_ci		size += ret;
157562306a36Sopenharmony_ci	}
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	if (mlx4_is_master(mdev->dev) && flow_type == MLX4_FS_REGULAR &&
157862306a36Sopenharmony_ci	    flow_attr->num_of_specs == 1) {
157962306a36Sopenharmony_ci		struct _rule_hw *rule_header = (struct _rule_hw *)(ctrl + 1);
158062306a36Sopenharmony_ci		enum ib_flow_spec_type header_spec =
158162306a36Sopenharmony_ci			((union ib_flow_spec *)(flow_attr + 1))->type;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci		if (header_spec == IB_FLOW_SPEC_ETH)
158462306a36Sopenharmony_ci			mlx4_handle_eth_header_mcast_prio(ctrl, rule_header);
158562306a36Sopenharmony_ci	}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	ret = mlx4_cmd_imm(mdev->dev, mailbox->dma, reg_id, size >> 2, 0,
158862306a36Sopenharmony_ci			   MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
158962306a36Sopenharmony_ci			   MLX4_CMD_NATIVE);
159062306a36Sopenharmony_ci	if (ret == -ENOMEM)
159162306a36Sopenharmony_ci		pr_err("mcg table is full. Fail to register network rule.\n");
159262306a36Sopenharmony_ci	else if (ret == -ENXIO)
159362306a36Sopenharmony_ci		pr_err("Device managed flow steering is disabled. Fail to register network rule.\n");
159462306a36Sopenharmony_ci	else if (ret)
159562306a36Sopenharmony_ci		pr_err("Invalid argument. Fail to register network rule.\n");
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	mlx4_free_cmd_mailbox(mdev->dev, mailbox);
159862306a36Sopenharmony_ci	return ret;
159962306a36Sopenharmony_ci}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_cistatic int __mlx4_ib_destroy_flow(struct mlx4_dev *dev, u64 reg_id)
160262306a36Sopenharmony_ci{
160362306a36Sopenharmony_ci	int err;
160462306a36Sopenharmony_ci	err = mlx4_cmd(dev, reg_id, 0, 0,
160562306a36Sopenharmony_ci		       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
160662306a36Sopenharmony_ci		       MLX4_CMD_NATIVE);
160762306a36Sopenharmony_ci	if (err)
160862306a36Sopenharmony_ci		pr_err("Fail to detach network rule. registration id = 0x%llx\n",
160962306a36Sopenharmony_ci		       reg_id);
161062306a36Sopenharmony_ci	return err;
161162306a36Sopenharmony_ci}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_cistatic int mlx4_ib_tunnel_steer_add(struct ib_qp *qp, struct ib_flow_attr *flow_attr,
161462306a36Sopenharmony_ci				    u64 *reg_id)
161562306a36Sopenharmony_ci{
161662306a36Sopenharmony_ci	void *ib_flow;
161762306a36Sopenharmony_ci	union ib_flow_spec *ib_spec;
161862306a36Sopenharmony_ci	struct mlx4_dev	*dev = to_mdev(qp->device)->dev;
161962306a36Sopenharmony_ci	int err = 0;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	if (dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN ||
162262306a36Sopenharmony_ci	    dev->caps.dmfs_high_steer_mode == MLX4_STEERING_DMFS_A0_STATIC)
162362306a36Sopenharmony_ci		return 0; /* do nothing */
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	ib_flow = flow_attr + 1;
162662306a36Sopenharmony_ci	ib_spec = (union ib_flow_spec *)ib_flow;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	if (ib_spec->type !=  IB_FLOW_SPEC_ETH || flow_attr->num_of_specs != 1)
162962306a36Sopenharmony_ci		return 0; /* do nothing */
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	err = mlx4_tunnel_steer_add(to_mdev(qp->device)->dev, ib_spec->eth.val.dst_mac,
163262306a36Sopenharmony_ci				    flow_attr->port, qp->qp_num,
163362306a36Sopenharmony_ci				    MLX4_DOMAIN_UVERBS | (flow_attr->priority & 0xff),
163462306a36Sopenharmony_ci				    reg_id);
163562306a36Sopenharmony_ci	return err;
163662306a36Sopenharmony_ci}
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_cistatic int mlx4_ib_add_dont_trap_rule(struct mlx4_dev *dev,
163962306a36Sopenharmony_ci				      struct ib_flow_attr *flow_attr,
164062306a36Sopenharmony_ci				      enum mlx4_net_trans_promisc_mode *type)
164162306a36Sopenharmony_ci{
164262306a36Sopenharmony_ci	int err = 0;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DMFS_UC_MC_SNIFFER) ||
164562306a36Sopenharmony_ci	    (dev->caps.dmfs_high_steer_mode == MLX4_STEERING_DMFS_A0_STATIC) ||
164662306a36Sopenharmony_ci	    (flow_attr->num_of_specs > 1) || (flow_attr->priority != 0)) {
164762306a36Sopenharmony_ci		return -EOPNOTSUPP;
164862306a36Sopenharmony_ci	}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	if (flow_attr->num_of_specs == 0) {
165162306a36Sopenharmony_ci		type[0] = MLX4_FS_MC_SNIFFER;
165262306a36Sopenharmony_ci		type[1] = MLX4_FS_UC_SNIFFER;
165362306a36Sopenharmony_ci	} else {
165462306a36Sopenharmony_ci		union ib_flow_spec *ib_spec;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci		ib_spec = (union ib_flow_spec *)(flow_attr + 1);
165762306a36Sopenharmony_ci		if (ib_spec->type !=  IB_FLOW_SPEC_ETH)
165862306a36Sopenharmony_ci			return -EINVAL;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci		/* if all is zero than MC and UC */
166162306a36Sopenharmony_ci		if (is_zero_ether_addr(ib_spec->eth.mask.dst_mac)) {
166262306a36Sopenharmony_ci			type[0] = MLX4_FS_MC_SNIFFER;
166362306a36Sopenharmony_ci			type[1] = MLX4_FS_UC_SNIFFER;
166462306a36Sopenharmony_ci		} else {
166562306a36Sopenharmony_ci			u8 mac[ETH_ALEN] = {ib_spec->eth.mask.dst_mac[0] ^ 0x01,
166662306a36Sopenharmony_ci					    ib_spec->eth.mask.dst_mac[1],
166762306a36Sopenharmony_ci					    ib_spec->eth.mask.dst_mac[2],
166862306a36Sopenharmony_ci					    ib_spec->eth.mask.dst_mac[3],
166962306a36Sopenharmony_ci					    ib_spec->eth.mask.dst_mac[4],
167062306a36Sopenharmony_ci					    ib_spec->eth.mask.dst_mac[5]};
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci			/* Above xor was only on MC bit, non empty mask is valid
167362306a36Sopenharmony_ci			 * only if this bit is set and rest are zero.
167462306a36Sopenharmony_ci			 */
167562306a36Sopenharmony_ci			if (!is_zero_ether_addr(&mac[0]))
167662306a36Sopenharmony_ci				return -EINVAL;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci			if (is_multicast_ether_addr(ib_spec->eth.val.dst_mac))
167962306a36Sopenharmony_ci				type[0] = MLX4_FS_MC_SNIFFER;
168062306a36Sopenharmony_ci			else
168162306a36Sopenharmony_ci				type[0] = MLX4_FS_UC_SNIFFER;
168262306a36Sopenharmony_ci		}
168362306a36Sopenharmony_ci	}
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	return err;
168662306a36Sopenharmony_ci}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_cistatic struct ib_flow *mlx4_ib_create_flow(struct ib_qp *qp,
168962306a36Sopenharmony_ci					   struct ib_flow_attr *flow_attr,
169062306a36Sopenharmony_ci					   struct ib_udata *udata)
169162306a36Sopenharmony_ci{
169262306a36Sopenharmony_ci	int err = 0, i = 0, j = 0;
169362306a36Sopenharmony_ci	struct mlx4_ib_flow *mflow;
169462306a36Sopenharmony_ci	enum mlx4_net_trans_promisc_mode type[2];
169562306a36Sopenharmony_ci	struct mlx4_dev *dev = (to_mdev(qp->device))->dev;
169662306a36Sopenharmony_ci	int is_bonded = mlx4_is_bonded(dev);
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	if (flow_attr->flags & ~IB_FLOW_ATTR_FLAGS_DONT_TRAP)
169962306a36Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	if ((flow_attr->flags & IB_FLOW_ATTR_FLAGS_DONT_TRAP) &&
170262306a36Sopenharmony_ci	    (flow_attr->type != IB_FLOW_ATTR_NORMAL))
170362306a36Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	if (udata &&
170662306a36Sopenharmony_ci	    udata->inlen && !ib_is_udata_cleared(udata, 0, udata->inlen))
170762306a36Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	memset(type, 0, sizeof(type));
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	mflow = kzalloc(sizeof(*mflow), GFP_KERNEL);
171262306a36Sopenharmony_ci	if (!mflow) {
171362306a36Sopenharmony_ci		err = -ENOMEM;
171462306a36Sopenharmony_ci		goto err_free;
171562306a36Sopenharmony_ci	}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	switch (flow_attr->type) {
171862306a36Sopenharmony_ci	case IB_FLOW_ATTR_NORMAL:
171962306a36Sopenharmony_ci		/* If dont trap flag (continue match) is set, under specific
172062306a36Sopenharmony_ci		 * condition traffic be replicated to given qp,
172162306a36Sopenharmony_ci		 * without stealing it
172262306a36Sopenharmony_ci		 */
172362306a36Sopenharmony_ci		if (unlikely(flow_attr->flags & IB_FLOW_ATTR_FLAGS_DONT_TRAP)) {
172462306a36Sopenharmony_ci			err = mlx4_ib_add_dont_trap_rule(dev,
172562306a36Sopenharmony_ci							 flow_attr,
172662306a36Sopenharmony_ci							 type);
172762306a36Sopenharmony_ci			if (err)
172862306a36Sopenharmony_ci				goto err_free;
172962306a36Sopenharmony_ci		} else {
173062306a36Sopenharmony_ci			type[0] = MLX4_FS_REGULAR;
173162306a36Sopenharmony_ci		}
173262306a36Sopenharmony_ci		break;
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	case IB_FLOW_ATTR_ALL_DEFAULT:
173562306a36Sopenharmony_ci		type[0] = MLX4_FS_ALL_DEFAULT;
173662306a36Sopenharmony_ci		break;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	case IB_FLOW_ATTR_MC_DEFAULT:
173962306a36Sopenharmony_ci		type[0] = MLX4_FS_MC_DEFAULT;
174062306a36Sopenharmony_ci		break;
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	case IB_FLOW_ATTR_SNIFFER:
174362306a36Sopenharmony_ci		type[0] = MLX4_FS_MIRROR_RX_PORT;
174462306a36Sopenharmony_ci		type[1] = MLX4_FS_MIRROR_SX_PORT;
174562306a36Sopenharmony_ci		break;
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	default:
174862306a36Sopenharmony_ci		err = -EINVAL;
174962306a36Sopenharmony_ci		goto err_free;
175062306a36Sopenharmony_ci	}
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	while (i < ARRAY_SIZE(type) && type[i]) {
175362306a36Sopenharmony_ci		err = __mlx4_ib_create_flow(qp, flow_attr, MLX4_DOMAIN_UVERBS,
175462306a36Sopenharmony_ci					    type[i], &mflow->reg_id[i].id);
175562306a36Sopenharmony_ci		if (err)
175662306a36Sopenharmony_ci			goto err_create_flow;
175762306a36Sopenharmony_ci		if (is_bonded) {
175862306a36Sopenharmony_ci			/* Application always sees one port so the mirror rule
175962306a36Sopenharmony_ci			 * must be on port #2
176062306a36Sopenharmony_ci			 */
176162306a36Sopenharmony_ci			flow_attr->port = 2;
176262306a36Sopenharmony_ci			err = __mlx4_ib_create_flow(qp, flow_attr,
176362306a36Sopenharmony_ci						    MLX4_DOMAIN_UVERBS, type[j],
176462306a36Sopenharmony_ci						    &mflow->reg_id[j].mirror);
176562306a36Sopenharmony_ci			flow_attr->port = 1;
176662306a36Sopenharmony_ci			if (err)
176762306a36Sopenharmony_ci				goto err_create_flow;
176862306a36Sopenharmony_ci			j++;
176962306a36Sopenharmony_ci		}
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci		i++;
177262306a36Sopenharmony_ci	}
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	if (i < ARRAY_SIZE(type) && flow_attr->type == IB_FLOW_ATTR_NORMAL) {
177562306a36Sopenharmony_ci		err = mlx4_ib_tunnel_steer_add(qp, flow_attr,
177662306a36Sopenharmony_ci					       &mflow->reg_id[i].id);
177762306a36Sopenharmony_ci		if (err)
177862306a36Sopenharmony_ci			goto err_create_flow;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci		if (is_bonded) {
178162306a36Sopenharmony_ci			flow_attr->port = 2;
178262306a36Sopenharmony_ci			err = mlx4_ib_tunnel_steer_add(qp, flow_attr,
178362306a36Sopenharmony_ci						       &mflow->reg_id[j].mirror);
178462306a36Sopenharmony_ci			flow_attr->port = 1;
178562306a36Sopenharmony_ci			if (err)
178662306a36Sopenharmony_ci				goto err_create_flow;
178762306a36Sopenharmony_ci			j++;
178862306a36Sopenharmony_ci		}
178962306a36Sopenharmony_ci		/* function to create mirror rule */
179062306a36Sopenharmony_ci		i++;
179162306a36Sopenharmony_ci	}
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	return &mflow->ibflow;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_cierr_create_flow:
179662306a36Sopenharmony_ci	while (i) {
179762306a36Sopenharmony_ci		(void)__mlx4_ib_destroy_flow(to_mdev(qp->device)->dev,
179862306a36Sopenharmony_ci					     mflow->reg_id[i].id);
179962306a36Sopenharmony_ci		i--;
180062306a36Sopenharmony_ci	}
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	while (j) {
180362306a36Sopenharmony_ci		(void)__mlx4_ib_destroy_flow(to_mdev(qp->device)->dev,
180462306a36Sopenharmony_ci					     mflow->reg_id[j].mirror);
180562306a36Sopenharmony_ci		j--;
180662306a36Sopenharmony_ci	}
180762306a36Sopenharmony_cierr_free:
180862306a36Sopenharmony_ci	kfree(mflow);
180962306a36Sopenharmony_ci	return ERR_PTR(err);
181062306a36Sopenharmony_ci}
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_cistatic int mlx4_ib_destroy_flow(struct ib_flow *flow_id)
181362306a36Sopenharmony_ci{
181462306a36Sopenharmony_ci	int err, ret = 0;
181562306a36Sopenharmony_ci	int i = 0;
181662306a36Sopenharmony_ci	struct mlx4_ib_dev *mdev = to_mdev(flow_id->qp->device);
181762306a36Sopenharmony_ci	struct mlx4_ib_flow *mflow = to_mflow(flow_id);
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	while (i < ARRAY_SIZE(mflow->reg_id) && mflow->reg_id[i].id) {
182062306a36Sopenharmony_ci		err = __mlx4_ib_destroy_flow(mdev->dev, mflow->reg_id[i].id);
182162306a36Sopenharmony_ci		if (err)
182262306a36Sopenharmony_ci			ret = err;
182362306a36Sopenharmony_ci		if (mflow->reg_id[i].mirror) {
182462306a36Sopenharmony_ci			err = __mlx4_ib_destroy_flow(mdev->dev,
182562306a36Sopenharmony_ci						     mflow->reg_id[i].mirror);
182662306a36Sopenharmony_ci			if (err)
182762306a36Sopenharmony_ci				ret = err;
182862306a36Sopenharmony_ci		}
182962306a36Sopenharmony_ci		i++;
183062306a36Sopenharmony_ci	}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	kfree(mflow);
183362306a36Sopenharmony_ci	return ret;
183462306a36Sopenharmony_ci}
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_cistatic int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
183762306a36Sopenharmony_ci{
183862306a36Sopenharmony_ci	int err;
183962306a36Sopenharmony_ci	struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
184062306a36Sopenharmony_ci	struct mlx4_dev	*dev = mdev->dev;
184162306a36Sopenharmony_ci	struct mlx4_ib_qp *mqp = to_mqp(ibqp);
184262306a36Sopenharmony_ci	struct mlx4_ib_steering *ib_steering = NULL;
184362306a36Sopenharmony_ci	enum mlx4_protocol prot = MLX4_PROT_IB_IPV6;
184462306a36Sopenharmony_ci	struct mlx4_flow_reg_id	reg_id;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	if (mdev->dev->caps.steering_mode ==
184762306a36Sopenharmony_ci	    MLX4_STEERING_MODE_DEVICE_MANAGED) {
184862306a36Sopenharmony_ci		ib_steering = kmalloc(sizeof(*ib_steering), GFP_KERNEL);
184962306a36Sopenharmony_ci		if (!ib_steering)
185062306a36Sopenharmony_ci			return -ENOMEM;
185162306a36Sopenharmony_ci	}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, mqp->port,
185462306a36Sopenharmony_ci				    !!(mqp->flags &
185562306a36Sopenharmony_ci				       MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK),
185662306a36Sopenharmony_ci				    prot, &reg_id.id);
185762306a36Sopenharmony_ci	if (err) {
185862306a36Sopenharmony_ci		pr_err("multicast attach op failed, err %d\n", err);
185962306a36Sopenharmony_ci		goto err_malloc;
186062306a36Sopenharmony_ci	}
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	reg_id.mirror = 0;
186362306a36Sopenharmony_ci	if (mlx4_is_bonded(dev)) {
186462306a36Sopenharmony_ci		err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw,
186562306a36Sopenharmony_ci					    (mqp->port == 1) ? 2 : 1,
186662306a36Sopenharmony_ci					    !!(mqp->flags &
186762306a36Sopenharmony_ci					    MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK),
186862306a36Sopenharmony_ci					    prot, &reg_id.mirror);
186962306a36Sopenharmony_ci		if (err)
187062306a36Sopenharmony_ci			goto err_add;
187162306a36Sopenharmony_ci	}
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	err = add_gid_entry(ibqp, gid);
187462306a36Sopenharmony_ci	if (err)
187562306a36Sopenharmony_ci		goto err_add;
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	if (ib_steering) {
187862306a36Sopenharmony_ci		memcpy(ib_steering->gid.raw, gid->raw, 16);
187962306a36Sopenharmony_ci		ib_steering->reg_id = reg_id;
188062306a36Sopenharmony_ci		mutex_lock(&mqp->mutex);
188162306a36Sopenharmony_ci		list_add(&ib_steering->list, &mqp->steering_rules);
188262306a36Sopenharmony_ci		mutex_unlock(&mqp->mutex);
188362306a36Sopenharmony_ci	}
188462306a36Sopenharmony_ci	return 0;
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_cierr_add:
188762306a36Sopenharmony_ci	mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw,
188862306a36Sopenharmony_ci			      prot, reg_id.id);
188962306a36Sopenharmony_ci	if (reg_id.mirror)
189062306a36Sopenharmony_ci		mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw,
189162306a36Sopenharmony_ci				      prot, reg_id.mirror);
189262306a36Sopenharmony_cierr_malloc:
189362306a36Sopenharmony_ci	kfree(ib_steering);
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	return err;
189662306a36Sopenharmony_ci}
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_cistatic struct mlx4_ib_gid_entry *find_gid_entry(struct mlx4_ib_qp *qp, u8 *raw)
189962306a36Sopenharmony_ci{
190062306a36Sopenharmony_ci	struct mlx4_ib_gid_entry *ge;
190162306a36Sopenharmony_ci	struct mlx4_ib_gid_entry *tmp;
190262306a36Sopenharmony_ci	struct mlx4_ib_gid_entry *ret = NULL;
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	list_for_each_entry_safe(ge, tmp, &qp->gid_list, list) {
190562306a36Sopenharmony_ci		if (!memcmp(raw, ge->gid.raw, 16)) {
190662306a36Sopenharmony_ci			ret = ge;
190762306a36Sopenharmony_ci			break;
190862306a36Sopenharmony_ci		}
190962306a36Sopenharmony_ci	}
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	return ret;
191262306a36Sopenharmony_ci}
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_cistatic int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
191562306a36Sopenharmony_ci{
191662306a36Sopenharmony_ci	int err;
191762306a36Sopenharmony_ci	struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
191862306a36Sopenharmony_ci	struct mlx4_dev *dev = mdev->dev;
191962306a36Sopenharmony_ci	struct mlx4_ib_qp *mqp = to_mqp(ibqp);
192062306a36Sopenharmony_ci	struct net_device *ndev;
192162306a36Sopenharmony_ci	struct mlx4_ib_gid_entry *ge;
192262306a36Sopenharmony_ci	struct mlx4_flow_reg_id reg_id = {0, 0};
192362306a36Sopenharmony_ci	enum mlx4_protocol prot =  MLX4_PROT_IB_IPV6;
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci	if (mdev->dev->caps.steering_mode ==
192662306a36Sopenharmony_ci	    MLX4_STEERING_MODE_DEVICE_MANAGED) {
192762306a36Sopenharmony_ci		struct mlx4_ib_steering *ib_steering;
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci		mutex_lock(&mqp->mutex);
193062306a36Sopenharmony_ci		list_for_each_entry(ib_steering, &mqp->steering_rules, list) {
193162306a36Sopenharmony_ci			if (!memcmp(ib_steering->gid.raw, gid->raw, 16)) {
193262306a36Sopenharmony_ci				list_del(&ib_steering->list);
193362306a36Sopenharmony_ci				break;
193462306a36Sopenharmony_ci			}
193562306a36Sopenharmony_ci		}
193662306a36Sopenharmony_ci		mutex_unlock(&mqp->mutex);
193762306a36Sopenharmony_ci		if (&ib_steering->list == &mqp->steering_rules) {
193862306a36Sopenharmony_ci			pr_err("Couldn't find reg_id for mgid. Steering rule is left attached\n");
193962306a36Sopenharmony_ci			return -EINVAL;
194062306a36Sopenharmony_ci		}
194162306a36Sopenharmony_ci		reg_id = ib_steering->reg_id;
194262306a36Sopenharmony_ci		kfree(ib_steering);
194362306a36Sopenharmony_ci	}
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	err = mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw,
194662306a36Sopenharmony_ci				    prot, reg_id.id);
194762306a36Sopenharmony_ci	if (err)
194862306a36Sopenharmony_ci		return err;
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	if (mlx4_is_bonded(dev)) {
195162306a36Sopenharmony_ci		err = mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw,
195262306a36Sopenharmony_ci					    prot, reg_id.mirror);
195362306a36Sopenharmony_ci		if (err)
195462306a36Sopenharmony_ci			return err;
195562306a36Sopenharmony_ci	}
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	mutex_lock(&mqp->mutex);
195862306a36Sopenharmony_ci	ge = find_gid_entry(mqp, gid->raw);
195962306a36Sopenharmony_ci	if (ge) {
196062306a36Sopenharmony_ci		spin_lock_bh(&mdev->iboe.lock);
196162306a36Sopenharmony_ci		ndev = ge->added ? mdev->iboe.netdevs[ge->port - 1] : NULL;
196262306a36Sopenharmony_ci		dev_hold(ndev);
196362306a36Sopenharmony_ci		spin_unlock_bh(&mdev->iboe.lock);
196462306a36Sopenharmony_ci		dev_put(ndev);
196562306a36Sopenharmony_ci		list_del(&ge->list);
196662306a36Sopenharmony_ci		kfree(ge);
196762306a36Sopenharmony_ci	} else
196862306a36Sopenharmony_ci		pr_warn("could not find mgid entry\n");
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	mutex_unlock(&mqp->mutex);
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	return 0;
197362306a36Sopenharmony_ci}
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_cistatic int init_node_data(struct mlx4_ib_dev *dev)
197662306a36Sopenharmony_ci{
197762306a36Sopenharmony_ci	struct ib_smp *in_mad;
197862306a36Sopenharmony_ci	struct ib_smp *out_mad;
197962306a36Sopenharmony_ci	int mad_ifc_flags = MLX4_MAD_IFC_IGNORE_KEYS;
198062306a36Sopenharmony_ci	int err = -ENOMEM;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
198362306a36Sopenharmony_ci	out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
198462306a36Sopenharmony_ci	if (!in_mad || !out_mad)
198562306a36Sopenharmony_ci		goto out;
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	ib_init_query_mad(in_mad);
198862306a36Sopenharmony_ci	in_mad->attr_id = IB_SMP_ATTR_NODE_DESC;
198962306a36Sopenharmony_ci	if (mlx4_is_master(dev->dev))
199062306a36Sopenharmony_ci		mad_ifc_flags |= MLX4_MAD_IFC_NET_VIEW;
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	err = mlx4_MAD_IFC(dev, mad_ifc_flags, 1, NULL, NULL, in_mad, out_mad);
199362306a36Sopenharmony_ci	if (err)
199462306a36Sopenharmony_ci		goto out;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	memcpy(dev->ib_dev.node_desc, out_mad->data, IB_DEVICE_NODE_DESC_MAX);
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	err = mlx4_MAD_IFC(dev, mad_ifc_flags, 1, NULL, NULL, in_mad, out_mad);
200162306a36Sopenharmony_ci	if (err)
200262306a36Sopenharmony_ci		goto out;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	dev->dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32));
200562306a36Sopenharmony_ci	memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ciout:
200862306a36Sopenharmony_ci	kfree(in_mad);
200962306a36Sopenharmony_ci	kfree(out_mad);
201062306a36Sopenharmony_ci	return err;
201162306a36Sopenharmony_ci}
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_cistatic ssize_t hca_type_show(struct device *device,
201462306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
201562306a36Sopenharmony_ci{
201662306a36Sopenharmony_ci	struct mlx4_ib_dev *dev =
201762306a36Sopenharmony_ci		rdma_device_to_drv_device(device, struct mlx4_ib_dev, ib_dev);
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	return sysfs_emit(buf, "MT%d\n", dev->dev->persist->pdev->device);
202062306a36Sopenharmony_ci}
202162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(hca_type);
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_cistatic ssize_t hw_rev_show(struct device *device,
202462306a36Sopenharmony_ci			   struct device_attribute *attr, char *buf)
202562306a36Sopenharmony_ci{
202662306a36Sopenharmony_ci	struct mlx4_ib_dev *dev =
202762306a36Sopenharmony_ci		rdma_device_to_drv_device(device, struct mlx4_ib_dev, ib_dev);
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	return sysfs_emit(buf, "%x\n", dev->dev->rev_id);
203062306a36Sopenharmony_ci}
203162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(hw_rev);
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_cistatic ssize_t board_id_show(struct device *device,
203462306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
203562306a36Sopenharmony_ci{
203662306a36Sopenharmony_ci	struct mlx4_ib_dev *dev =
203762306a36Sopenharmony_ci		rdma_device_to_drv_device(device, struct mlx4_ib_dev, ib_dev);
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	return sysfs_emit(buf, "%.*s\n", MLX4_BOARD_ID_LEN, dev->dev->board_id);
204062306a36Sopenharmony_ci}
204162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(board_id);
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_cistatic struct attribute *mlx4_class_attributes[] = {
204462306a36Sopenharmony_ci	&dev_attr_hw_rev.attr,
204562306a36Sopenharmony_ci	&dev_attr_hca_type.attr,
204662306a36Sopenharmony_ci	&dev_attr_board_id.attr,
204762306a36Sopenharmony_ci	NULL
204862306a36Sopenharmony_ci};
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_cistatic const struct attribute_group mlx4_attr_group = {
205162306a36Sopenharmony_ci	.attrs = mlx4_class_attributes,
205262306a36Sopenharmony_ci};
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_cistruct diag_counter {
205562306a36Sopenharmony_ci	const char *name;
205662306a36Sopenharmony_ci	u32 offset;
205762306a36Sopenharmony_ci};
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci#define DIAG_COUNTER(_name, _offset)			\
206062306a36Sopenharmony_ci	{ .name = #_name, .offset = _offset }
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_cistatic const struct diag_counter diag_basic[] = {
206362306a36Sopenharmony_ci	DIAG_COUNTER(rq_num_lle, 0x00),
206462306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_lle, 0x04),
206562306a36Sopenharmony_ci	DIAG_COUNTER(rq_num_lqpoe, 0x08),
206662306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_lqpoe, 0x0C),
206762306a36Sopenharmony_ci	DIAG_COUNTER(rq_num_lpe, 0x18),
206862306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_lpe, 0x1C),
206962306a36Sopenharmony_ci	DIAG_COUNTER(rq_num_wrfe, 0x20),
207062306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_wrfe, 0x24),
207162306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_mwbe, 0x2C),
207262306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_bre, 0x34),
207362306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_rire, 0x44),
207462306a36Sopenharmony_ci	DIAG_COUNTER(rq_num_rire, 0x48),
207562306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_rae, 0x4C),
207662306a36Sopenharmony_ci	DIAG_COUNTER(rq_num_rae, 0x50),
207762306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_roe, 0x54),
207862306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_tree, 0x5C),
207962306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_rree, 0x64),
208062306a36Sopenharmony_ci	DIAG_COUNTER(rq_num_rnr, 0x68),
208162306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_rnr, 0x6C),
208262306a36Sopenharmony_ci	DIAG_COUNTER(rq_num_oos, 0x100),
208362306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_oos, 0x104),
208462306a36Sopenharmony_ci};
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_cistatic const struct diag_counter diag_ext[] = {
208762306a36Sopenharmony_ci	DIAG_COUNTER(rq_num_dup, 0x130),
208862306a36Sopenharmony_ci	DIAG_COUNTER(sq_num_to, 0x134),
208962306a36Sopenharmony_ci};
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_cistatic const struct diag_counter diag_device_only[] = {
209262306a36Sopenharmony_ci	DIAG_COUNTER(num_cqovf, 0x1A0),
209362306a36Sopenharmony_ci	DIAG_COUNTER(rq_num_udsdprd, 0x118),
209462306a36Sopenharmony_ci};
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_cistatic struct rdma_hw_stats *
209762306a36Sopenharmony_cimlx4_ib_alloc_hw_device_stats(struct ib_device *ibdev)
209862306a36Sopenharmony_ci{
209962306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(ibdev);
210062306a36Sopenharmony_ci	struct mlx4_ib_diag_counters *diag = dev->diag_counters;
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	if (!diag[0].descs)
210362306a36Sopenharmony_ci		return NULL;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	return rdma_alloc_hw_stats_struct(diag[0].descs, diag[0].num_counters,
210662306a36Sopenharmony_ci					  RDMA_HW_STATS_DEFAULT_LIFESPAN);
210762306a36Sopenharmony_ci}
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_cistatic struct rdma_hw_stats *
211062306a36Sopenharmony_cimlx4_ib_alloc_hw_port_stats(struct ib_device *ibdev, u32 port_num)
211162306a36Sopenharmony_ci{
211262306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(ibdev);
211362306a36Sopenharmony_ci	struct mlx4_ib_diag_counters *diag = dev->diag_counters;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	if (!diag[1].descs)
211662306a36Sopenharmony_ci		return NULL;
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci	return rdma_alloc_hw_stats_struct(diag[1].descs, diag[1].num_counters,
211962306a36Sopenharmony_ci					  RDMA_HW_STATS_DEFAULT_LIFESPAN);
212062306a36Sopenharmony_ci}
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_cistatic int mlx4_ib_get_hw_stats(struct ib_device *ibdev,
212362306a36Sopenharmony_ci				struct rdma_hw_stats *stats,
212462306a36Sopenharmony_ci				u32 port, int index)
212562306a36Sopenharmony_ci{
212662306a36Sopenharmony_ci	struct mlx4_ib_dev *dev = to_mdev(ibdev);
212762306a36Sopenharmony_ci	struct mlx4_ib_diag_counters *diag = dev->diag_counters;
212862306a36Sopenharmony_ci	u32 hw_value[ARRAY_SIZE(diag_device_only) +
212962306a36Sopenharmony_ci		ARRAY_SIZE(diag_ext) + ARRAY_SIZE(diag_basic)] = {};
213062306a36Sopenharmony_ci	int ret;
213162306a36Sopenharmony_ci	int i;
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	ret = mlx4_query_diag_counters(dev->dev,
213462306a36Sopenharmony_ci				       MLX4_OP_MOD_QUERY_TRANSPORT_CI_ERRORS,
213562306a36Sopenharmony_ci				       diag[!!port].offset, hw_value,
213662306a36Sopenharmony_ci				       diag[!!port].num_counters, port);
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci	if (ret)
213962306a36Sopenharmony_ci		return ret;
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	for (i = 0; i < diag[!!port].num_counters; i++)
214262306a36Sopenharmony_ci		stats->value[i] = hw_value[i];
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	return diag[!!port].num_counters;
214562306a36Sopenharmony_ci}
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_cistatic int __mlx4_ib_alloc_diag_counters(struct mlx4_ib_dev *ibdev,
214862306a36Sopenharmony_ci					 struct rdma_stat_desc **pdescs,
214962306a36Sopenharmony_ci					 u32 **offset, u32 *num, bool port)
215062306a36Sopenharmony_ci{
215162306a36Sopenharmony_ci	u32 num_counters;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	num_counters = ARRAY_SIZE(diag_basic);
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	if (ibdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DIAG_PER_PORT)
215662306a36Sopenharmony_ci		num_counters += ARRAY_SIZE(diag_ext);
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	if (!port)
215962306a36Sopenharmony_ci		num_counters += ARRAY_SIZE(diag_device_only);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	*pdescs = kcalloc(num_counters, sizeof(struct rdma_stat_desc),
216262306a36Sopenharmony_ci			  GFP_KERNEL);
216362306a36Sopenharmony_ci	if (!*pdescs)
216462306a36Sopenharmony_ci		return -ENOMEM;
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci	*offset = kcalloc(num_counters, sizeof(**offset), GFP_KERNEL);
216762306a36Sopenharmony_ci	if (!*offset)
216862306a36Sopenharmony_ci		goto err;
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	*num = num_counters;
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	return 0;
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_cierr:
217562306a36Sopenharmony_ci	kfree(*pdescs);
217662306a36Sopenharmony_ci	return -ENOMEM;
217762306a36Sopenharmony_ci}
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_cistatic void mlx4_ib_fill_diag_counters(struct mlx4_ib_dev *ibdev,
218062306a36Sopenharmony_ci				       struct rdma_stat_desc *descs,
218162306a36Sopenharmony_ci				       u32 *offset, bool port)
218262306a36Sopenharmony_ci{
218362306a36Sopenharmony_ci	int i;
218462306a36Sopenharmony_ci	int j;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	for (i = 0, j = 0; i < ARRAY_SIZE(diag_basic); i++, j++) {
218762306a36Sopenharmony_ci		descs[i].name = diag_basic[i].name;
218862306a36Sopenharmony_ci		offset[i] = diag_basic[i].offset;
218962306a36Sopenharmony_ci	}
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci	if (ibdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DIAG_PER_PORT) {
219262306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(diag_ext); i++, j++) {
219362306a36Sopenharmony_ci			descs[j].name = diag_ext[i].name;
219462306a36Sopenharmony_ci			offset[j] = diag_ext[i].offset;
219562306a36Sopenharmony_ci		}
219662306a36Sopenharmony_ci	}
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci	if (!port) {
219962306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(diag_device_only); i++, j++) {
220062306a36Sopenharmony_ci			descs[j].name = diag_device_only[i].name;
220162306a36Sopenharmony_ci			offset[j] = diag_device_only[i].offset;
220262306a36Sopenharmony_ci		}
220362306a36Sopenharmony_ci	}
220462306a36Sopenharmony_ci}
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_cistatic const struct ib_device_ops mlx4_ib_hw_stats_ops = {
220762306a36Sopenharmony_ci	.alloc_hw_device_stats = mlx4_ib_alloc_hw_device_stats,
220862306a36Sopenharmony_ci	.alloc_hw_port_stats = mlx4_ib_alloc_hw_port_stats,
220962306a36Sopenharmony_ci	.get_hw_stats = mlx4_ib_get_hw_stats,
221062306a36Sopenharmony_ci};
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_cistatic const struct ib_device_ops mlx4_ib_hw_stats_ops1 = {
221362306a36Sopenharmony_ci	.alloc_hw_device_stats = mlx4_ib_alloc_hw_device_stats,
221462306a36Sopenharmony_ci	.get_hw_stats = mlx4_ib_get_hw_stats,
221562306a36Sopenharmony_ci};
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_cistatic int mlx4_ib_alloc_diag_counters(struct mlx4_ib_dev *ibdev)
221862306a36Sopenharmony_ci{
221962306a36Sopenharmony_ci	struct mlx4_ib_diag_counters *diag = ibdev->diag_counters;
222062306a36Sopenharmony_ci	int i;
222162306a36Sopenharmony_ci	int ret;
222262306a36Sopenharmony_ci	bool per_port = !!(ibdev->dev->caps.flags2 &
222362306a36Sopenharmony_ci		MLX4_DEV_CAP_FLAG2_DIAG_PER_PORT);
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	if (mlx4_is_slave(ibdev->dev))
222662306a36Sopenharmony_ci		return 0;
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	for (i = 0; i < MLX4_DIAG_COUNTERS_TYPES; i++) {
222962306a36Sopenharmony_ci		/*
223062306a36Sopenharmony_ci		 * i == 1 means we are building port counters, set a different
223162306a36Sopenharmony_ci		 * stats ops without port stats callback.
223262306a36Sopenharmony_ci		 */
223362306a36Sopenharmony_ci		if (i && !per_port) {
223462306a36Sopenharmony_ci			ib_set_device_ops(&ibdev->ib_dev,
223562306a36Sopenharmony_ci					  &mlx4_ib_hw_stats_ops1);
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci			return 0;
223862306a36Sopenharmony_ci		}
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci		ret = __mlx4_ib_alloc_diag_counters(ibdev, &diag[i].descs,
224162306a36Sopenharmony_ci						    &diag[i].offset,
224262306a36Sopenharmony_ci						    &diag[i].num_counters, i);
224362306a36Sopenharmony_ci		if (ret)
224462306a36Sopenharmony_ci			goto err_alloc;
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci		mlx4_ib_fill_diag_counters(ibdev, diag[i].descs,
224762306a36Sopenharmony_ci					   diag[i].offset, i);
224862306a36Sopenharmony_ci	}
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	ib_set_device_ops(&ibdev->ib_dev, &mlx4_ib_hw_stats_ops);
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci	return 0;
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_cierr_alloc:
225562306a36Sopenharmony_ci	if (i) {
225662306a36Sopenharmony_ci		kfree(diag[i - 1].descs);
225762306a36Sopenharmony_ci		kfree(diag[i - 1].offset);
225862306a36Sopenharmony_ci	}
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	return ret;
226162306a36Sopenharmony_ci}
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_cistatic void mlx4_ib_diag_cleanup(struct mlx4_ib_dev *ibdev)
226462306a36Sopenharmony_ci{
226562306a36Sopenharmony_ci	int i;
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	for (i = 0; i < MLX4_DIAG_COUNTERS_TYPES; i++) {
226862306a36Sopenharmony_ci		kfree(ibdev->diag_counters[i].offset);
226962306a36Sopenharmony_ci		kfree(ibdev->diag_counters[i].descs);
227062306a36Sopenharmony_ci	}
227162306a36Sopenharmony_ci}
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci#define MLX4_IB_INVALID_MAC	((u64)-1)
227462306a36Sopenharmony_cistatic void mlx4_ib_update_qps(struct mlx4_ib_dev *ibdev,
227562306a36Sopenharmony_ci			       struct net_device *dev,
227662306a36Sopenharmony_ci			       int port)
227762306a36Sopenharmony_ci{
227862306a36Sopenharmony_ci	u64 new_smac = 0;
227962306a36Sopenharmony_ci	u64 release_mac = MLX4_IB_INVALID_MAC;
228062306a36Sopenharmony_ci	struct mlx4_ib_qp *qp;
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	new_smac = ether_addr_to_u64(dev->dev_addr);
228362306a36Sopenharmony_ci	atomic64_set(&ibdev->iboe.mac[port - 1], new_smac);
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci	/* no need for update QP1 and mac registration in non-SRIOV */
228662306a36Sopenharmony_ci	if (!mlx4_is_mfunc(ibdev->dev))
228762306a36Sopenharmony_ci		return;
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci	mutex_lock(&ibdev->qp1_proxy_lock[port - 1]);
229062306a36Sopenharmony_ci	qp = ibdev->qp1_proxy[port - 1];
229162306a36Sopenharmony_ci	if (qp) {
229262306a36Sopenharmony_ci		int new_smac_index;
229362306a36Sopenharmony_ci		u64 old_smac;
229462306a36Sopenharmony_ci		struct mlx4_update_qp_params update_params;
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci		mutex_lock(&qp->mutex);
229762306a36Sopenharmony_ci		old_smac = qp->pri.smac;
229862306a36Sopenharmony_ci		if (new_smac == old_smac)
229962306a36Sopenharmony_ci			goto unlock;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci		new_smac_index = mlx4_register_mac(ibdev->dev, port, new_smac);
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci		if (new_smac_index < 0)
230462306a36Sopenharmony_ci			goto unlock;
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci		update_params.smac_index = new_smac_index;
230762306a36Sopenharmony_ci		if (mlx4_update_qp(ibdev->dev, qp->mqp.qpn, MLX4_UPDATE_QP_SMAC,
230862306a36Sopenharmony_ci				   &update_params)) {
230962306a36Sopenharmony_ci			release_mac = new_smac;
231062306a36Sopenharmony_ci			goto unlock;
231162306a36Sopenharmony_ci		}
231262306a36Sopenharmony_ci		/* if old port was zero, no mac was yet registered for this QP */
231362306a36Sopenharmony_ci		if (qp->pri.smac_port)
231462306a36Sopenharmony_ci			release_mac = old_smac;
231562306a36Sopenharmony_ci		qp->pri.smac = new_smac;
231662306a36Sopenharmony_ci		qp->pri.smac_port = port;
231762306a36Sopenharmony_ci		qp->pri.smac_index = new_smac_index;
231862306a36Sopenharmony_ci	}
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ciunlock:
232162306a36Sopenharmony_ci	if (release_mac != MLX4_IB_INVALID_MAC)
232262306a36Sopenharmony_ci		mlx4_unregister_mac(ibdev->dev, port, release_mac);
232362306a36Sopenharmony_ci	if (qp)
232462306a36Sopenharmony_ci		mutex_unlock(&qp->mutex);
232562306a36Sopenharmony_ci	mutex_unlock(&ibdev->qp1_proxy_lock[port - 1]);
232662306a36Sopenharmony_ci}
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_cistatic void mlx4_ib_scan_netdev(struct mlx4_ib_dev *ibdev,
232962306a36Sopenharmony_ci				struct net_device *dev,
233062306a36Sopenharmony_ci				unsigned long event)
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci{
233362306a36Sopenharmony_ci	struct mlx4_ib_iboe *iboe = &ibdev->iboe;
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci	ASSERT_RTNL();
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	if (dev->dev.parent != ibdev->ib_dev.dev.parent)
233862306a36Sopenharmony_ci		return;
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci	spin_lock_bh(&iboe->lock);
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci	iboe->netdevs[dev->dev_port] = event != NETDEV_UNREGISTER ? dev : NULL;
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	if (event == NETDEV_UP || event == NETDEV_DOWN) {
234562306a36Sopenharmony_ci		enum ib_port_state port_state;
234662306a36Sopenharmony_ci		struct ib_event ibev = { };
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci		if (ib_get_cached_port_state(&ibdev->ib_dev, dev->dev_port + 1,
234962306a36Sopenharmony_ci					     &port_state))
235062306a36Sopenharmony_ci			goto iboe_out;
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci		if (event == NETDEV_UP &&
235362306a36Sopenharmony_ci		    (port_state != IB_PORT_ACTIVE ||
235462306a36Sopenharmony_ci		     iboe->last_port_state[dev->dev_port] != IB_PORT_DOWN))
235562306a36Sopenharmony_ci			goto iboe_out;
235662306a36Sopenharmony_ci		if (event == NETDEV_DOWN &&
235762306a36Sopenharmony_ci		    (port_state != IB_PORT_DOWN ||
235862306a36Sopenharmony_ci		     iboe->last_port_state[dev->dev_port] != IB_PORT_ACTIVE))
235962306a36Sopenharmony_ci			goto iboe_out;
236062306a36Sopenharmony_ci		iboe->last_port_state[dev->dev_port] = port_state;
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci		ibev.device = &ibdev->ib_dev;
236362306a36Sopenharmony_ci		ibev.element.port_num = dev->dev_port + 1;
236462306a36Sopenharmony_ci		ibev.event = event == NETDEV_UP ? IB_EVENT_PORT_ACTIVE :
236562306a36Sopenharmony_ci						  IB_EVENT_PORT_ERR;
236662306a36Sopenharmony_ci		ib_dispatch_event(&ibev);
236762306a36Sopenharmony_ci	}
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ciiboe_out:
237062306a36Sopenharmony_ci	spin_unlock_bh(&iboe->lock);
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	if (event == NETDEV_CHANGEADDR || event == NETDEV_REGISTER ||
237362306a36Sopenharmony_ci	    event == NETDEV_UP || event == NETDEV_CHANGE)
237462306a36Sopenharmony_ci		mlx4_ib_update_qps(ibdev, dev, dev->dev_port + 1);
237562306a36Sopenharmony_ci}
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_cistatic int mlx4_ib_netdev_event(struct notifier_block *this,
237862306a36Sopenharmony_ci				unsigned long event, void *ptr)
237962306a36Sopenharmony_ci{
238062306a36Sopenharmony_ci	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
238162306a36Sopenharmony_ci	struct mlx4_ib_dev *ibdev;
238262306a36Sopenharmony_ci
238362306a36Sopenharmony_ci	if (!net_eq(dev_net(dev), &init_net))
238462306a36Sopenharmony_ci		return NOTIFY_DONE;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	ibdev = container_of(this, struct mlx4_ib_dev, iboe.nb);
238762306a36Sopenharmony_ci	mlx4_ib_scan_netdev(ibdev, dev, event);
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_ci	return NOTIFY_DONE;
239062306a36Sopenharmony_ci}
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_cistatic void init_pkeys(struct mlx4_ib_dev *ibdev)
239362306a36Sopenharmony_ci{
239462306a36Sopenharmony_ci	int port;
239562306a36Sopenharmony_ci	int slave;
239662306a36Sopenharmony_ci	int i;
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	if (mlx4_is_master(ibdev->dev)) {
239962306a36Sopenharmony_ci		for (slave = 0; slave <= ibdev->dev->persist->num_vfs;
240062306a36Sopenharmony_ci		     ++slave) {
240162306a36Sopenharmony_ci			for (port = 1; port <= ibdev->dev->caps.num_ports; ++port) {
240262306a36Sopenharmony_ci				for (i = 0;
240362306a36Sopenharmony_ci				     i < ibdev->dev->phys_caps.pkey_phys_table_len[port];
240462306a36Sopenharmony_ci				     ++i) {
240562306a36Sopenharmony_ci					ibdev->pkeys.virt2phys_pkey[slave][port - 1][i] =
240662306a36Sopenharmony_ci					/* master has the identity virt2phys pkey mapping */
240762306a36Sopenharmony_ci						(slave == mlx4_master_func_num(ibdev->dev) || !i) ? i :
240862306a36Sopenharmony_ci							ibdev->dev->phys_caps.pkey_phys_table_len[port] - 1;
240962306a36Sopenharmony_ci					mlx4_sync_pkey_table(ibdev->dev, slave, port, i,
241062306a36Sopenharmony_ci							     ibdev->pkeys.virt2phys_pkey[slave][port - 1][i]);
241162306a36Sopenharmony_ci				}
241262306a36Sopenharmony_ci			}
241362306a36Sopenharmony_ci		}
241462306a36Sopenharmony_ci		/* initialize pkey cache */
241562306a36Sopenharmony_ci		for (port = 1; port <= ibdev->dev->caps.num_ports; ++port) {
241662306a36Sopenharmony_ci			for (i = 0;
241762306a36Sopenharmony_ci			     i < ibdev->dev->phys_caps.pkey_phys_table_len[port];
241862306a36Sopenharmony_ci			     ++i)
241962306a36Sopenharmony_ci				ibdev->pkeys.phys_pkey_cache[port-1][i] =
242062306a36Sopenharmony_ci					(i) ? 0 : 0xFFFF;
242162306a36Sopenharmony_ci		}
242262306a36Sopenharmony_ci	}
242362306a36Sopenharmony_ci}
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_cistatic void mlx4_ib_alloc_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev)
242662306a36Sopenharmony_ci{
242762306a36Sopenharmony_ci	int i, j, eq = 0, total_eqs = 0;
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	ibdev->eq_table = kcalloc(dev->caps.num_comp_vectors,
243062306a36Sopenharmony_ci				  sizeof(ibdev->eq_table[0]), GFP_KERNEL);
243162306a36Sopenharmony_ci	if (!ibdev->eq_table)
243262306a36Sopenharmony_ci		return;
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci	for (i = 1; i <= dev->caps.num_ports; i++) {
243562306a36Sopenharmony_ci		for (j = 0; j < mlx4_get_eqs_per_port(dev, i);
243662306a36Sopenharmony_ci		     j++, total_eqs++) {
243762306a36Sopenharmony_ci			if (i > 1 &&  mlx4_is_eq_shared(dev, total_eqs))
243862306a36Sopenharmony_ci				continue;
243962306a36Sopenharmony_ci			ibdev->eq_table[eq] = total_eqs;
244062306a36Sopenharmony_ci			if (!mlx4_assign_eq(dev, i,
244162306a36Sopenharmony_ci					    &ibdev->eq_table[eq]))
244262306a36Sopenharmony_ci				eq++;
244362306a36Sopenharmony_ci			else
244462306a36Sopenharmony_ci				ibdev->eq_table[eq] = -1;
244562306a36Sopenharmony_ci		}
244662306a36Sopenharmony_ci	}
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	for (i = eq; i < dev->caps.num_comp_vectors;
244962306a36Sopenharmony_ci	     ibdev->eq_table[i++] = -1)
245062306a36Sopenharmony_ci		;
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	/* Advertise the new number of EQs to clients */
245362306a36Sopenharmony_ci	ibdev->ib_dev.num_comp_vectors = eq;
245462306a36Sopenharmony_ci}
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_cistatic void mlx4_ib_free_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev)
245762306a36Sopenharmony_ci{
245862306a36Sopenharmony_ci	int i;
245962306a36Sopenharmony_ci	int total_eqs = ibdev->ib_dev.num_comp_vectors;
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci	/* no eqs were allocated */
246262306a36Sopenharmony_ci	if (!ibdev->eq_table)
246362306a36Sopenharmony_ci		return;
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	/* Reset the advertised EQ number */
246662306a36Sopenharmony_ci	ibdev->ib_dev.num_comp_vectors = 0;
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	for (i = 0; i < total_eqs; i++)
246962306a36Sopenharmony_ci		mlx4_release_eq(dev, ibdev->eq_table[i]);
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	kfree(ibdev->eq_table);
247262306a36Sopenharmony_ci	ibdev->eq_table = NULL;
247362306a36Sopenharmony_ci}
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_cistatic int mlx4_port_immutable(struct ib_device *ibdev, u32 port_num,
247662306a36Sopenharmony_ci			       struct ib_port_immutable *immutable)
247762306a36Sopenharmony_ci{
247862306a36Sopenharmony_ci	struct ib_port_attr attr;
247962306a36Sopenharmony_ci	struct mlx4_ib_dev *mdev = to_mdev(ibdev);
248062306a36Sopenharmony_ci	int err;
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	if (mlx4_ib_port_link_layer(ibdev, port_num) == IB_LINK_LAYER_INFINIBAND) {
248362306a36Sopenharmony_ci		immutable->core_cap_flags = RDMA_CORE_PORT_IBA_IB;
248462306a36Sopenharmony_ci		immutable->max_mad_size = IB_MGMT_MAD_SIZE;
248562306a36Sopenharmony_ci	} else {
248662306a36Sopenharmony_ci		if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE)
248762306a36Sopenharmony_ci			immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE;
248862306a36Sopenharmony_ci		if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2)
248962306a36Sopenharmony_ci			immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE |
249062306a36Sopenharmony_ci				RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP;
249162306a36Sopenharmony_ci		immutable->core_cap_flags |= RDMA_CORE_PORT_RAW_PACKET;
249262306a36Sopenharmony_ci		if (immutable->core_cap_flags & (RDMA_CORE_PORT_IBA_ROCE |
249362306a36Sopenharmony_ci		    RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP))
249462306a36Sopenharmony_ci			immutable->max_mad_size = IB_MGMT_MAD_SIZE;
249562306a36Sopenharmony_ci	}
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci	err = ib_query_port(ibdev, port_num, &attr);
249862306a36Sopenharmony_ci	if (err)
249962306a36Sopenharmony_ci		return err;
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	immutable->pkey_tbl_len = attr.pkey_tbl_len;
250262306a36Sopenharmony_ci	immutable->gid_tbl_len = attr.gid_tbl_len;
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci	return 0;
250562306a36Sopenharmony_ci}
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_cistatic void get_fw_ver_str(struct ib_device *device, char *str)
250862306a36Sopenharmony_ci{
250962306a36Sopenharmony_ci	struct mlx4_ib_dev *dev =
251062306a36Sopenharmony_ci		container_of(device, struct mlx4_ib_dev, ib_dev);
251162306a36Sopenharmony_ci	snprintf(str, IB_FW_VERSION_NAME_MAX, "%d.%d.%d",
251262306a36Sopenharmony_ci		 (int) (dev->dev->caps.fw_ver >> 32),
251362306a36Sopenharmony_ci		 (int) (dev->dev->caps.fw_ver >> 16) & 0xffff,
251462306a36Sopenharmony_ci		 (int) dev->dev->caps.fw_ver & 0xffff);
251562306a36Sopenharmony_ci}
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_cistatic const struct ib_device_ops mlx4_ib_dev_ops = {
251862306a36Sopenharmony_ci	.owner = THIS_MODULE,
251962306a36Sopenharmony_ci	.driver_id = RDMA_DRIVER_MLX4,
252062306a36Sopenharmony_ci	.uverbs_abi_ver = MLX4_IB_UVERBS_ABI_VERSION,
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci	.add_gid = mlx4_ib_add_gid,
252362306a36Sopenharmony_ci	.alloc_mr = mlx4_ib_alloc_mr,
252462306a36Sopenharmony_ci	.alloc_pd = mlx4_ib_alloc_pd,
252562306a36Sopenharmony_ci	.alloc_ucontext = mlx4_ib_alloc_ucontext,
252662306a36Sopenharmony_ci	.attach_mcast = mlx4_ib_mcg_attach,
252762306a36Sopenharmony_ci	.create_ah = mlx4_ib_create_ah,
252862306a36Sopenharmony_ci	.create_cq = mlx4_ib_create_cq,
252962306a36Sopenharmony_ci	.create_qp = mlx4_ib_create_qp,
253062306a36Sopenharmony_ci	.create_srq = mlx4_ib_create_srq,
253162306a36Sopenharmony_ci	.dealloc_pd = mlx4_ib_dealloc_pd,
253262306a36Sopenharmony_ci	.dealloc_ucontext = mlx4_ib_dealloc_ucontext,
253362306a36Sopenharmony_ci	.del_gid = mlx4_ib_del_gid,
253462306a36Sopenharmony_ci	.dereg_mr = mlx4_ib_dereg_mr,
253562306a36Sopenharmony_ci	.destroy_ah = mlx4_ib_destroy_ah,
253662306a36Sopenharmony_ci	.destroy_cq = mlx4_ib_destroy_cq,
253762306a36Sopenharmony_ci	.destroy_qp = mlx4_ib_destroy_qp,
253862306a36Sopenharmony_ci	.destroy_srq = mlx4_ib_destroy_srq,
253962306a36Sopenharmony_ci	.detach_mcast = mlx4_ib_mcg_detach,
254062306a36Sopenharmony_ci	.device_group = &mlx4_attr_group,
254162306a36Sopenharmony_ci	.disassociate_ucontext = mlx4_ib_disassociate_ucontext,
254262306a36Sopenharmony_ci	.drain_rq = mlx4_ib_drain_rq,
254362306a36Sopenharmony_ci	.drain_sq = mlx4_ib_drain_sq,
254462306a36Sopenharmony_ci	.get_dev_fw_str = get_fw_ver_str,
254562306a36Sopenharmony_ci	.get_dma_mr = mlx4_ib_get_dma_mr,
254662306a36Sopenharmony_ci	.get_link_layer = mlx4_ib_port_link_layer,
254762306a36Sopenharmony_ci	.get_netdev = mlx4_ib_get_netdev,
254862306a36Sopenharmony_ci	.get_port_immutable = mlx4_port_immutable,
254962306a36Sopenharmony_ci	.map_mr_sg = mlx4_ib_map_mr_sg,
255062306a36Sopenharmony_ci	.mmap = mlx4_ib_mmap,
255162306a36Sopenharmony_ci	.modify_cq = mlx4_ib_modify_cq,
255262306a36Sopenharmony_ci	.modify_device = mlx4_ib_modify_device,
255362306a36Sopenharmony_ci	.modify_port = mlx4_ib_modify_port,
255462306a36Sopenharmony_ci	.modify_qp = mlx4_ib_modify_qp,
255562306a36Sopenharmony_ci	.modify_srq = mlx4_ib_modify_srq,
255662306a36Sopenharmony_ci	.poll_cq = mlx4_ib_poll_cq,
255762306a36Sopenharmony_ci	.post_recv = mlx4_ib_post_recv,
255862306a36Sopenharmony_ci	.post_send = mlx4_ib_post_send,
255962306a36Sopenharmony_ci	.post_srq_recv = mlx4_ib_post_srq_recv,
256062306a36Sopenharmony_ci	.process_mad = mlx4_ib_process_mad,
256162306a36Sopenharmony_ci	.query_ah = mlx4_ib_query_ah,
256262306a36Sopenharmony_ci	.query_device = mlx4_ib_query_device,
256362306a36Sopenharmony_ci	.query_gid = mlx4_ib_query_gid,
256462306a36Sopenharmony_ci	.query_pkey = mlx4_ib_query_pkey,
256562306a36Sopenharmony_ci	.query_port = mlx4_ib_query_port,
256662306a36Sopenharmony_ci	.query_qp = mlx4_ib_query_qp,
256762306a36Sopenharmony_ci	.query_srq = mlx4_ib_query_srq,
256862306a36Sopenharmony_ci	.reg_user_mr = mlx4_ib_reg_user_mr,
256962306a36Sopenharmony_ci	.req_notify_cq = mlx4_ib_arm_cq,
257062306a36Sopenharmony_ci	.rereg_user_mr = mlx4_ib_rereg_user_mr,
257162306a36Sopenharmony_ci	.resize_cq = mlx4_ib_resize_cq,
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_ah, mlx4_ib_ah, ibah),
257462306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_cq, mlx4_ib_cq, ibcq),
257562306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_pd, mlx4_ib_pd, ibpd),
257662306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_qp, mlx4_ib_qp, ibqp),
257762306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_srq, mlx4_ib_srq, ibsrq),
257862306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_ucontext, mlx4_ib_ucontext, ibucontext),
257962306a36Sopenharmony_ci};
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_cistatic const struct ib_device_ops mlx4_ib_dev_wq_ops = {
258262306a36Sopenharmony_ci	.create_rwq_ind_table = mlx4_ib_create_rwq_ind_table,
258362306a36Sopenharmony_ci	.create_wq = mlx4_ib_create_wq,
258462306a36Sopenharmony_ci	.destroy_rwq_ind_table = mlx4_ib_destroy_rwq_ind_table,
258562306a36Sopenharmony_ci	.destroy_wq = mlx4_ib_destroy_wq,
258662306a36Sopenharmony_ci	.modify_wq = mlx4_ib_modify_wq,
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_rwq_ind_table, mlx4_ib_rwq_ind_table,
258962306a36Sopenharmony_ci			   ib_rwq_ind_tbl),
259062306a36Sopenharmony_ci};
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_cistatic const struct ib_device_ops mlx4_ib_dev_mw_ops = {
259362306a36Sopenharmony_ci	.alloc_mw = mlx4_ib_alloc_mw,
259462306a36Sopenharmony_ci	.dealloc_mw = mlx4_ib_dealloc_mw,
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_mw, mlx4_ib_mw, ibmw),
259762306a36Sopenharmony_ci};
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_cistatic const struct ib_device_ops mlx4_ib_dev_xrc_ops = {
260062306a36Sopenharmony_ci	.alloc_xrcd = mlx4_ib_alloc_xrcd,
260162306a36Sopenharmony_ci	.dealloc_xrcd = mlx4_ib_dealloc_xrcd,
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci	INIT_RDMA_OBJ_SIZE(ib_xrcd, mlx4_ib_xrcd, ibxrcd),
260462306a36Sopenharmony_ci};
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_cistatic const struct ib_device_ops mlx4_ib_dev_fs_ops = {
260762306a36Sopenharmony_ci	.create_flow = mlx4_ib_create_flow,
260862306a36Sopenharmony_ci	.destroy_flow = mlx4_ib_destroy_flow,
260962306a36Sopenharmony_ci};
261062306a36Sopenharmony_ci
261162306a36Sopenharmony_cistatic int mlx4_ib_probe(struct auxiliary_device *adev,
261262306a36Sopenharmony_ci			 const struct auxiliary_device_id *id)
261362306a36Sopenharmony_ci{
261462306a36Sopenharmony_ci	struct mlx4_adev *madev = container_of(adev, struct mlx4_adev, adev);
261562306a36Sopenharmony_ci	struct mlx4_dev *dev = madev->mdev;
261662306a36Sopenharmony_ci	struct mlx4_ib_dev *ibdev;
261762306a36Sopenharmony_ci	int num_ports = 0;
261862306a36Sopenharmony_ci	int i, j;
261962306a36Sopenharmony_ci	int err;
262062306a36Sopenharmony_ci	struct mlx4_ib_iboe *iboe;
262162306a36Sopenharmony_ci	int ib_num_ports = 0;
262262306a36Sopenharmony_ci	int num_req_counters;
262362306a36Sopenharmony_ci	int allocated;
262462306a36Sopenharmony_ci	u32 counter_index;
262562306a36Sopenharmony_ci	struct counter_index *new_counter_index;
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	pr_info_once("%s", mlx4_ib_version);
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	num_ports = 0;
263062306a36Sopenharmony_ci	mlx4_foreach_ib_transport_port(i, dev)
263162306a36Sopenharmony_ci		num_ports++;
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci	/* No point in registering a device with no ports... */
263462306a36Sopenharmony_ci	if (num_ports == 0)
263562306a36Sopenharmony_ci		return -ENODEV;
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci	ibdev = ib_alloc_device(mlx4_ib_dev, ib_dev);
263862306a36Sopenharmony_ci	if (!ibdev) {
263962306a36Sopenharmony_ci		dev_err(&dev->persist->pdev->dev,
264062306a36Sopenharmony_ci			"Device struct alloc failed\n");
264162306a36Sopenharmony_ci		return -ENOMEM;
264262306a36Sopenharmony_ci	}
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_ci	iboe = &ibdev->iboe;
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci	err = mlx4_pd_alloc(dev, &ibdev->priv_pdn);
264762306a36Sopenharmony_ci	if (err)
264862306a36Sopenharmony_ci		goto err_dealloc;
264962306a36Sopenharmony_ci
265062306a36Sopenharmony_ci	err = mlx4_uar_alloc(dev, &ibdev->priv_uar);
265162306a36Sopenharmony_ci	if (err)
265262306a36Sopenharmony_ci		goto err_pd;
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci	ibdev->uar_map = ioremap((phys_addr_t) ibdev->priv_uar.pfn << PAGE_SHIFT,
265562306a36Sopenharmony_ci				 PAGE_SIZE);
265662306a36Sopenharmony_ci	if (!ibdev->uar_map) {
265762306a36Sopenharmony_ci		err = -ENOMEM;
265862306a36Sopenharmony_ci		goto err_uar;
265962306a36Sopenharmony_ci	}
266062306a36Sopenharmony_ci	MLX4_INIT_DOORBELL_LOCK(&ibdev->uar_lock);
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	ibdev->dev = dev;
266362306a36Sopenharmony_ci	ibdev->bond_next_port	= 0;
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ci	ibdev->ib_dev.node_type		= RDMA_NODE_IB_CA;
266662306a36Sopenharmony_ci	ibdev->ib_dev.local_dma_lkey	= dev->caps.reserved_lkey;
266762306a36Sopenharmony_ci	ibdev->num_ports		= num_ports;
266862306a36Sopenharmony_ci	ibdev->ib_dev.phys_port_cnt     = mlx4_is_bonded(dev) ?
266962306a36Sopenharmony_ci						1 : ibdev->num_ports;
267062306a36Sopenharmony_ci	ibdev->ib_dev.num_comp_vectors	= dev->caps.num_comp_vectors;
267162306a36Sopenharmony_ci	ibdev->ib_dev.dev.parent	= &dev->persist->pdev->dev;
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci	ib_set_device_ops(&ibdev->ib_dev, &mlx4_ib_dev_ops);
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci	if ((dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS) &&
267662306a36Sopenharmony_ci	    ((mlx4_ib_port_link_layer(&ibdev->ib_dev, 1) ==
267762306a36Sopenharmony_ci	    IB_LINK_LAYER_ETHERNET) ||
267862306a36Sopenharmony_ci	    (mlx4_ib_port_link_layer(&ibdev->ib_dev, 2) ==
267962306a36Sopenharmony_ci	    IB_LINK_LAYER_ETHERNET)))
268062306a36Sopenharmony_ci		ib_set_device_ops(&ibdev->ib_dev, &mlx4_ib_dev_wq_ops);
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_MEM_WINDOW ||
268362306a36Sopenharmony_ci	    dev->caps.bmme_flags & MLX4_BMME_FLAG_TYPE_2_WIN)
268462306a36Sopenharmony_ci		ib_set_device_ops(&ibdev->ib_dev, &mlx4_ib_dev_mw_ops);
268562306a36Sopenharmony_ci
268662306a36Sopenharmony_ci	if (dev->caps.flags & MLX4_DEV_CAP_FLAG_XRC) {
268762306a36Sopenharmony_ci		ib_set_device_ops(&ibdev->ib_dev, &mlx4_ib_dev_xrc_ops);
268862306a36Sopenharmony_ci	}
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	if (check_flow_steering_support(dev)) {
269162306a36Sopenharmony_ci		ibdev->steering_support = MLX4_STEERING_MODE_DEVICE_MANAGED;
269262306a36Sopenharmony_ci		ib_set_device_ops(&ibdev->ib_dev, &mlx4_ib_dev_fs_ops);
269362306a36Sopenharmony_ci	}
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	if (!dev->caps.userspace_caps)
269662306a36Sopenharmony_ci		ibdev->ib_dev.ops.uverbs_abi_ver =
269762306a36Sopenharmony_ci			MLX4_IB_UVERBS_NO_DEV_CAPS_ABI_VERSION;
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci	mlx4_ib_alloc_eqs(dev, ibdev);
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	spin_lock_init(&iboe->lock);
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_ci	err = init_node_data(ibdev);
270462306a36Sopenharmony_ci	if (err)
270562306a36Sopenharmony_ci		goto err_map;
270662306a36Sopenharmony_ci	mlx4_init_sl2vl_tbl(ibdev);
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci	for (i = 0; i < ibdev->num_ports; ++i) {
270962306a36Sopenharmony_ci		mutex_init(&ibdev->counters_table[i].mutex);
271062306a36Sopenharmony_ci		INIT_LIST_HEAD(&ibdev->counters_table[i].counters_list);
271162306a36Sopenharmony_ci		iboe->last_port_state[i] = IB_PORT_DOWN;
271262306a36Sopenharmony_ci	}
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	num_req_counters = mlx4_is_bonded(dev) ? 1 : ibdev->num_ports;
271562306a36Sopenharmony_ci	for (i = 0; i < num_req_counters; ++i) {
271662306a36Sopenharmony_ci		mutex_init(&ibdev->qp1_proxy_lock[i]);
271762306a36Sopenharmony_ci		allocated = 0;
271862306a36Sopenharmony_ci		if (mlx4_ib_port_link_layer(&ibdev->ib_dev, i + 1) ==
271962306a36Sopenharmony_ci						IB_LINK_LAYER_ETHERNET) {
272062306a36Sopenharmony_ci			err = mlx4_counter_alloc(ibdev->dev, &counter_index,
272162306a36Sopenharmony_ci						 MLX4_RES_USAGE_DRIVER);
272262306a36Sopenharmony_ci			/* if failed to allocate a new counter, use default */
272362306a36Sopenharmony_ci			if (err)
272462306a36Sopenharmony_ci				counter_index =
272562306a36Sopenharmony_ci					mlx4_get_default_counter_index(dev,
272662306a36Sopenharmony_ci								       i + 1);
272762306a36Sopenharmony_ci			else
272862306a36Sopenharmony_ci				allocated = 1;
272962306a36Sopenharmony_ci		} else { /* IB_LINK_LAYER_INFINIBAND use the default counter */
273062306a36Sopenharmony_ci			counter_index = mlx4_get_default_counter_index(dev,
273162306a36Sopenharmony_ci								       i + 1);
273262306a36Sopenharmony_ci		}
273362306a36Sopenharmony_ci		new_counter_index = kmalloc(sizeof(*new_counter_index),
273462306a36Sopenharmony_ci					    GFP_KERNEL);
273562306a36Sopenharmony_ci		if (!new_counter_index) {
273662306a36Sopenharmony_ci			err = -ENOMEM;
273762306a36Sopenharmony_ci			if (allocated)
273862306a36Sopenharmony_ci				mlx4_counter_free(ibdev->dev, counter_index);
273962306a36Sopenharmony_ci			goto err_counter;
274062306a36Sopenharmony_ci		}
274162306a36Sopenharmony_ci		new_counter_index->index = counter_index;
274262306a36Sopenharmony_ci		new_counter_index->allocated = allocated;
274362306a36Sopenharmony_ci		list_add_tail(&new_counter_index->list,
274462306a36Sopenharmony_ci			      &ibdev->counters_table[i].counters_list);
274562306a36Sopenharmony_ci		ibdev->counters_table[i].default_counter = counter_index;
274662306a36Sopenharmony_ci		pr_info("counter index %d for port %d allocated %d\n",
274762306a36Sopenharmony_ci			counter_index, i + 1, allocated);
274862306a36Sopenharmony_ci	}
274962306a36Sopenharmony_ci	if (mlx4_is_bonded(dev))
275062306a36Sopenharmony_ci		for (i = 1; i < ibdev->num_ports ; ++i) {
275162306a36Sopenharmony_ci			new_counter_index =
275262306a36Sopenharmony_ci					kmalloc(sizeof(struct counter_index),
275362306a36Sopenharmony_ci						GFP_KERNEL);
275462306a36Sopenharmony_ci			if (!new_counter_index) {
275562306a36Sopenharmony_ci				err = -ENOMEM;
275662306a36Sopenharmony_ci				goto err_counter;
275762306a36Sopenharmony_ci			}
275862306a36Sopenharmony_ci			new_counter_index->index = counter_index;
275962306a36Sopenharmony_ci			new_counter_index->allocated = 0;
276062306a36Sopenharmony_ci			list_add_tail(&new_counter_index->list,
276162306a36Sopenharmony_ci				      &ibdev->counters_table[i].counters_list);
276262306a36Sopenharmony_ci			ibdev->counters_table[i].default_counter =
276362306a36Sopenharmony_ci								counter_index;
276462306a36Sopenharmony_ci		}
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci	mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
276762306a36Sopenharmony_ci		ib_num_ports++;
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci	spin_lock_init(&ibdev->sm_lock);
277062306a36Sopenharmony_ci	mutex_init(&ibdev->cap_mask_mutex);
277162306a36Sopenharmony_ci	INIT_LIST_HEAD(&ibdev->qp_list);
277262306a36Sopenharmony_ci	spin_lock_init(&ibdev->reset_flow_resource_lock);
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci	if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED &&
277562306a36Sopenharmony_ci	    ib_num_ports) {
277662306a36Sopenharmony_ci		ibdev->steer_qpn_count = MLX4_IB_UC_MAX_NUM_QPS;
277762306a36Sopenharmony_ci		err = mlx4_qp_reserve_range(dev, ibdev->steer_qpn_count,
277862306a36Sopenharmony_ci					    MLX4_IB_UC_STEER_QPN_ALIGN,
277962306a36Sopenharmony_ci					    &ibdev->steer_qpn_base, 0,
278062306a36Sopenharmony_ci					    MLX4_RES_USAGE_DRIVER);
278162306a36Sopenharmony_ci		if (err)
278262306a36Sopenharmony_ci			goto err_counter;
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci		ibdev->ib_uc_qpns_bitmap = bitmap_alloc(ibdev->steer_qpn_count,
278562306a36Sopenharmony_ci							GFP_KERNEL);
278662306a36Sopenharmony_ci		if (!ibdev->ib_uc_qpns_bitmap) {
278762306a36Sopenharmony_ci			err = -ENOMEM;
278862306a36Sopenharmony_ci			goto err_steer_qp_release;
278962306a36Sopenharmony_ci		}
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ci		if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DMFS_IPOIB) {
279262306a36Sopenharmony_ci			bitmap_zero(ibdev->ib_uc_qpns_bitmap,
279362306a36Sopenharmony_ci				    ibdev->steer_qpn_count);
279462306a36Sopenharmony_ci			err = mlx4_FLOW_STEERING_IB_UC_QP_RANGE(
279562306a36Sopenharmony_ci					dev, ibdev->steer_qpn_base,
279662306a36Sopenharmony_ci					ibdev->steer_qpn_base +
279762306a36Sopenharmony_ci					ibdev->steer_qpn_count - 1);
279862306a36Sopenharmony_ci			if (err)
279962306a36Sopenharmony_ci				goto err_steer_free_bitmap;
280062306a36Sopenharmony_ci		} else {
280162306a36Sopenharmony_ci			bitmap_fill(ibdev->ib_uc_qpns_bitmap,
280262306a36Sopenharmony_ci				    ibdev->steer_qpn_count);
280362306a36Sopenharmony_ci		}
280462306a36Sopenharmony_ci	}
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci	for (j = 1; j <= ibdev->dev->caps.num_ports; j++)
280762306a36Sopenharmony_ci		atomic64_set(&iboe->mac[j - 1], ibdev->dev->caps.def_mac[j]);
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	err = mlx4_ib_alloc_diag_counters(ibdev);
281062306a36Sopenharmony_ci	if (err)
281162306a36Sopenharmony_ci		goto err_steer_free_bitmap;
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci	err = ib_register_device(&ibdev->ib_dev, "mlx4_%d",
281462306a36Sopenharmony_ci				 &dev->persist->pdev->dev);
281562306a36Sopenharmony_ci	if (err)
281662306a36Sopenharmony_ci		goto err_diag_counters;
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci	err = mlx4_ib_mad_init(ibdev);
281962306a36Sopenharmony_ci	if (err)
282062306a36Sopenharmony_ci		goto err_reg;
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci	err = mlx4_ib_init_sriov(ibdev);
282362306a36Sopenharmony_ci	if (err)
282462306a36Sopenharmony_ci		goto err_mad;
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	if (!iboe->nb.notifier_call) {
282762306a36Sopenharmony_ci		iboe->nb.notifier_call = mlx4_ib_netdev_event;
282862306a36Sopenharmony_ci		err = register_netdevice_notifier(&iboe->nb);
282962306a36Sopenharmony_ci		if (err) {
283062306a36Sopenharmony_ci			iboe->nb.notifier_call = NULL;
283162306a36Sopenharmony_ci			goto err_notif;
283262306a36Sopenharmony_ci		}
283362306a36Sopenharmony_ci	}
283462306a36Sopenharmony_ci	if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ROCE_V1_V2) {
283562306a36Sopenharmony_ci		err = mlx4_config_roce_v2_port(dev, ROCE_V2_UDP_DPORT);
283662306a36Sopenharmony_ci		if (err)
283762306a36Sopenharmony_ci			goto err_notif;
283862306a36Sopenharmony_ci	}
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci	ibdev->ib_active = true;
284162306a36Sopenharmony_ci	mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
284262306a36Sopenharmony_ci		devlink_port_type_ib_set(mlx4_get_devlink_port(dev, i),
284362306a36Sopenharmony_ci					 &ibdev->ib_dev);
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	if (mlx4_is_mfunc(ibdev->dev))
284662306a36Sopenharmony_ci		init_pkeys(ibdev);
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	/* create paravirt contexts for any VFs which are active */
284962306a36Sopenharmony_ci	if (mlx4_is_master(ibdev->dev)) {
285062306a36Sopenharmony_ci		for (j = 0; j < MLX4_MFUNC_MAX; j++) {
285162306a36Sopenharmony_ci			if (j == mlx4_master_func_num(ibdev->dev))
285262306a36Sopenharmony_ci				continue;
285362306a36Sopenharmony_ci			if (mlx4_is_slave_active(ibdev->dev, j))
285462306a36Sopenharmony_ci				do_slave_init(ibdev, j, 1);
285562306a36Sopenharmony_ci		}
285662306a36Sopenharmony_ci	}
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci	/* register mlx4 core notifier */
285962306a36Sopenharmony_ci	ibdev->mlx_nb.notifier_call = mlx4_ib_event;
286062306a36Sopenharmony_ci	err = mlx4_register_event_notifier(dev, &ibdev->mlx_nb);
286162306a36Sopenharmony_ci	WARN(err, "failed to register mlx4 event notifier (%d)", err);
286262306a36Sopenharmony_ci
286362306a36Sopenharmony_ci	auxiliary_set_drvdata(adev, ibdev);
286462306a36Sopenharmony_ci	return 0;
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_cierr_notif:
286762306a36Sopenharmony_ci	if (ibdev->iboe.nb.notifier_call) {
286862306a36Sopenharmony_ci		if (unregister_netdevice_notifier(&ibdev->iboe.nb))
286962306a36Sopenharmony_ci			pr_warn("failure unregistering notifier\n");
287062306a36Sopenharmony_ci		ibdev->iboe.nb.notifier_call = NULL;
287162306a36Sopenharmony_ci	}
287262306a36Sopenharmony_ci	flush_workqueue(wq);
287362306a36Sopenharmony_ci
287462306a36Sopenharmony_ci	mlx4_ib_close_sriov(ibdev);
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_cierr_mad:
287762306a36Sopenharmony_ci	mlx4_ib_mad_cleanup(ibdev);
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_cierr_reg:
288062306a36Sopenharmony_ci	ib_unregister_device(&ibdev->ib_dev);
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_cierr_diag_counters:
288362306a36Sopenharmony_ci	mlx4_ib_diag_cleanup(ibdev);
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_cierr_steer_free_bitmap:
288662306a36Sopenharmony_ci	bitmap_free(ibdev->ib_uc_qpns_bitmap);
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_cierr_steer_qp_release:
288962306a36Sopenharmony_ci	mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
289062306a36Sopenharmony_ci			      ibdev->steer_qpn_count);
289162306a36Sopenharmony_cierr_counter:
289262306a36Sopenharmony_ci	for (i = 0; i < ibdev->num_ports; ++i)
289362306a36Sopenharmony_ci		mlx4_ib_delete_counters_table(ibdev, &ibdev->counters_table[i]);
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_cierr_map:
289662306a36Sopenharmony_ci	mlx4_ib_free_eqs(dev, ibdev);
289762306a36Sopenharmony_ci	iounmap(ibdev->uar_map);
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_cierr_uar:
290062306a36Sopenharmony_ci	mlx4_uar_free(dev, &ibdev->priv_uar);
290162306a36Sopenharmony_ci
290262306a36Sopenharmony_cierr_pd:
290362306a36Sopenharmony_ci	mlx4_pd_free(dev, ibdev->priv_pdn);
290462306a36Sopenharmony_ci
290562306a36Sopenharmony_cierr_dealloc:
290662306a36Sopenharmony_ci	ib_dealloc_device(&ibdev->ib_dev);
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ci	return err;
290962306a36Sopenharmony_ci}
291062306a36Sopenharmony_ci
291162306a36Sopenharmony_ciint mlx4_ib_steer_qp_alloc(struct mlx4_ib_dev *dev, int count, int *qpn)
291262306a36Sopenharmony_ci{
291362306a36Sopenharmony_ci	int offset;
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci	WARN_ON(!dev->ib_uc_qpns_bitmap);
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	offset = bitmap_find_free_region(dev->ib_uc_qpns_bitmap,
291862306a36Sopenharmony_ci					 dev->steer_qpn_count,
291962306a36Sopenharmony_ci					 get_count_order(count));
292062306a36Sopenharmony_ci	if (offset < 0)
292162306a36Sopenharmony_ci		return offset;
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_ci	*qpn = dev->steer_qpn_base + offset;
292462306a36Sopenharmony_ci	return 0;
292562306a36Sopenharmony_ci}
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_civoid mlx4_ib_steer_qp_free(struct mlx4_ib_dev *dev, u32 qpn, int count)
292862306a36Sopenharmony_ci{
292962306a36Sopenharmony_ci	if (!qpn ||
293062306a36Sopenharmony_ci	    dev->steering_support != MLX4_STEERING_MODE_DEVICE_MANAGED)
293162306a36Sopenharmony_ci		return;
293262306a36Sopenharmony_ci
293362306a36Sopenharmony_ci	if (WARN(qpn < dev->steer_qpn_base, "qpn = %u, steer_qpn_base = %u\n",
293462306a36Sopenharmony_ci		 qpn, dev->steer_qpn_base))
293562306a36Sopenharmony_ci		/* not supposed to be here */
293662306a36Sopenharmony_ci		return;
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	bitmap_release_region(dev->ib_uc_qpns_bitmap,
293962306a36Sopenharmony_ci			      qpn - dev->steer_qpn_base,
294062306a36Sopenharmony_ci			      get_count_order(count));
294162306a36Sopenharmony_ci}
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ciint mlx4_ib_steer_qp_reg(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
294462306a36Sopenharmony_ci			 int is_attach)
294562306a36Sopenharmony_ci{
294662306a36Sopenharmony_ci	int err;
294762306a36Sopenharmony_ci	size_t flow_size;
294862306a36Sopenharmony_ci	struct ib_flow_attr *flow;
294962306a36Sopenharmony_ci	struct ib_flow_spec_ib *ib_spec;
295062306a36Sopenharmony_ci
295162306a36Sopenharmony_ci	if (is_attach) {
295262306a36Sopenharmony_ci		flow_size = sizeof(struct ib_flow_attr) +
295362306a36Sopenharmony_ci			    sizeof(struct ib_flow_spec_ib);
295462306a36Sopenharmony_ci		flow = kzalloc(flow_size, GFP_KERNEL);
295562306a36Sopenharmony_ci		if (!flow)
295662306a36Sopenharmony_ci			return -ENOMEM;
295762306a36Sopenharmony_ci		flow->port = mqp->port;
295862306a36Sopenharmony_ci		flow->num_of_specs = 1;
295962306a36Sopenharmony_ci		flow->size = flow_size;
296062306a36Sopenharmony_ci		ib_spec = (struct ib_flow_spec_ib *)(flow + 1);
296162306a36Sopenharmony_ci		ib_spec->type = IB_FLOW_SPEC_IB;
296262306a36Sopenharmony_ci		ib_spec->size = sizeof(struct ib_flow_spec_ib);
296362306a36Sopenharmony_ci		/* Add an empty rule for IB L2 */
296462306a36Sopenharmony_ci		memset(&ib_spec->mask, 0, sizeof(ib_spec->mask));
296562306a36Sopenharmony_ci
296662306a36Sopenharmony_ci		err = __mlx4_ib_create_flow(&mqp->ibqp, flow, MLX4_DOMAIN_NIC,
296762306a36Sopenharmony_ci					    MLX4_FS_REGULAR, &mqp->reg_id);
296862306a36Sopenharmony_ci		kfree(flow);
296962306a36Sopenharmony_ci		return err;
297062306a36Sopenharmony_ci	}
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_ci	return __mlx4_ib_destroy_flow(mdev->dev, mqp->reg_id);
297362306a36Sopenharmony_ci}
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_cistatic void mlx4_ib_remove(struct auxiliary_device *adev)
297662306a36Sopenharmony_ci{
297762306a36Sopenharmony_ci	struct mlx4_adev *madev = container_of(adev, struct mlx4_adev, adev);
297862306a36Sopenharmony_ci	struct mlx4_dev *dev = madev->mdev;
297962306a36Sopenharmony_ci	struct mlx4_ib_dev *ibdev = auxiliary_get_drvdata(adev);
298062306a36Sopenharmony_ci	int p;
298162306a36Sopenharmony_ci	int i;
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_ci	mlx4_unregister_event_notifier(dev, &ibdev->mlx_nb);
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_ci	mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
298662306a36Sopenharmony_ci		devlink_port_type_clear(mlx4_get_devlink_port(dev, i));
298762306a36Sopenharmony_ci	ibdev->ib_active = false;
298862306a36Sopenharmony_ci	flush_workqueue(wq);
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci	if (ibdev->iboe.nb.notifier_call) {
299162306a36Sopenharmony_ci		if (unregister_netdevice_notifier(&ibdev->iboe.nb))
299262306a36Sopenharmony_ci			pr_warn("failure unregistering notifier\n");
299362306a36Sopenharmony_ci		ibdev->iboe.nb.notifier_call = NULL;
299462306a36Sopenharmony_ci	}
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci	mlx4_ib_close_sriov(ibdev);
299762306a36Sopenharmony_ci	mlx4_ib_mad_cleanup(ibdev);
299862306a36Sopenharmony_ci	ib_unregister_device(&ibdev->ib_dev);
299962306a36Sopenharmony_ci	mlx4_ib_diag_cleanup(ibdev);
300062306a36Sopenharmony_ci
300162306a36Sopenharmony_ci	mlx4_qp_release_range(dev, ibdev->steer_qpn_base,
300262306a36Sopenharmony_ci			      ibdev->steer_qpn_count);
300362306a36Sopenharmony_ci	bitmap_free(ibdev->ib_uc_qpns_bitmap);
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_ci	iounmap(ibdev->uar_map);
300662306a36Sopenharmony_ci	for (p = 0; p < ibdev->num_ports; ++p)
300762306a36Sopenharmony_ci		mlx4_ib_delete_counters_table(ibdev, &ibdev->counters_table[p]);
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci	mlx4_foreach_port(p, dev, MLX4_PORT_TYPE_IB)
301062306a36Sopenharmony_ci		mlx4_CLOSE_PORT(dev, p);
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci	mlx4_ib_free_eqs(dev, ibdev);
301362306a36Sopenharmony_ci
301462306a36Sopenharmony_ci	mlx4_uar_free(dev, &ibdev->priv_uar);
301562306a36Sopenharmony_ci	mlx4_pd_free(dev, ibdev->priv_pdn);
301662306a36Sopenharmony_ci	ib_dealloc_device(&ibdev->ib_dev);
301762306a36Sopenharmony_ci}
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_cistatic void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init)
302062306a36Sopenharmony_ci{
302162306a36Sopenharmony_ci	struct mlx4_ib_demux_work **dm;
302262306a36Sopenharmony_ci	struct mlx4_dev *dev = ibdev->dev;
302362306a36Sopenharmony_ci	int i;
302462306a36Sopenharmony_ci	unsigned long flags;
302562306a36Sopenharmony_ci	struct mlx4_active_ports actv_ports;
302662306a36Sopenharmony_ci	unsigned int ports;
302762306a36Sopenharmony_ci	unsigned int first_port;
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_ci	if (!mlx4_is_master(dev))
303062306a36Sopenharmony_ci		return;
303162306a36Sopenharmony_ci
303262306a36Sopenharmony_ci	actv_ports = mlx4_get_active_ports(dev, slave);
303362306a36Sopenharmony_ci	ports = bitmap_weight(actv_ports.ports, dev->caps.num_ports);
303462306a36Sopenharmony_ci	first_port = find_first_bit(actv_ports.ports, dev->caps.num_ports);
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	dm = kcalloc(ports, sizeof(*dm), GFP_ATOMIC);
303762306a36Sopenharmony_ci	if (!dm)
303862306a36Sopenharmony_ci		return;
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	for (i = 0; i < ports; i++) {
304162306a36Sopenharmony_ci		dm[i] = kmalloc(sizeof (struct mlx4_ib_demux_work), GFP_ATOMIC);
304262306a36Sopenharmony_ci		if (!dm[i]) {
304362306a36Sopenharmony_ci			while (--i >= 0)
304462306a36Sopenharmony_ci				kfree(dm[i]);
304562306a36Sopenharmony_ci			goto out;
304662306a36Sopenharmony_ci		}
304762306a36Sopenharmony_ci		INIT_WORK(&dm[i]->work, mlx4_ib_tunnels_update_work);
304862306a36Sopenharmony_ci		dm[i]->port = first_port + i + 1;
304962306a36Sopenharmony_ci		dm[i]->slave = slave;
305062306a36Sopenharmony_ci		dm[i]->do_init = do_init;
305162306a36Sopenharmony_ci		dm[i]->dev = ibdev;
305262306a36Sopenharmony_ci	}
305362306a36Sopenharmony_ci	/* initialize or tear down tunnel QPs for the slave */
305462306a36Sopenharmony_ci	spin_lock_irqsave(&ibdev->sriov.going_down_lock, flags);
305562306a36Sopenharmony_ci	if (!ibdev->sriov.is_going_down) {
305662306a36Sopenharmony_ci		for (i = 0; i < ports; i++)
305762306a36Sopenharmony_ci			queue_work(ibdev->sriov.demux[i].ud_wq, &dm[i]->work);
305862306a36Sopenharmony_ci		spin_unlock_irqrestore(&ibdev->sriov.going_down_lock, flags);
305962306a36Sopenharmony_ci	} else {
306062306a36Sopenharmony_ci		spin_unlock_irqrestore(&ibdev->sriov.going_down_lock, flags);
306162306a36Sopenharmony_ci		for (i = 0; i < ports; i++)
306262306a36Sopenharmony_ci			kfree(dm[i]);
306362306a36Sopenharmony_ci	}
306462306a36Sopenharmony_ciout:
306562306a36Sopenharmony_ci	kfree(dm);
306662306a36Sopenharmony_ci	return;
306762306a36Sopenharmony_ci}
306862306a36Sopenharmony_ci
306962306a36Sopenharmony_cistatic void mlx4_ib_handle_catas_error(struct mlx4_ib_dev *ibdev)
307062306a36Sopenharmony_ci{
307162306a36Sopenharmony_ci	struct mlx4_ib_qp *mqp;
307262306a36Sopenharmony_ci	unsigned long flags_qp;
307362306a36Sopenharmony_ci	unsigned long flags_cq;
307462306a36Sopenharmony_ci	struct mlx4_ib_cq *send_mcq, *recv_mcq;
307562306a36Sopenharmony_ci	struct list_head    cq_notify_list;
307662306a36Sopenharmony_ci	struct mlx4_cq *mcq;
307762306a36Sopenharmony_ci	unsigned long flags;
307862306a36Sopenharmony_ci
307962306a36Sopenharmony_ci	pr_warn("mlx4_ib_handle_catas_error was started\n");
308062306a36Sopenharmony_ci	INIT_LIST_HEAD(&cq_notify_list);
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci	/* Go over qp list reside on that ibdev, sync with create/destroy qp.*/
308362306a36Sopenharmony_ci	spin_lock_irqsave(&ibdev->reset_flow_resource_lock, flags);
308462306a36Sopenharmony_ci
308562306a36Sopenharmony_ci	list_for_each_entry(mqp, &ibdev->qp_list, qps_list) {
308662306a36Sopenharmony_ci		spin_lock_irqsave(&mqp->sq.lock, flags_qp);
308762306a36Sopenharmony_ci		if (mqp->sq.tail != mqp->sq.head) {
308862306a36Sopenharmony_ci			send_mcq = to_mcq(mqp->ibqp.send_cq);
308962306a36Sopenharmony_ci			spin_lock_irqsave(&send_mcq->lock, flags_cq);
309062306a36Sopenharmony_ci			if (send_mcq->mcq.comp &&
309162306a36Sopenharmony_ci			    mqp->ibqp.send_cq->comp_handler) {
309262306a36Sopenharmony_ci				if (!send_mcq->mcq.reset_notify_added) {
309362306a36Sopenharmony_ci					send_mcq->mcq.reset_notify_added = 1;
309462306a36Sopenharmony_ci					list_add_tail(&send_mcq->mcq.reset_notify,
309562306a36Sopenharmony_ci						      &cq_notify_list);
309662306a36Sopenharmony_ci				}
309762306a36Sopenharmony_ci			}
309862306a36Sopenharmony_ci			spin_unlock_irqrestore(&send_mcq->lock, flags_cq);
309962306a36Sopenharmony_ci		}
310062306a36Sopenharmony_ci		spin_unlock_irqrestore(&mqp->sq.lock, flags_qp);
310162306a36Sopenharmony_ci		/* Now, handle the QP's receive queue */
310262306a36Sopenharmony_ci		spin_lock_irqsave(&mqp->rq.lock, flags_qp);
310362306a36Sopenharmony_ci		/* no handling is needed for SRQ */
310462306a36Sopenharmony_ci		if (!mqp->ibqp.srq) {
310562306a36Sopenharmony_ci			if (mqp->rq.tail != mqp->rq.head) {
310662306a36Sopenharmony_ci				recv_mcq = to_mcq(mqp->ibqp.recv_cq);
310762306a36Sopenharmony_ci				spin_lock_irqsave(&recv_mcq->lock, flags_cq);
310862306a36Sopenharmony_ci				if (recv_mcq->mcq.comp &&
310962306a36Sopenharmony_ci				    mqp->ibqp.recv_cq->comp_handler) {
311062306a36Sopenharmony_ci					if (!recv_mcq->mcq.reset_notify_added) {
311162306a36Sopenharmony_ci						recv_mcq->mcq.reset_notify_added = 1;
311262306a36Sopenharmony_ci						list_add_tail(&recv_mcq->mcq.reset_notify,
311362306a36Sopenharmony_ci							      &cq_notify_list);
311462306a36Sopenharmony_ci					}
311562306a36Sopenharmony_ci				}
311662306a36Sopenharmony_ci				spin_unlock_irqrestore(&recv_mcq->lock,
311762306a36Sopenharmony_ci						       flags_cq);
311862306a36Sopenharmony_ci			}
311962306a36Sopenharmony_ci		}
312062306a36Sopenharmony_ci		spin_unlock_irqrestore(&mqp->rq.lock, flags_qp);
312162306a36Sopenharmony_ci	}
312262306a36Sopenharmony_ci
312362306a36Sopenharmony_ci	list_for_each_entry(mcq, &cq_notify_list, reset_notify) {
312462306a36Sopenharmony_ci		mcq->comp(mcq);
312562306a36Sopenharmony_ci	}
312662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ibdev->reset_flow_resource_lock, flags);
312762306a36Sopenharmony_ci	pr_warn("mlx4_ib_handle_catas_error ended\n");
312862306a36Sopenharmony_ci}
312962306a36Sopenharmony_ci
313062306a36Sopenharmony_cistatic void handle_bonded_port_state_event(struct work_struct *work)
313162306a36Sopenharmony_ci{
313262306a36Sopenharmony_ci	struct ib_event_work *ew =
313362306a36Sopenharmony_ci		container_of(work, struct ib_event_work, work);
313462306a36Sopenharmony_ci	struct mlx4_ib_dev *ibdev = ew->ib_dev;
313562306a36Sopenharmony_ci	enum ib_port_state bonded_port_state = IB_PORT_NOP;
313662306a36Sopenharmony_ci	int i;
313762306a36Sopenharmony_ci	struct ib_event ibev;
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	kfree(ew);
314062306a36Sopenharmony_ci	spin_lock_bh(&ibdev->iboe.lock);
314162306a36Sopenharmony_ci	for (i = 0; i < MLX4_MAX_PORTS; ++i) {
314262306a36Sopenharmony_ci		struct net_device *curr_netdev = ibdev->iboe.netdevs[i];
314362306a36Sopenharmony_ci		enum ib_port_state curr_port_state;
314462306a36Sopenharmony_ci
314562306a36Sopenharmony_ci		if (!curr_netdev)
314662306a36Sopenharmony_ci			continue;
314762306a36Sopenharmony_ci
314862306a36Sopenharmony_ci		curr_port_state =
314962306a36Sopenharmony_ci			(netif_running(curr_netdev) &&
315062306a36Sopenharmony_ci			 netif_carrier_ok(curr_netdev)) ?
315162306a36Sopenharmony_ci			IB_PORT_ACTIVE : IB_PORT_DOWN;
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_ci		bonded_port_state = (bonded_port_state != IB_PORT_ACTIVE) ?
315462306a36Sopenharmony_ci			curr_port_state : IB_PORT_ACTIVE;
315562306a36Sopenharmony_ci	}
315662306a36Sopenharmony_ci	spin_unlock_bh(&ibdev->iboe.lock);
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci	ibev.device = &ibdev->ib_dev;
315962306a36Sopenharmony_ci	ibev.element.port_num = 1;
316062306a36Sopenharmony_ci	ibev.event = (bonded_port_state == IB_PORT_ACTIVE) ?
316162306a36Sopenharmony_ci		IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ci	ib_dispatch_event(&ibev);
316462306a36Sopenharmony_ci}
316562306a36Sopenharmony_ci
316662306a36Sopenharmony_civoid mlx4_ib_sl2vl_update(struct mlx4_ib_dev *mdev, int port)
316762306a36Sopenharmony_ci{
316862306a36Sopenharmony_ci	u64 sl2vl;
316962306a36Sopenharmony_ci	int err;
317062306a36Sopenharmony_ci
317162306a36Sopenharmony_ci	err = mlx4_ib_query_sl2vl(&mdev->ib_dev, port, &sl2vl);
317262306a36Sopenharmony_ci	if (err) {
317362306a36Sopenharmony_ci		pr_err("Unable to get current sl to vl mapping for port %d.  Using all zeroes (%d)\n",
317462306a36Sopenharmony_ci		       port, err);
317562306a36Sopenharmony_ci		sl2vl = 0;
317662306a36Sopenharmony_ci	}
317762306a36Sopenharmony_ci	atomic64_set(&mdev->sl2vl[port - 1], sl2vl);
317862306a36Sopenharmony_ci}
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_cistatic void ib_sl2vl_update_work(struct work_struct *work)
318162306a36Sopenharmony_ci{
318262306a36Sopenharmony_ci	struct ib_event_work *ew = container_of(work, struct ib_event_work, work);
318362306a36Sopenharmony_ci	struct mlx4_ib_dev *mdev = ew->ib_dev;
318462306a36Sopenharmony_ci	int port = ew->port;
318562306a36Sopenharmony_ci
318662306a36Sopenharmony_ci	mlx4_ib_sl2vl_update(mdev, port);
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ci	kfree(ew);
318962306a36Sopenharmony_ci}
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_civoid mlx4_sched_ib_sl2vl_update_work(struct mlx4_ib_dev *ibdev,
319262306a36Sopenharmony_ci				     int port)
319362306a36Sopenharmony_ci{
319462306a36Sopenharmony_ci	struct ib_event_work *ew;
319562306a36Sopenharmony_ci
319662306a36Sopenharmony_ci	ew = kmalloc(sizeof(*ew), GFP_ATOMIC);
319762306a36Sopenharmony_ci	if (ew) {
319862306a36Sopenharmony_ci		INIT_WORK(&ew->work, ib_sl2vl_update_work);
319962306a36Sopenharmony_ci		ew->port = port;
320062306a36Sopenharmony_ci		ew->ib_dev = ibdev;
320162306a36Sopenharmony_ci		queue_work(wq, &ew->work);
320262306a36Sopenharmony_ci	}
320362306a36Sopenharmony_ci}
320462306a36Sopenharmony_ci
320562306a36Sopenharmony_cistatic int mlx4_ib_event(struct notifier_block *this, unsigned long event,
320662306a36Sopenharmony_ci			 void *param)
320762306a36Sopenharmony_ci{
320862306a36Sopenharmony_ci	struct mlx4_ib_dev *ibdev =
320962306a36Sopenharmony_ci		container_of(this, struct mlx4_ib_dev, mlx_nb);
321062306a36Sopenharmony_ci	struct mlx4_dev *dev = ibdev->dev;
321162306a36Sopenharmony_ci	struct ib_event ibev;
321262306a36Sopenharmony_ci	struct mlx4_eqe *eqe = NULL;
321362306a36Sopenharmony_ci	struct ib_event_work *ew;
321462306a36Sopenharmony_ci	int p = 0;
321562306a36Sopenharmony_ci
321662306a36Sopenharmony_ci	if (mlx4_is_bonded(dev) &&
321762306a36Sopenharmony_ci	    ((event == MLX4_DEV_EVENT_PORT_UP) ||
321862306a36Sopenharmony_ci	    (event == MLX4_DEV_EVENT_PORT_DOWN))) {
321962306a36Sopenharmony_ci		ew = kmalloc(sizeof(*ew), GFP_ATOMIC);
322062306a36Sopenharmony_ci		if (!ew)
322162306a36Sopenharmony_ci			return NOTIFY_DONE;
322262306a36Sopenharmony_ci		INIT_WORK(&ew->work, handle_bonded_port_state_event);
322362306a36Sopenharmony_ci		ew->ib_dev = ibdev;
322462306a36Sopenharmony_ci		queue_work(wq, &ew->work);
322562306a36Sopenharmony_ci		return NOTIFY_DONE;
322662306a36Sopenharmony_ci	}
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci	switch (event) {
322962306a36Sopenharmony_ci	case MLX4_DEV_EVENT_CATASTROPHIC_ERROR:
323062306a36Sopenharmony_ci		break;
323162306a36Sopenharmony_ci	case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
323262306a36Sopenharmony_ci		eqe = (struct mlx4_eqe *)param;
323362306a36Sopenharmony_ci		break;
323462306a36Sopenharmony_ci	default:
323562306a36Sopenharmony_ci		p = *(int *)param;
323662306a36Sopenharmony_ci		break;
323762306a36Sopenharmony_ci	}
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci	switch (event) {
324062306a36Sopenharmony_ci	case MLX4_DEV_EVENT_PORT_UP:
324162306a36Sopenharmony_ci		if (p > ibdev->num_ports)
324262306a36Sopenharmony_ci			return NOTIFY_DONE;
324362306a36Sopenharmony_ci		if (!mlx4_is_slave(dev) &&
324462306a36Sopenharmony_ci		    rdma_port_get_link_layer(&ibdev->ib_dev, p) ==
324562306a36Sopenharmony_ci			IB_LINK_LAYER_INFINIBAND) {
324662306a36Sopenharmony_ci			if (mlx4_is_master(dev))
324762306a36Sopenharmony_ci				mlx4_ib_invalidate_all_guid_record(ibdev, p);
324862306a36Sopenharmony_ci			if (ibdev->dev->flags & MLX4_FLAG_SECURE_HOST &&
324962306a36Sopenharmony_ci			    !(ibdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT))
325062306a36Sopenharmony_ci				mlx4_sched_ib_sl2vl_update_work(ibdev, p);
325162306a36Sopenharmony_ci		}
325262306a36Sopenharmony_ci		ibev.event = IB_EVENT_PORT_ACTIVE;
325362306a36Sopenharmony_ci		break;
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci	case MLX4_DEV_EVENT_PORT_DOWN:
325662306a36Sopenharmony_ci		if (p > ibdev->num_ports)
325762306a36Sopenharmony_ci			return NOTIFY_DONE;
325862306a36Sopenharmony_ci		ibev.event = IB_EVENT_PORT_ERR;
325962306a36Sopenharmony_ci		break;
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ci	case MLX4_DEV_EVENT_CATASTROPHIC_ERROR:
326262306a36Sopenharmony_ci		ibdev->ib_active = false;
326362306a36Sopenharmony_ci		ibev.event = IB_EVENT_DEVICE_FATAL;
326462306a36Sopenharmony_ci		mlx4_ib_handle_catas_error(ibdev);
326562306a36Sopenharmony_ci		break;
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_ci	case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
326862306a36Sopenharmony_ci		ew = kmalloc(sizeof *ew, GFP_ATOMIC);
326962306a36Sopenharmony_ci		if (!ew)
327062306a36Sopenharmony_ci			return NOTIFY_DONE;
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci		INIT_WORK(&ew->work, handle_port_mgmt_change_event);
327362306a36Sopenharmony_ci		memcpy(&ew->ib_eqe, eqe, sizeof *eqe);
327462306a36Sopenharmony_ci		ew->ib_dev = ibdev;
327562306a36Sopenharmony_ci		/* need to queue only for port owner, which uses GEN_EQE */
327662306a36Sopenharmony_ci		if (mlx4_is_master(dev))
327762306a36Sopenharmony_ci			queue_work(wq, &ew->work);
327862306a36Sopenharmony_ci		else
327962306a36Sopenharmony_ci			handle_port_mgmt_change_event(&ew->work);
328062306a36Sopenharmony_ci		return NOTIFY_DONE;
328162306a36Sopenharmony_ci
328262306a36Sopenharmony_ci	case MLX4_DEV_EVENT_SLAVE_INIT:
328362306a36Sopenharmony_ci		/* here, p is the slave id */
328462306a36Sopenharmony_ci		do_slave_init(ibdev, p, 1);
328562306a36Sopenharmony_ci		if (mlx4_is_master(dev)) {
328662306a36Sopenharmony_ci			int i;
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci			for (i = 1; i <= ibdev->num_ports; i++) {
328962306a36Sopenharmony_ci				if (rdma_port_get_link_layer(&ibdev->ib_dev, i)
329062306a36Sopenharmony_ci					== IB_LINK_LAYER_INFINIBAND)
329162306a36Sopenharmony_ci					mlx4_ib_slave_alias_guid_event(ibdev,
329262306a36Sopenharmony_ci								       p, i,
329362306a36Sopenharmony_ci								       1);
329462306a36Sopenharmony_ci			}
329562306a36Sopenharmony_ci		}
329662306a36Sopenharmony_ci		return NOTIFY_DONE;
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci	case MLX4_DEV_EVENT_SLAVE_SHUTDOWN:
329962306a36Sopenharmony_ci		if (mlx4_is_master(dev)) {
330062306a36Sopenharmony_ci			int i;
330162306a36Sopenharmony_ci
330262306a36Sopenharmony_ci			for (i = 1; i <= ibdev->num_ports; i++) {
330362306a36Sopenharmony_ci				if (rdma_port_get_link_layer(&ibdev->ib_dev, i)
330462306a36Sopenharmony_ci					== IB_LINK_LAYER_INFINIBAND)
330562306a36Sopenharmony_ci					mlx4_ib_slave_alias_guid_event(ibdev,
330662306a36Sopenharmony_ci								       p, i,
330762306a36Sopenharmony_ci								       0);
330862306a36Sopenharmony_ci			}
330962306a36Sopenharmony_ci		}
331062306a36Sopenharmony_ci		/* here, p is the slave id */
331162306a36Sopenharmony_ci		do_slave_init(ibdev, p, 0);
331262306a36Sopenharmony_ci		return NOTIFY_DONE;
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_ci	default:
331562306a36Sopenharmony_ci		return NOTIFY_DONE;
331662306a36Sopenharmony_ci	}
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci	ibev.device	      = &ibdev->ib_dev;
331962306a36Sopenharmony_ci	ibev.element.port_num = mlx4_is_bonded(ibdev->dev) ? 1 : (u8)p;
332062306a36Sopenharmony_ci
332162306a36Sopenharmony_ci	ib_dispatch_event(&ibev);
332262306a36Sopenharmony_ci	return NOTIFY_DONE;
332362306a36Sopenharmony_ci}
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_cistatic const struct auxiliary_device_id mlx4_ib_id_table[] = {
332662306a36Sopenharmony_ci	{ .name = MLX4_ADEV_NAME ".ib" },
332762306a36Sopenharmony_ci	{},
332862306a36Sopenharmony_ci};
332962306a36Sopenharmony_ci
333062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(auxiliary, mlx4_ib_id_table);
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_cistatic struct mlx4_adrv mlx4_ib_adrv = {
333362306a36Sopenharmony_ci	.adrv = {
333462306a36Sopenharmony_ci		.name	= "ib",
333562306a36Sopenharmony_ci		.probe	= mlx4_ib_probe,
333662306a36Sopenharmony_ci		.remove	= mlx4_ib_remove,
333762306a36Sopenharmony_ci		.id_table = mlx4_ib_id_table,
333862306a36Sopenharmony_ci	},
333962306a36Sopenharmony_ci	.protocol	= MLX4_PROT_IB_IPV6,
334062306a36Sopenharmony_ci	.flags		= MLX4_INTFF_BONDING
334162306a36Sopenharmony_ci};
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_cistatic int __init mlx4_ib_init(void)
334462306a36Sopenharmony_ci{
334562306a36Sopenharmony_ci	int err;
334662306a36Sopenharmony_ci
334762306a36Sopenharmony_ci	wq = alloc_ordered_workqueue("mlx4_ib", WQ_MEM_RECLAIM);
334862306a36Sopenharmony_ci	if (!wq)
334962306a36Sopenharmony_ci		return -ENOMEM;
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci	err = mlx4_ib_qp_event_init();
335262306a36Sopenharmony_ci	if (err)
335362306a36Sopenharmony_ci		goto clean_qp_event;
335462306a36Sopenharmony_ci
335562306a36Sopenharmony_ci	err = mlx4_ib_cm_init();
335662306a36Sopenharmony_ci	if (err)
335762306a36Sopenharmony_ci		goto clean_wq;
335862306a36Sopenharmony_ci
335962306a36Sopenharmony_ci	err = mlx4_ib_mcg_init();
336062306a36Sopenharmony_ci	if (err)
336162306a36Sopenharmony_ci		goto clean_cm;
336262306a36Sopenharmony_ci
336362306a36Sopenharmony_ci	err = mlx4_register_auxiliary_driver(&mlx4_ib_adrv);
336462306a36Sopenharmony_ci	if (err)
336562306a36Sopenharmony_ci		goto clean_mcg;
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_ci	return 0;
336862306a36Sopenharmony_ci
336962306a36Sopenharmony_ciclean_mcg:
337062306a36Sopenharmony_ci	mlx4_ib_mcg_destroy();
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ciclean_cm:
337362306a36Sopenharmony_ci	mlx4_ib_cm_destroy();
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ciclean_wq:
337662306a36Sopenharmony_ci	mlx4_ib_qp_event_cleanup();
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ciclean_qp_event:
337962306a36Sopenharmony_ci	destroy_workqueue(wq);
338062306a36Sopenharmony_ci	return err;
338162306a36Sopenharmony_ci}
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_cistatic void __exit mlx4_ib_cleanup(void)
338462306a36Sopenharmony_ci{
338562306a36Sopenharmony_ci	mlx4_unregister_auxiliary_driver(&mlx4_ib_adrv);
338662306a36Sopenharmony_ci	mlx4_ib_mcg_destroy();
338762306a36Sopenharmony_ci	mlx4_ib_cm_destroy();
338862306a36Sopenharmony_ci	mlx4_ib_qp_event_cleanup();
338962306a36Sopenharmony_ci	destroy_workqueue(wq);
339062306a36Sopenharmony_ci}
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_cimodule_init(mlx4_ib_init);
339362306a36Sopenharmony_cimodule_exit(mlx4_ib_cleanup);
3394