Commit 0fe3e204 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlx4-HA-LAG-SRIOV-VF'

Or Gerlitz says:

====================
Add HA and LAG support for mlx4 SRIOV VFs

This series is built upon the code added in commit ce388fff "Merge branch
'mlx4-next'" which added HA and LAG support to mlx4 RoCE and SRIOV services.

We add HA and Link Aggregation support to single ported mlx4 Ethernet VFs.

In this case, the PF Ethernet interfaces are bonded, the VFs see single
port HW devices (already supported) -- however, now this port is highly
available. This means that all VF HW QPs (both VF Ethernet driver and VF
RoCE / RAW QPs) are subject to the V2P (Virtual-To-Physical) mapping which
is managed by the PF driver, and hence resilient across link failures and
such events.

When bonding operates in Dynamic link aggregation (802.3ad) mode, traffic
from each VF will go over the VF "base port" (the port this VF is assigned
to by the admin) as long as this port is up. When the port fails, traffic
from all VFs that are defined on this port will move to the other port, and
be back to their base-port when it recovers.

Moni and Or.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0d76d6e8 e57968a1
......@@ -40,6 +40,7 @@
#include <linux/gfp.h>
#include <rdma/ib_pma.h>
#include <linux/mlx4/driver.h>
#include "mlx4_ib.h"
enum {
......@@ -606,8 +607,8 @@ static int mlx4_ib_demux_mad(struct ib_device *ibdev, u8 port,
struct ib_mad *mad)
{
struct mlx4_ib_dev *dev = to_mdev(ibdev);
int err;
int slave;
int err, other_port;
int slave = -1;
u8 *slave_id;
int is_eth = 0;
......@@ -625,7 +626,17 @@ static int mlx4_ib_demux_mad(struct ib_device *ibdev, u8 port,
mlx4_ib_warn(ibdev, "RoCE mgmt class is not CM\n");
return -EINVAL;
}
if (mlx4_get_slave_from_roce_gid(dev->dev, port, grh->dgid.raw, &slave)) {
err = mlx4_get_slave_from_roce_gid(dev->dev, port, grh->dgid.raw, &slave);
if (err && mlx4_is_mf_bonded(dev->dev)) {
other_port = (port == 1) ? 2 : 1;
err = mlx4_get_slave_from_roce_gid(dev->dev, other_port, grh->dgid.raw, &slave);
if (!err) {
port = other_port;
pr_debug("resolved slave %d from gid %pI6 wire port %d other %d\n",
slave, grh->dgid.raw, port, other_port);
}
}
if (err) {
mlx4_ib_warn(ibdev, "failed matching grh\n");
return -ENOENT;
}
......
......@@ -151,6 +151,17 @@ void mlx4_gen_slave_eqe(struct work_struct *work)
eqe = next_slave_event_eqe(slave_eq)) {
slave = eqe->slave_id;
if (eqe->type == MLX4_EVENT_TYPE_PORT_CHANGE &&
eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN &&
mlx4_is_bonded(dev)) {
struct mlx4_port_cap port_cap;
if (!mlx4_QUERY_PORT(dev, 1, &port_cap) && port_cap.link_state)
goto consume;
if (!mlx4_QUERY_PORT(dev, 2, &port_cap) && port_cap.link_state)
goto consume;
}
/* All active slaves need to receive the event */
if (slave == ALL_SLAVES) {
for (i = 0; i <= dev->persist->num_vfs; i++) {
......@@ -174,6 +185,7 @@ void mlx4_gen_slave_eqe(struct work_struct *work)
mlx4_warn(dev, "Failed to generate event for slave %d\n",
slave);
}
consume:
++slave_eq->cons;
}
}
......@@ -594,7 +606,9 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
break;
for (i = 0; i < dev->persist->num_vfs + 1;
i++) {
if (!test_bit(i, slaves_port.slaves))
int reported_port = mlx4_is_bonded(dev) ? 1 : mlx4_phys_to_slave_port(dev, i, port);
if (!test_bit(i, slaves_port.slaves) && !mlx4_is_bonded(dev))
continue;
if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) {
if (i == mlx4_master_func_num(dev))
......@@ -606,7 +620,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
eqe->event.port_change.port =
cpu_to_be32(
(be32_to_cpu(eqe->event.port_change.port) & 0xFFFFFFF)
| (mlx4_phys_to_slave_port(dev, i, port) << 28));
| (reported_port << 28));
mlx4_slave_event(dev, i, eqe);
}
} else { /* IB port */
......@@ -636,7 +650,9 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
for (i = 0;
i < dev->persist->num_vfs + 1;
i++) {
if (!test_bit(i, slaves_port.slaves))
int reported_port = mlx4_is_bonded(dev) ? 1 : mlx4_phys_to_slave_port(dev, i, port);
if (!test_bit(i, slaves_port.slaves) && !mlx4_is_bonded(dev))
continue;
if (i == mlx4_master_func_num(dev))
continue;
......@@ -645,7 +661,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
eqe->event.port_change.port =
cpu_to_be32(
(be32_to_cpu(eqe->event.port_change.port) & 0xFFFFFFF)
| (mlx4_phys_to_slave_port(dev, i, port) << 28));
| (reported_port << 28));
mlx4_slave_event(dev, i, eqe);
}
}
......
......@@ -1104,6 +1104,7 @@ int mlx4_QUERY_PORT(struct mlx4_dev *dev, int port, struct mlx4_port_cap *port_c
goto out;
MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET);
port_cap->link_state = (field & 0x80) >> 7;
port_cap->supported_port_types = field & 3;
port_cap->suggested_type = (field >> 3) & 1;
port_cap->default_sense = (field >> 4) & 1;
......@@ -1310,6 +1311,15 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
port_type |= MLX4_PORT_LINK_UP_MASK;
else if (IFLA_VF_LINK_STATE_DISABLE == admin_link_state)
port_type &= ~MLX4_PORT_LINK_UP_MASK;
else if (IFLA_VF_LINK_STATE_AUTO == admin_link_state && mlx4_is_bonded(dev)) {
int other_port = (port == 1) ? 2 : 1;
struct mlx4_port_cap port_cap;
err = mlx4_QUERY_PORT(dev, other_port, &port_cap);
if (err)
goto out;
port_type |= (port_cap.link_state << 7);
}
MLX4_PUT(outbox->buf, port_type,
QUERY_PORT_SUPPORTED_TYPE_OFFSET);
......@@ -1325,7 +1335,7 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
MLX4_PUT(outbox->buf, short_field,
QUERY_PORT_CUR_MAX_PKEY_OFFSET);
}
out:
return err;
}
......
......@@ -44,6 +44,7 @@ struct mlx4_mod_stat_cfg {
};
struct mlx4_port_cap {
u8 link_state;
u8 supported_port_types;
u8 suggested_type;
u8 default_sense;
......
......@@ -1221,6 +1221,76 @@ static ssize_t set_port_ib_mtu(struct device *dev,
return err ? err : count;
}
/* bond for multi-function device */
#define MAX_MF_BOND_ALLOWED_SLAVES 63
static int mlx4_mf_bond(struct mlx4_dev *dev)
{
int err = 0;
struct mlx4_slaves_pport slaves_port1;
struct mlx4_slaves_pport slaves_port2;
DECLARE_BITMAP(slaves_port_1_2, MLX4_MFUNC_MAX);
slaves_port1 = mlx4_phys_to_slaves_pport(dev, 1);
slaves_port2 = mlx4_phys_to_slaves_pport(dev, 2);
bitmap_and(slaves_port_1_2,
slaves_port1.slaves, slaves_port2.slaves,
dev->persist->num_vfs + 1);
/* only single port vfs are allowed */
if (bitmap_weight(slaves_port_1_2, dev->persist->num_vfs + 1) > 1) {
mlx4_warn(dev, "HA mode unsupported for dual ported VFs\n");
return -EINVAL;
}
/* limit on maximum allowed VFs */
if ((bitmap_weight(slaves_port1.slaves, dev->persist->num_vfs + 1) +
bitmap_weight(slaves_port2.slaves, dev->persist->num_vfs + 1)) >
MAX_MF_BOND_ALLOWED_SLAVES)
return -EINVAL;
if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) {
mlx4_warn(dev, "HA mode unsupported for NON DMFS steering\n");
return -EINVAL;
}
err = mlx4_bond_mac_table(dev);
if (err)
return err;
err = mlx4_bond_vlan_table(dev);
if (err)
goto err1;
err = mlx4_bond_fs_rules(dev);
if (err)
goto err2;
return 0;
err2:
(void)mlx4_unbond_vlan_table(dev);
err1:
(void)mlx4_unbond_mac_table(dev);
return err;
}
static int mlx4_mf_unbond(struct mlx4_dev *dev)
{
int ret, ret1;
ret = mlx4_unbond_fs_rules(dev);
if (ret)
mlx4_warn(dev, "multifunction unbond for flow rules failedi (%d)\n", ret);
ret1 = mlx4_unbond_mac_table(dev);
if (ret1) {
mlx4_warn(dev, "multifunction unbond for MAC table failed (%d)\n", ret1);
ret = ret1;
}
ret1 = mlx4_unbond_vlan_table(dev);
if (ret1) {
mlx4_warn(dev, "multifunction unbond for VLAN table failed (%d)\n", ret1);
ret = ret1;
}
return ret;
}
int mlx4_bond(struct mlx4_dev *dev)
{
int ret = 0;
......@@ -1228,16 +1298,23 @@ int mlx4_bond(struct mlx4_dev *dev)
mutex_lock(&priv->bond_mutex);
if (!mlx4_is_bonded(dev))
if (!mlx4_is_bonded(dev)) {
ret = mlx4_do_bond(dev, true);
else
ret = 0;
if (ret)
mlx4_err(dev, "Failed to bond device: %d\n", ret);
if (!ret && mlx4_is_master(dev)) {
ret = mlx4_mf_bond(dev);
if (ret) {
mlx4_err(dev, "bond for multifunction failed\n");
mlx4_do_bond(dev, false);
}
}
}
mutex_unlock(&priv->bond_mutex);
if (ret)
mlx4_err(dev, "Failed to bond device: %d\n", ret);
else
if (!ret)
mlx4_dbg(dev, "Device is bonded\n");
return ret;
}
EXPORT_SYMBOL_GPL(mlx4_bond);
......@@ -1249,14 +1326,24 @@ int mlx4_unbond(struct mlx4_dev *dev)
mutex_lock(&priv->bond_mutex);
if (mlx4_is_bonded(dev))
if (mlx4_is_bonded(dev)) {
int ret2 = 0;
ret = mlx4_do_bond(dev, false);
if (ret)
mlx4_err(dev, "Failed to unbond device: %d\n", ret);
if (mlx4_is_master(dev))
ret2 = mlx4_mf_unbond(dev);
if (ret2) {
mlx4_warn(dev, "Failed to unbond device for multifunction (%d)\n", ret2);
ret = ret2;
}
}
mutex_unlock(&priv->bond_mutex);
if (ret)
mlx4_err(dev, "Failed to unbond device: %d\n", ret);
else
if (!ret)
mlx4_dbg(dev, "Device is unbonded\n");
return ret;
}
EXPORT_SYMBOL_GPL(mlx4_unbond);
......
......@@ -736,6 +736,7 @@ struct mlx4_catas_err {
struct mlx4_mac_table {
__be64 entries[MLX4_MAX_MAC_NUM];
int refs[MLX4_MAX_MAC_NUM];
bool is_dup[MLX4_MAX_MAC_NUM];
struct mutex mutex;
int total;
int max;
......@@ -758,6 +759,7 @@ struct mlx4_roce_gid_table {
struct mlx4_vlan_table {
__be32 entries[MLX4_MAX_VLAN_NUM];
int refs[MLX4_MAX_VLAN_NUM];
int is_dup[MLX4_MAX_VLAN_NUM];
struct mutex mutex;
int total;
int max;
......@@ -1225,6 +1227,10 @@ void mlx4_init_roce_gid_table(struct mlx4_dev *dev,
struct mlx4_roce_gid_table *table);
void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan);
int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index);
int mlx4_bond_vlan_table(struct mlx4_dev *dev);
int mlx4_unbond_vlan_table(struct mlx4_dev *dev);
int mlx4_bond_mac_table(struct mlx4_dev *dev);
int mlx4_unbond_mac_table(struct mlx4_dev *dev);
int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port, int pkey_tbl_sz);
/* resource tracker functions*/
......@@ -1385,6 +1391,8 @@ int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port);
int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave);
int mlx4_config_mad_demux(struct mlx4_dev *dev);
int mlx4_do_bond(struct mlx4_dev *dev, bool enable);
int mlx4_bond_fs_rules(struct mlx4_dev *dev);
int mlx4_unbond_fs_rules(struct mlx4_dev *dev);
enum mlx4_zone_flags {
MLX4_ZONE_ALLOW_ALLOC_FROM_LOWER_PRIO = 1UL << 0,
......
This diff is collapsed.
......@@ -222,6 +222,13 @@ enum res_fs_rule_states {
struct res_fs_rule {
struct res_common com;
int qpn;
/* VF DMFS mbox with port flipped */
void *mirr_mbox;
/* > 0 --> apply mirror when getting into HA mode */
/* = 0 --> un-apply mirror when getting out of HA mode */
u32 mirr_mbox_size;
struct list_head mirr_list;
u64 mirr_rule_id;
};
static void *res_tracker_lookup(struct rb_root *root, u64 res_id)
......@@ -4284,6 +4291,22 @@ int mlx4_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave,
return err;
}
static u32 qp_attach_mbox_size(void *mbox)
{
u32 size = sizeof(struct mlx4_net_trans_rule_hw_ctrl);
struct _rule_hw *rule_header;
rule_header = (struct _rule_hw *)(mbox + size);
while (rule_header->size) {
size += rule_header->size * sizeof(u32);
rule_header += 1;
}
return size;
}
static int mlx4_do_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule);
int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
......@@ -4300,6 +4323,8 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_net_trans_rule_hw_ctrl *ctrl;
struct _rule_hw *rule_header;
int header_id;
struct res_fs_rule *rrule;
u32 mbox_size;
if (dev->caps.steering_mode !=
MLX4_STEERING_MODE_DEVICE_MANAGED)
......@@ -4328,7 +4353,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
case MLX4_NET_TRANS_RULE_ID_ETH:
if (validate_eth_header_mac(slave, rule_header, rlist)) {
err = -EINVAL;
goto err_put;
goto err_put_qp;
}
break;
case MLX4_NET_TRANS_RULE_ID_IB:
......@@ -4339,7 +4364,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
pr_warn("Can't attach FS rule without L2 headers, adding L2 header\n");
if (add_eth_header(dev, slave, inbox, rlist, header_id)) {
err = -EINVAL;
goto err_put;
goto err_put_qp;
}
vhcr->in_modifier +=
sizeof(struct mlx4_net_trans_rule_hw_eth) >> 2;
......@@ -4347,7 +4372,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
default:
pr_err("Corrupted mailbox\n");
err = -EINVAL;
goto err_put;
goto err_put_qp;
}
execute:
......@@ -4356,23 +4381,69 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
MLX4_CMD_NATIVE);
if (err)
goto err_put;
goto err_put_qp;
err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn);
if (err) {
mlx4_err(dev, "Fail to add flow steering resources\n");
/* detach rule*/
goto err_detach;
}
err = get_res(dev, slave, vhcr->out_param, RES_FS_RULE, &rrule);
if (err)
goto err_detach;
mbox_size = qp_attach_mbox_size(inbox->buf);
rrule->mirr_mbox = kmalloc(mbox_size, GFP_KERNEL);
if (!rrule->mirr_mbox) {
err = -ENOMEM;
goto err_put_rule;
}
rrule->mirr_mbox_size = mbox_size;
rrule->mirr_rule_id = 0;
memcpy(rrule->mirr_mbox, inbox->buf, mbox_size);
/* set different port */
ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)rrule->mirr_mbox;
if (ctrl->port == 1)
ctrl->port = 2;
else
ctrl->port = 1;
if (mlx4_is_bonded(dev))
mlx4_do_mirror_rule(dev, rrule);
atomic_inc(&rqp->ref_count);
err_put_rule:
put_res(dev, slave, vhcr->out_param, RES_FS_RULE);
err_detach:
/* detach rule on error */
if (err)
mlx4_cmd(dev, vhcr->out_param, 0, 0,
MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
MLX4_CMD_NATIVE);
goto err_put;
}
atomic_inc(&rqp->ref_count);
err_put:
err_put_qp:
put_res(dev, slave, qpn, RES_QP);
return err;
}
static int mlx4_undo_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule)
{
int err;
err = rem_res_range(dev, fs_rule->com.owner, fs_rule->com.res_id, 1, RES_FS_RULE, 0);
if (err) {
mlx4_err(dev, "Fail to remove flow steering resources\n");
return err;
}
mlx4_cmd(dev, fs_rule->com.res_id, 0, 0, MLX4_QP_FLOW_STEERING_DETACH,
MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
return 0;
}
int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave,
struct mlx4_vhcr *vhcr,
struct mlx4_cmd_mailbox *inbox,
......@@ -4382,6 +4453,7 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave,
int err;
struct res_qp *rqp;
struct res_fs_rule *rrule;
u64 mirr_reg_id;
if (dev->caps.steering_mode !=
MLX4_STEERING_MODE_DEVICE_MANAGED)
......@@ -4390,12 +4462,30 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave,
err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule);
if (err)
return err;
if (!rrule->mirr_mbox) {
mlx4_err(dev, "Mirror rules cannot be removed explicitly\n");
put_res(dev, slave, vhcr->in_param, RES_FS_RULE);
return -EINVAL;
}
mirr_reg_id = rrule->mirr_rule_id;
kfree(rrule->mirr_mbox);
/* Release the rule form busy state before removal */
put_res(dev, slave, vhcr->in_param, RES_FS_RULE);
err = get_res(dev, slave, rrule->qpn, RES_QP, &rqp);
if (err)
return err;
if (mirr_reg_id && mlx4_is_bonded(dev)) {
err = get_res(dev, slave, mirr_reg_id, RES_FS_RULE, &rrule);
if (err) {
mlx4_err(dev, "Fail to get resource of mirror rule\n");
} else {
put_res(dev, slave, mirr_reg_id, RES_FS_RULE);
mlx4_undo_mirror_rule(dev, rrule);
}
}
err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 0);
if (err) {
mlx4_err(dev, "Fail to remove flow steering resources\n");
......@@ -4833,6 +4923,91 @@ static void rem_slave_mtts(struct mlx4_dev *dev, int slave)
spin_unlock_irq(mlx4_tlock(dev));
}
static int mlx4_do_mirror_rule(struct mlx4_dev *dev, struct res_fs_rule *fs_rule)
{
struct mlx4_cmd_mailbox *mailbox;
int err;
struct res_fs_rule *mirr_rule;
u64 reg_id;
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox))
return PTR_ERR(mailbox);
if (!fs_rule->mirr_mbox) {
mlx4_err(dev, "rule mirroring mailbox is null\n");
return -EINVAL;
}
memcpy(mailbox->buf, fs_rule->mirr_mbox, fs_rule->mirr_mbox_size);
err = mlx4_cmd_imm(dev, mailbox->dma, &reg_id, fs_rule->mirr_mbox_size >> 2, 0,
MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A,
MLX4_CMD_NATIVE);
mlx4_free_cmd_mailbox(dev, mailbox);
if (err)
goto err;
err = add_res_range(dev, fs_rule->com.owner, reg_id, 1, RES_FS_RULE, fs_rule->qpn);
if (err)
goto err_detach;
err = get_res(dev, fs_rule->com.owner, reg_id, RES_FS_RULE, &mirr_rule);
if (err)
goto err_rem;
fs_rule->mirr_rule_id = reg_id;
mirr_rule->mirr_rule_id = 0;
mirr_rule->mirr_mbox_size = 0;
mirr_rule->mirr_mbox = NULL;
put_res(dev, fs_rule->com.owner, reg_id, RES_FS_RULE);
return 0;
err_rem:
rem_res_range(dev, fs_rule->com.owner, reg_id, 1, RES_FS_RULE, 0);
err_detach:
mlx4_cmd(dev, reg_id, 0, 0, MLX4_QP_FLOW_STEERING_DETACH,
MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
err:
return err;
}
static int mlx4_mirror_fs_rules(struct mlx4_dev *dev, bool bond)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_resource_tracker *tracker =
&priv->mfunc.master.res_tracker;
struct rb_root *root = &tracker->res_tree[RES_FS_RULE];
struct rb_node *p;
struct res_fs_rule *fs_rule;
int err = 0;
LIST_HEAD(mirr_list);
for (p = rb_first(root); p; p = rb_next(p)) {
fs_rule = rb_entry(p, struct res_fs_rule, com.node);
if ((bond && fs_rule->mirr_mbox_size) ||
(!bond && !fs_rule->mirr_mbox_size))
list_add_tail(&fs_rule->mirr_list, &mirr_list);
}
list_for_each_entry(fs_rule, &mirr_list, mirr_list) {
if (bond)
err += mlx4_do_mirror_rule(dev, fs_rule);
else
err += mlx4_undo_mirror_rule(dev, fs_rule);
}
return err;
}
int mlx4_bond_fs_rules(struct mlx4_dev *dev)
{
return mlx4_mirror_fs_rules(dev, true);
}
int mlx4_unbond_fs_rules(struct mlx4_dev *dev)
{
return mlx4_mirror_fs_rules(dev, false);
}
static void rem_slave_fs_rule(struct mlx4_dev *dev, int slave)
{
struct mlx4_priv *priv = mlx4_priv(dev);
......
......@@ -75,6 +75,11 @@ static inline int mlx4_is_bonded(struct mlx4_dev *dev)
return !!(dev->flags & MLX4_FLAG_BONDED);
}
static inline int mlx4_is_mf_bonded(struct mlx4_dev *dev)
{
return (mlx4_is_bonded(dev) && mlx4_is_mfunc(dev));
}
struct mlx4_port_map {
u8 port1;
u8 port2;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment