|
@@ -819,38 +819,93 @@ static void slave_adjust_steering_mode(struct mlx4_dev *dev,
|
|
mlx4_steering_mode_str(dev->caps.steering_mode));
|
|
mlx4_steering_mode_str(dev->caps.steering_mode));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void mlx4_slave_destroy_special_qp_cap(struct mlx4_dev *dev)
|
|
|
|
+{
|
|
|
|
+ kfree(dev->caps.spec_qps);
|
|
|
|
+ dev->caps.spec_qps = NULL;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int mlx4_slave_special_qp_cap(struct mlx4_dev *dev)
|
|
|
|
+{
|
|
|
|
+ struct mlx4_func_cap *func_cap = NULL;
|
|
|
|
+ struct mlx4_caps *caps = &dev->caps;
|
|
|
|
+ int i, err = 0;
|
|
|
|
+
|
|
|
|
+ func_cap = kzalloc(sizeof(*func_cap), GFP_KERNEL);
|
|
|
|
+ caps->spec_qps = kcalloc(caps->num_ports, sizeof(*caps->spec_qps), GFP_KERNEL);
|
|
|
|
+
|
|
|
|
+ if (!func_cap || !caps->spec_qps) {
|
|
|
|
+ mlx4_err(dev, "Failed to allocate memory for special qps cap\n");
|
|
|
|
+ err = -ENOMEM;
|
|
|
|
+ goto err_mem;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (i = 1; i <= caps->num_ports; ++i) {
|
|
|
|
+ err = mlx4_QUERY_FUNC_CAP(dev, i, func_cap);
|
|
|
|
+ if (err) {
|
|
|
|
+ mlx4_err(dev, "QUERY_FUNC_CAP port command failed for port %d, aborting (%d)\n",
|
|
|
|
+ i, err);
|
|
|
|
+ goto err_mem;
|
|
|
|
+ }
|
|
|
|
+ caps->spec_qps[i - 1] = func_cap->spec_qps;
|
|
|
|
+ caps->port_mask[i] = caps->port_type[i];
|
|
|
|
+ caps->phys_port_id[i] = func_cap->phys_port_id;
|
|
|
|
+ err = mlx4_get_slave_pkey_gid_tbl_len(dev, i,
|
|
|
|
+ &caps->gid_table_len[i],
|
|
|
|
+ &caps->pkey_table_len[i]);
|
|
|
|
+ if (err) {
|
|
|
|
+ mlx4_err(dev, "QUERY_PORT command failed for port %d, aborting (%d)\n",
|
|
|
|
+ i, err);
|
|
|
|
+ goto err_mem;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+err_mem:
|
|
|
|
+ if (err)
|
|
|
|
+ mlx4_slave_destroy_special_qp_cap(dev);
|
|
|
|
+ kfree(func_cap);
|
|
|
|
+ return err;
|
|
|
|
+}
|
|
|
|
+
|
|
static int mlx4_slave_cap(struct mlx4_dev *dev)
|
|
static int mlx4_slave_cap(struct mlx4_dev *dev)
|
|
{
|
|
{
|
|
int err;
|
|
int err;
|
|
u32 page_size;
|
|
u32 page_size;
|
|
- struct mlx4_dev_cap dev_cap;
|
|
|
|
- struct mlx4_func_cap func_cap;
|
|
|
|
- struct mlx4_init_hca_param hca_param;
|
|
|
|
- u8 i;
|
|
|
|
|
|
+ struct mlx4_dev_cap *dev_cap = NULL;
|
|
|
|
+ struct mlx4_func_cap *func_cap = NULL;
|
|
|
|
+ struct mlx4_init_hca_param *hca_param = NULL;
|
|
|
|
+
|
|
|
|
+ hca_param = kzalloc(sizeof(*hca_param), GFP_KERNEL);
|
|
|
|
+ func_cap = kzalloc(sizeof(*func_cap), GFP_KERNEL);
|
|
|
|
+ dev_cap = kzalloc(sizeof(*dev_cap), GFP_KERNEL);
|
|
|
|
+ if (!hca_param || !func_cap || !dev_cap) {
|
|
|
|
+ mlx4_err(dev, "Failed to allocate memory for slave_cap\n");
|
|
|
|
+ err = -ENOMEM;
|
|
|
|
+ goto free_mem;
|
|
|
|
+ }
|
|
|
|
|
|
- memset(&hca_param, 0, sizeof(hca_param));
|
|
|
|
- err = mlx4_QUERY_HCA(dev, &hca_param);
|
|
|
|
|
|
+ err = mlx4_QUERY_HCA(dev, hca_param);
|
|
if (err) {
|
|
if (err) {
|
|
mlx4_err(dev, "QUERY_HCA command failed, aborting\n");
|
|
mlx4_err(dev, "QUERY_HCA command failed, aborting\n");
|
|
- return err;
|
|
|
|
|
|
+ goto free_mem;
|
|
}
|
|
}
|
|
|
|
|
|
/* fail if the hca has an unknown global capability
|
|
/* fail if the hca has an unknown global capability
|
|
* at this time global_caps should be always zeroed
|
|
* at this time global_caps should be always zeroed
|
|
*/
|
|
*/
|
|
- if (hca_param.global_caps) {
|
|
|
|
|
|
+ if (hca_param->global_caps) {
|
|
mlx4_err(dev, "Unknown hca global capabilities\n");
|
|
mlx4_err(dev, "Unknown hca global capabilities\n");
|
|
- return -EINVAL;
|
|
|
|
|
|
+ err = -EINVAL;
|
|
|
|
+ goto free_mem;
|
|
}
|
|
}
|
|
|
|
|
|
- dev->caps.hca_core_clock = hca_param.hca_core_clock;
|
|
|
|
|
|
+ dev->caps.hca_core_clock = hca_param->hca_core_clock;
|
|
|
|
|
|
- memset(&dev_cap, 0, sizeof(dev_cap));
|
|
|
|
- dev->caps.max_qp_dest_rdma = 1 << hca_param.log_rd_per_qp;
|
|
|
|
- err = mlx4_dev_cap(dev, &dev_cap);
|
|
|
|
|
|
+ dev->caps.max_qp_dest_rdma = 1 << hca_param->log_rd_per_qp;
|
|
|
|
+ err = mlx4_dev_cap(dev, dev_cap);
|
|
if (err) {
|
|
if (err) {
|
|
mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting\n");
|
|
mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting\n");
|
|
- return err;
|
|
|
|
|
|
+ goto free_mem;
|
|
}
|
|
}
|
|
|
|
|
|
err = mlx4_QUERY_FW(dev);
|
|
err = mlx4_QUERY_FW(dev);
|
|
@@ -862,21 +917,23 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
|
|
if (page_size > PAGE_SIZE) {
|
|
if (page_size > PAGE_SIZE) {
|
|
mlx4_err(dev, "HCA minimum page size of %d bigger than kernel PAGE_SIZE of %ld, aborting\n",
|
|
mlx4_err(dev, "HCA minimum page size of %d bigger than kernel PAGE_SIZE of %ld, aborting\n",
|
|
page_size, PAGE_SIZE);
|
|
page_size, PAGE_SIZE);
|
|
- return -ENODEV;
|
|
|
|
|
|
+ err = -ENODEV;
|
|
|
|
+ goto free_mem;
|
|
}
|
|
}
|
|
|
|
|
|
/* Set uar_page_shift for VF */
|
|
/* Set uar_page_shift for VF */
|
|
- dev->uar_page_shift = hca_param.uar_page_sz + 12;
|
|
|
|
|
|
+ dev->uar_page_shift = hca_param->uar_page_sz + 12;
|
|
|
|
|
|
/* Make sure the master uar page size is valid */
|
|
/* Make sure the master uar page size is valid */
|
|
if (dev->uar_page_shift > PAGE_SHIFT) {
|
|
if (dev->uar_page_shift > PAGE_SHIFT) {
|
|
mlx4_err(dev,
|
|
mlx4_err(dev,
|
|
"Invalid configuration: uar page size is larger than system page size\n");
|
|
"Invalid configuration: uar page size is larger than system page size\n");
|
|
- return -ENODEV;
|
|
|
|
|
|
+ err = -ENODEV;
|
|
|
|
+ goto free_mem;
|
|
}
|
|
}
|
|
|
|
|
|
/* Set reserved_uars based on the uar_page_shift */
|
|
/* Set reserved_uars based on the uar_page_shift */
|
|
- mlx4_set_num_reserved_uars(dev, &dev_cap);
|
|
|
|
|
|
+ mlx4_set_num_reserved_uars(dev, dev_cap);
|
|
|
|
|
|
/* Although uar page size in FW differs from system page size,
|
|
/* Although uar page size in FW differs from system page size,
|
|
* upper software layers (mlx4_ib, mlx4_en and part of mlx4_core)
|
|
* upper software layers (mlx4_ib, mlx4_en and part of mlx4_core)
|
|
@@ -884,34 +941,35 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
|
|
*/
|
|
*/
|
|
dev->caps.uar_page_size = PAGE_SIZE;
|
|
dev->caps.uar_page_size = PAGE_SIZE;
|
|
|
|
|
|
- memset(&func_cap, 0, sizeof(func_cap));
|
|
|
|
- err = mlx4_QUERY_FUNC_CAP(dev, 0, &func_cap);
|
|
|
|
|
|
+ err = mlx4_QUERY_FUNC_CAP(dev, 0, func_cap);
|
|
if (err) {
|
|
if (err) {
|
|
mlx4_err(dev, "QUERY_FUNC_CAP general command failed, aborting (%d)\n",
|
|
mlx4_err(dev, "QUERY_FUNC_CAP general command failed, aborting (%d)\n",
|
|
err);
|
|
err);
|
|
- return err;
|
|
|
|
|
|
+ goto free_mem;
|
|
}
|
|
}
|
|
|
|
|
|
- if ((func_cap.pf_context_behaviour | PF_CONTEXT_BEHAVIOUR_MASK) !=
|
|
|
|
|
|
+ if ((func_cap->pf_context_behaviour | PF_CONTEXT_BEHAVIOUR_MASK) !=
|
|
PF_CONTEXT_BEHAVIOUR_MASK) {
|
|
PF_CONTEXT_BEHAVIOUR_MASK) {
|
|
mlx4_err(dev, "Unknown pf context behaviour %x known flags %x\n",
|
|
mlx4_err(dev, "Unknown pf context behaviour %x known flags %x\n",
|
|
- func_cap.pf_context_behaviour, PF_CONTEXT_BEHAVIOUR_MASK);
|
|
|
|
- return -EINVAL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- dev->caps.num_ports = func_cap.num_ports;
|
|
|
|
- dev->quotas.qp = func_cap.qp_quota;
|
|
|
|
- dev->quotas.srq = func_cap.srq_quota;
|
|
|
|
- dev->quotas.cq = func_cap.cq_quota;
|
|
|
|
- dev->quotas.mpt = func_cap.mpt_quota;
|
|
|
|
- dev->quotas.mtt = func_cap.mtt_quota;
|
|
|
|
- dev->caps.num_qps = 1 << hca_param.log_num_qps;
|
|
|
|
- dev->caps.num_srqs = 1 << hca_param.log_num_srqs;
|
|
|
|
- dev->caps.num_cqs = 1 << hca_param.log_num_cqs;
|
|
|
|
- dev->caps.num_mpts = 1 << hca_param.log_mpt_sz;
|
|
|
|
- dev->caps.num_eqs = func_cap.max_eq;
|
|
|
|
- dev->caps.reserved_eqs = func_cap.reserved_eq;
|
|
|
|
- dev->caps.reserved_lkey = func_cap.reserved_lkey;
|
|
|
|
|
|
+ func_cap->pf_context_behaviour,
|
|
|
|
+ PF_CONTEXT_BEHAVIOUR_MASK);
|
|
|
|
+ err = -EINVAL;
|
|
|
|
+ goto free_mem;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dev->caps.num_ports = func_cap->num_ports;
|
|
|
|
+ dev->quotas.qp = func_cap->qp_quota;
|
|
|
|
+ dev->quotas.srq = func_cap->srq_quota;
|
|
|
|
+ dev->quotas.cq = func_cap->cq_quota;
|
|
|
|
+ dev->quotas.mpt = func_cap->mpt_quota;
|
|
|
|
+ dev->quotas.mtt = func_cap->mtt_quota;
|
|
|
|
+ dev->caps.num_qps = 1 << hca_param->log_num_qps;
|
|
|
|
+ dev->caps.num_srqs = 1 << hca_param->log_num_srqs;
|
|
|
|
+ dev->caps.num_cqs = 1 << hca_param->log_num_cqs;
|
|
|
|
+ dev->caps.num_mpts = 1 << hca_param->log_mpt_sz;
|
|
|
|
+ dev->caps.num_eqs = func_cap->max_eq;
|
|
|
|
+ dev->caps.reserved_eqs = func_cap->reserved_eq;
|
|
|
|
+ dev->caps.reserved_lkey = func_cap->reserved_lkey;
|
|
dev->caps.num_pds = MLX4_NUM_PDS;
|
|
dev->caps.num_pds = MLX4_NUM_PDS;
|
|
dev->caps.num_mgms = 0;
|
|
dev->caps.num_mgms = 0;
|
|
dev->caps.num_amgms = 0;
|
|
dev->caps.num_amgms = 0;
|
|
@@ -924,38 +982,10 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
|
|
|
|
|
|
mlx4_replace_zero_macs(dev);
|
|
mlx4_replace_zero_macs(dev);
|
|
|
|
|
|
- dev->caps.qp0_qkey = kcalloc(dev->caps.num_ports, sizeof(u32), GFP_KERNEL);
|
|
|
|
- dev->caps.qp0_tunnel = kcalloc(dev->caps.num_ports, sizeof(u32), GFP_KERNEL);
|
|
|
|
- dev->caps.qp0_proxy = kcalloc(dev->caps.num_ports, sizeof(u32), GFP_KERNEL);
|
|
|
|
- dev->caps.qp1_tunnel = kcalloc(dev->caps.num_ports, sizeof(u32), GFP_KERNEL);
|
|
|
|
- dev->caps.qp1_proxy = kcalloc(dev->caps.num_ports, sizeof(u32), GFP_KERNEL);
|
|
|
|
-
|
|
|
|
- if (!dev->caps.qp0_tunnel || !dev->caps.qp0_proxy ||
|
|
|
|
- !dev->caps.qp1_tunnel || !dev->caps.qp1_proxy ||
|
|
|
|
- !dev->caps.qp0_qkey) {
|
|
|
|
- err = -ENOMEM;
|
|
|
|
- goto err_mem;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (i = 1; i <= dev->caps.num_ports; ++i) {
|
|
|
|
- err = mlx4_QUERY_FUNC_CAP(dev, i, &func_cap);
|
|
|
|
- if (err) {
|
|
|
|
- mlx4_err(dev, "QUERY_FUNC_CAP port command failed for port %d, aborting (%d)\n",
|
|
|
|
- i, err);
|
|
|
|
- goto err_mem;
|
|
|
|
- }
|
|
|
|
- dev->caps.qp0_qkey[i - 1] = func_cap.qp0_qkey;
|
|
|
|
- dev->caps.qp0_tunnel[i - 1] = func_cap.qp0_tunnel_qpn;
|
|
|
|
- dev->caps.qp0_proxy[i - 1] = func_cap.qp0_proxy_qpn;
|
|
|
|
- dev->caps.qp1_tunnel[i - 1] = func_cap.qp1_tunnel_qpn;
|
|
|
|
- dev->caps.qp1_proxy[i - 1] = func_cap.qp1_proxy_qpn;
|
|
|
|
- dev->caps.port_mask[i] = dev->caps.port_type[i];
|
|
|
|
- dev->caps.phys_port_id[i] = func_cap.phys_port_id;
|
|
|
|
- err = mlx4_get_slave_pkey_gid_tbl_len(dev, i,
|
|
|
|
- &dev->caps.gid_table_len[i],
|
|
|
|
- &dev->caps.pkey_table_len[i]);
|
|
|
|
- if (err)
|
|
|
|
- goto err_mem;
|
|
|
|
|
|
+ err = mlx4_slave_special_qp_cap(dev);
|
|
|
|
+ if (err) {
|
|
|
|
+ mlx4_err(dev, "Set special QP caps failed. aborting\n");
|
|
|
|
+ goto free_mem;
|
|
}
|
|
}
|
|
|
|
|
|
if (dev->caps.uar_page_size * (dev->caps.num_uars -
|
|
if (dev->caps.uar_page_size * (dev->caps.num_uars -
|
|
@@ -970,7 +1000,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
|
|
goto err_mem;
|
|
goto err_mem;
|
|
}
|
|
}
|
|
|
|
|
|
- if (hca_param.dev_cap_enabled & MLX4_DEV_CAP_64B_EQE_ENABLED) {
|
|
|
|
|
|
+ if (hca_param->dev_cap_enabled & MLX4_DEV_CAP_64B_EQE_ENABLED) {
|
|
dev->caps.eqe_size = 64;
|
|
dev->caps.eqe_size = 64;
|
|
dev->caps.eqe_factor = 1;
|
|
dev->caps.eqe_factor = 1;
|
|
} else {
|
|
} else {
|
|
@@ -978,20 +1008,20 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
|
|
dev->caps.eqe_factor = 0;
|
|
dev->caps.eqe_factor = 0;
|
|
}
|
|
}
|
|
|
|
|
|
- if (hca_param.dev_cap_enabled & MLX4_DEV_CAP_64B_CQE_ENABLED) {
|
|
|
|
|
|
+ if (hca_param->dev_cap_enabled & MLX4_DEV_CAP_64B_CQE_ENABLED) {
|
|
dev->caps.cqe_size = 64;
|
|
dev->caps.cqe_size = 64;
|
|
dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_LARGE_CQE;
|
|
dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_LARGE_CQE;
|
|
} else {
|
|
} else {
|
|
dev->caps.cqe_size = 32;
|
|
dev->caps.cqe_size = 32;
|
|
}
|
|
}
|
|
|
|
|
|
- if (hca_param.dev_cap_enabled & MLX4_DEV_CAP_EQE_STRIDE_ENABLED) {
|
|
|
|
- dev->caps.eqe_size = hca_param.eqe_size;
|
|
|
|
|
|
+ if (hca_param->dev_cap_enabled & MLX4_DEV_CAP_EQE_STRIDE_ENABLED) {
|
|
|
|
+ dev->caps.eqe_size = hca_param->eqe_size;
|
|
dev->caps.eqe_factor = 0;
|
|
dev->caps.eqe_factor = 0;
|
|
}
|
|
}
|
|
|
|
|
|
- if (hca_param.dev_cap_enabled & MLX4_DEV_CAP_CQE_STRIDE_ENABLED) {
|
|
|
|
- dev->caps.cqe_size = hca_param.cqe_size;
|
|
|
|
|
|
+ if (hca_param->dev_cap_enabled & MLX4_DEV_CAP_CQE_STRIDE_ENABLED) {
|
|
|
|
+ dev->caps.cqe_size = hca_param->cqe_size;
|
|
/* User still need to know when CQE > 32B */
|
|
/* User still need to know when CQE > 32B */
|
|
dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_LARGE_CQE;
|
|
dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_LARGE_CQE;
|
|
}
|
|
}
|
|
@@ -999,31 +1029,27 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
|
|
dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS;
|
|
dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS;
|
|
mlx4_warn(dev, "Timestamping is not supported in slave mode\n");
|
|
mlx4_warn(dev, "Timestamping is not supported in slave mode\n");
|
|
|
|
|
|
- slave_adjust_steering_mode(dev, &dev_cap, &hca_param);
|
|
|
|
|
|
+ dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_USER_MAC_EN;
|
|
|
|
+ mlx4_dbg(dev, "User MAC FW update is not supported in slave mode\n");
|
|
|
|
+
|
|
|
|
+ slave_adjust_steering_mode(dev, dev_cap, hca_param);
|
|
mlx4_dbg(dev, "RSS support for IP fragments is %s\n",
|
|
mlx4_dbg(dev, "RSS support for IP fragments is %s\n",
|
|
- hca_param.rss_ip_frags ? "on" : "off");
|
|
|
|
|
|
+ hca_param->rss_ip_frags ? "on" : "off");
|
|
|
|
|
|
- if (func_cap.extra_flags & MLX4_QUERY_FUNC_FLAGS_BF_RES_QP &&
|
|
|
|
|
|
+ if (func_cap->extra_flags & MLX4_QUERY_FUNC_FLAGS_BF_RES_QP &&
|
|
dev->caps.bf_reg_size)
|
|
dev->caps.bf_reg_size)
|
|
dev->caps.alloc_res_qp_mask |= MLX4_RESERVE_ETH_BF_QP;
|
|
dev->caps.alloc_res_qp_mask |= MLX4_RESERVE_ETH_BF_QP;
|
|
|
|
|
|
- if (func_cap.extra_flags & MLX4_QUERY_FUNC_FLAGS_A0_RES_QP)
|
|
|
|
|
|
+ if (func_cap->extra_flags & MLX4_QUERY_FUNC_FLAGS_A0_RES_QP)
|
|
dev->caps.alloc_res_qp_mask |= MLX4_RESERVE_A0_QP;
|
|
dev->caps.alloc_res_qp_mask |= MLX4_RESERVE_A0_QP;
|
|
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
err_mem:
|
|
err_mem:
|
|
- kfree(dev->caps.qp0_qkey);
|
|
|
|
- kfree(dev->caps.qp0_tunnel);
|
|
|
|
- kfree(dev->caps.qp0_proxy);
|
|
|
|
- kfree(dev->caps.qp1_tunnel);
|
|
|
|
- kfree(dev->caps.qp1_proxy);
|
|
|
|
- dev->caps.qp0_qkey = NULL;
|
|
|
|
- dev->caps.qp0_tunnel = NULL;
|
|
|
|
- dev->caps.qp0_proxy = NULL;
|
|
|
|
- dev->caps.qp1_tunnel = NULL;
|
|
|
|
- dev->caps.qp1_proxy = NULL;
|
|
|
|
-
|
|
|
|
|
|
+ if (err)
|
|
|
|
+ mlx4_slave_destroy_special_qp_cap(dev);
|
|
|
|
+free_mem:
|
|
|
|
+ kfree(hca_param);
|
|
|
|
+ kfree(func_cap);
|
|
|
|
+ kfree(dev_cap);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2407,13 +2433,8 @@ unmap_bf:
|
|
unmap_internal_clock(dev);
|
|
unmap_internal_clock(dev);
|
|
unmap_bf_area(dev);
|
|
unmap_bf_area(dev);
|
|
|
|
|
|
- if (mlx4_is_slave(dev)) {
|
|
|
|
- kfree(dev->caps.qp0_qkey);
|
|
|
|
- kfree(dev->caps.qp0_tunnel);
|
|
|
|
- kfree(dev->caps.qp0_proxy);
|
|
|
|
- kfree(dev->caps.qp1_tunnel);
|
|
|
|
- kfree(dev->caps.qp1_proxy);
|
|
|
|
- }
|
|
|
|
|
|
+ if (mlx4_is_slave(dev))
|
|
|
|
+ mlx4_slave_destroy_special_qp_cap(dev);
|
|
|
|
|
|
err_close:
|
|
err_close:
|
|
if (mlx4_is_slave(dev))
|
|
if (mlx4_is_slave(dev))
|
|
@@ -3596,13 +3617,8 @@ err_master_mfunc:
|
|
mlx4_multi_func_cleanup(dev);
|
|
mlx4_multi_func_cleanup(dev);
|
|
}
|
|
}
|
|
|
|
|
|
- if (mlx4_is_slave(dev)) {
|
|
|
|
- kfree(dev->caps.qp0_qkey);
|
|
|
|
- kfree(dev->caps.qp0_tunnel);
|
|
|
|
- kfree(dev->caps.qp0_proxy);
|
|
|
|
- kfree(dev->caps.qp1_tunnel);
|
|
|
|
- kfree(dev->caps.qp1_proxy);
|
|
|
|
- }
|
|
|
|
|
|
+ if (mlx4_is_slave(dev))
|
|
|
|
+ mlx4_slave_destroy_special_qp_cap(dev);
|
|
|
|
|
|
err_close:
|
|
err_close:
|
|
mlx4_close_hca(dev);
|
|
mlx4_close_hca(dev);
|
|
@@ -3942,11 +3958,7 @@ static void mlx4_unload_one(struct pci_dev *pdev)
|
|
if (!mlx4_is_slave(dev))
|
|
if (!mlx4_is_slave(dev))
|
|
mlx4_free_ownership(dev);
|
|
mlx4_free_ownership(dev);
|
|
|
|
|
|
- kfree(dev->caps.qp0_qkey);
|
|
|
|
- kfree(dev->caps.qp0_tunnel);
|
|
|
|
- kfree(dev->caps.qp0_proxy);
|
|
|
|
- kfree(dev->caps.qp1_tunnel);
|
|
|
|
- kfree(dev->caps.qp1_proxy);
|
|
|
|
|
|
+ mlx4_slave_destroy_special_qp_cap(dev);
|
|
kfree(dev->dev_vfs);
|
|
kfree(dev->dev_vfs);
|
|
|
|
|
|
mlx4_clean_dev(dev);
|
|
mlx4_clean_dev(dev);
|