|
@@ -61,6 +61,7 @@ void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table)
|
|
|
for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
|
|
|
table->entries[i] = 0;
|
|
|
table->refs[i] = 0;
|
|
|
+ table->is_dup[i] = false;
|
|
|
}
|
|
|
table->max = 1 << dev->caps.log_num_macs;
|
|
|
table->total = 0;
|
|
@@ -74,6 +75,7 @@ void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
|
|
|
for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
|
|
|
table->entries[i] = 0;
|
|
|
table->refs[i] = 0;
|
|
|
+ table->is_dup[i] = false;
|
|
|
}
|
|
|
table->max = (1 << dev->caps.log_num_vlans) - MLX4_VLAN_REGULAR;
|
|
|
table->total = 0;
|
|
@@ -159,21 +161,94 @@ int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(mlx4_find_cached_mac);
|
|
|
|
|
|
+static bool mlx4_need_mf_bond(struct mlx4_dev *dev)
|
|
|
+{
|
|
|
+ int i, num_eth_ports = 0;
|
|
|
+
|
|
|
+ if (!mlx4_is_mfunc(dev))
|
|
|
+ return false;
|
|
|
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
|
|
|
+ ++num_eth_ports;
|
|
|
+
|
|
|
+ return (num_eth_ports == 2) ? true : false;
|
|
|
+}
|
|
|
+
|
|
|
int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
|
|
|
{
|
|
|
struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
|
|
|
struct mlx4_mac_table *table = &info->mac_table;
|
|
|
int i, err = 0;
|
|
|
int free = -1;
|
|
|
+ int free_for_dup = -1;
|
|
|
+ bool dup = mlx4_is_mf_bonded(dev);
|
|
|
+ u8 dup_port = (port == 1) ? 2 : 1;
|
|
|
+ struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
|
|
|
+ bool need_mf_bond = mlx4_need_mf_bond(dev);
|
|
|
+ bool can_mf_bond = true;
|
|
|
+
|
|
|
+ mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d %s duplicate\n",
|
|
|
+ (unsigned long long)mac, port,
|
|
|
+ dup ? "with" : "without");
|
|
|
+
|
|
|
+ if (need_mf_bond) {
|
|
|
+ if (port == 1) {
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ mutex_lock(&dup_table->mutex);
|
|
|
+ } else {
|
|
|
+ mutex_lock(&dup_table->mutex);
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (need_mf_bond) {
|
|
|
+ int index_at_port = -1;
|
|
|
+ int index_at_dup_port = -1;
|
|
|
|
|
|
- mlx4_dbg(dev, "Registering MAC: 0x%llx for port %d\n",
|
|
|
- (unsigned long long) mac, port);
|
|
|
+ for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
|
|
|
+ if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))))
|
|
|
+ index_at_port = i;
|
|
|
+ if (((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]))))
|
|
|
+ index_at_dup_port = i;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* check that same mac is not in the tables at different indices */
|
|
|
+ if ((index_at_port != index_at_dup_port) &&
|
|
|
+ (index_at_port >= 0) &&
|
|
|
+ (index_at_dup_port >= 0))
|
|
|
+ can_mf_bond = false;
|
|
|
+
|
|
|
+ /* If the mac is already in the primary table, the slot must be
|
|
|
+ * available in the duplicate table as well.
|
|
|
+ */
|
|
|
+ if (index_at_port >= 0 && index_at_dup_port < 0 &&
|
|
|
+ dup_table->refs[index_at_port]) {
|
|
|
+ can_mf_bond = false;
|
|
|
+ }
|
|
|
+ /* If the mac is already in the duplicate table, check that the
|
|
|
+ * corresponding index is not occupied in the primary table, or
|
|
|
+ * the primary table already contains the mac at the same index.
|
|
|
+ * Otherwise, you cannot bond (primary contains a different mac
|
|
|
+ * at that index).
|
|
|
+ */
|
|
|
+ if (index_at_dup_port >= 0) {
|
|
|
+ if (!table->refs[index_at_dup_port] ||
|
|
|
+ ((MLX4_MAC_MASK & mac) == (MLX4_MAC_MASK & be64_to_cpu(table->entries[index_at_dup_port]))))
|
|
|
+ free_for_dup = index_at_dup_port;
|
|
|
+ else
|
|
|
+ can_mf_bond = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- mutex_lock(&table->mutex);
|
|
|
for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
|
|
|
if (!table->refs[i]) {
|
|
|
if (free < 0)
|
|
|
free = i;
|
|
|
+ if (free_for_dup < 0 && need_mf_bond && can_mf_bond) {
|
|
|
+ if (!dup_table->refs[i])
|
|
|
+ free_for_dup = i;
|
|
|
+ }
|
|
|
continue;
|
|
|
}
|
|
|
|
|
@@ -182,10 +257,30 @@ int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
|
|
|
/* MAC already registered, increment ref count */
|
|
|
err = i;
|
|
|
++table->refs[i];
|
|
|
+ if (dup) {
|
|
|
+ u64 dup_mac = MLX4_MAC_MASK & be64_to_cpu(dup_table->entries[i]);
|
|
|
+
|
|
|
+ if (dup_mac != mac || !dup_table->is_dup[i]) {
|
|
|
+ mlx4_warn(dev, "register mac: expect duplicate mac 0x%llx on port %d index %d\n",
|
|
|
+ mac, dup_port, i);
|
|
|
+ }
|
|
|
+ }
|
|
|
goto out;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (need_mf_bond && (free_for_dup < 0)) {
|
|
|
+ if (dup) {
|
|
|
+ mlx4_warn(dev, "Fail to allocate duplicate MAC table entry\n");
|
|
|
+ mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n");
|
|
|
+ dup = false;
|
|
|
+ }
|
|
|
+ can_mf_bond = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (need_mf_bond && can_mf_bond)
|
|
|
+ free = free_for_dup;
|
|
|
+
|
|
|
mlx4_dbg(dev, "Free MAC index is %d\n", free);
|
|
|
|
|
|
if (table->total == table->max) {
|
|
@@ -205,10 +300,35 @@ int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
|
|
|
goto out;
|
|
|
}
|
|
|
table->refs[free] = 1;
|
|
|
- err = free;
|
|
|
+ table->is_dup[free] = false;
|
|
|
++table->total;
|
|
|
+ if (dup) {
|
|
|
+ dup_table->refs[free] = 0;
|
|
|
+ dup_table->is_dup[free] = true;
|
|
|
+ dup_table->entries[free] = cpu_to_be64(mac | MLX4_MAC_VALID);
|
|
|
+
|
|
|
+ err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries);
|
|
|
+ if (unlikely(err)) {
|
|
|
+ mlx4_warn(dev, "Failed adding duplicate mac: 0x%llx\n", mac);
|
|
|
+ dup_table->is_dup[free] = false;
|
|
|
+ dup_table->entries[free] = 0;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ ++dup_table->total;
|
|
|
+ }
|
|
|
+ err = free;
|
|
|
out:
|
|
|
- mutex_unlock(&table->mutex);
|
|
|
+ if (need_mf_bond) {
|
|
|
+ if (port == 2) {
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ mutex_unlock(&dup_table->mutex);
|
|
|
+ } else {
|
|
|
+ mutex_unlock(&dup_table->mutex);
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ }
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(__mlx4_register_mac);
|
|
@@ -255,6 +375,9 @@ void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
|
|
|
struct mlx4_port_info *info;
|
|
|
struct mlx4_mac_table *table;
|
|
|
int index;
|
|
|
+ bool dup = mlx4_is_mf_bonded(dev);
|
|
|
+ u8 dup_port = (port == 1) ? 2 : 1;
|
|
|
+ struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
|
|
|
|
|
|
if (port < 1 || port > dev->caps.num_ports) {
|
|
|
mlx4_warn(dev, "invalid port number (%d), aborting...\n", port);
|
|
@@ -262,22 +385,59 @@ void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
|
|
|
}
|
|
|
info = &mlx4_priv(dev)->port[port];
|
|
|
table = &info->mac_table;
|
|
|
- mutex_lock(&table->mutex);
|
|
|
+
|
|
|
+ if (dup) {
|
|
|
+ if (port == 1) {
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ mutex_lock(&dup_table->mutex);
|
|
|
+ } else {
|
|
|
+ mutex_lock(&dup_table->mutex);
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ }
|
|
|
+
|
|
|
index = find_index(dev, table, mac);
|
|
|
|
|
|
if (validate_index(dev, table, index))
|
|
|
goto out;
|
|
|
- if (--table->refs[index]) {
|
|
|
+
|
|
|
+ if (--table->refs[index] || table->is_dup[index]) {
|
|
|
mlx4_dbg(dev, "Have more references for index %d, no need to modify mac table\n",
|
|
|
index);
|
|
|
+ if (!table->refs[index])
|
|
|
+ dup_table->is_dup[index] = false;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
table->entries[index] = 0;
|
|
|
- mlx4_set_port_mac_table(dev, port, table->entries);
|
|
|
+ if (mlx4_set_port_mac_table(dev, port, table->entries))
|
|
|
+ mlx4_warn(dev, "Fail to set mac in port %d during unregister\n", port);
|
|
|
--table->total;
|
|
|
+
|
|
|
+ if (dup) {
|
|
|
+ dup_table->is_dup[index] = false;
|
|
|
+ if (dup_table->refs[index])
|
|
|
+ goto out;
|
|
|
+ dup_table->entries[index] = 0;
|
|
|
+ if (mlx4_set_port_mac_table(dev, dup_port, dup_table->entries))
|
|
|
+ mlx4_warn(dev, "Fail to set mac in duplicate port %d during unregister\n", dup_port);
|
|
|
+
|
|
|
+ --table->total;
|
|
|
+ }
|
|
|
out:
|
|
|
- mutex_unlock(&table->mutex);
|
|
|
+ if (dup) {
|
|
|
+ if (port == 2) {
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ mutex_unlock(&dup_table->mutex);
|
|
|
+ } else {
|
|
|
+ mutex_unlock(&dup_table->mutex);
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ }
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(__mlx4_unregister_mac);
|
|
|
|
|
@@ -311,9 +471,22 @@ int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
|
|
|
struct mlx4_mac_table *table = &info->mac_table;
|
|
|
int index = qpn - info->base_qpn;
|
|
|
int err = 0;
|
|
|
+ bool dup = mlx4_is_mf_bonded(dev);
|
|
|
+ u8 dup_port = (port == 1) ? 2 : 1;
|
|
|
+ struct mlx4_mac_table *dup_table = &mlx4_priv(dev)->port[dup_port].mac_table;
|
|
|
|
|
|
/* CX1 doesn't support multi-functions */
|
|
|
- mutex_lock(&table->mutex);
|
|
|
+ if (dup) {
|
|
|
+ if (port == 1) {
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ mutex_lock(&dup_table->mutex);
|
|
|
+ } else {
|
|
|
+ mutex_lock(&dup_table->mutex);
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ }
|
|
|
|
|
|
err = validate_index(dev, table, index);
|
|
|
if (err)
|
|
@@ -326,9 +499,30 @@ int __mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac)
|
|
|
mlx4_err(dev, "Failed adding MAC: 0x%llx\n",
|
|
|
(unsigned long long) new_mac);
|
|
|
table->entries[index] = 0;
|
|
|
+ } else {
|
|
|
+ if (dup) {
|
|
|
+ dup_table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
|
|
|
+
|
|
|
+ err = mlx4_set_port_mac_table(dev, dup_port, dup_table->entries);
|
|
|
+ if (unlikely(err)) {
|
|
|
+ mlx4_err(dev, "Failed adding duplicate MAC: 0x%llx\n",
|
|
|
+ (unsigned long long)new_mac);
|
|
|
+ dup_table->entries[index] = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
out:
|
|
|
- mutex_unlock(&table->mutex);
|
|
|
+ if (dup) {
|
|
|
+ if (port == 2) {
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ mutex_unlock(&dup_table->mutex);
|
|
|
+ } else {
|
|
|
+ mutex_unlock(&dup_table->mutex);
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ }
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(__mlx4_replace_mac);
|
|
@@ -380,8 +574,28 @@ int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
|
|
|
struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
|
|
|
int i, err = 0;
|
|
|
int free = -1;
|
|
|
-
|
|
|
- mutex_lock(&table->mutex);
|
|
|
+ int free_for_dup = -1;
|
|
|
+ bool dup = mlx4_is_mf_bonded(dev);
|
|
|
+ u8 dup_port = (port == 1) ? 2 : 1;
|
|
|
+ struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table;
|
|
|
+ bool need_mf_bond = mlx4_need_mf_bond(dev);
|
|
|
+ bool can_mf_bond = true;
|
|
|
+
|
|
|
+ mlx4_dbg(dev, "Registering VLAN: %d for port %d %s duplicate\n",
|
|
|
+ vlan, port,
|
|
|
+ dup ? "with" : "without");
|
|
|
+
|
|
|
+ if (need_mf_bond) {
|
|
|
+ if (port == 1) {
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ mutex_lock(&dup_table->mutex);
|
|
|
+ } else {
|
|
|
+ mutex_lock(&dup_table->mutex);
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ }
|
|
|
|
|
|
if (table->total == table->max) {
|
|
|
/* No free vlan entries */
|
|
@@ -389,22 +603,85 @@ int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
+ if (need_mf_bond) {
|
|
|
+ int index_at_port = -1;
|
|
|
+ int index_at_dup_port = -1;
|
|
|
+
|
|
|
+ for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
|
|
|
+ if ((vlan == (MLX4_VLAN_MASK & be32_to_cpu(table->entries[i]))))
|
|
|
+ index_at_port = i;
|
|
|
+ if ((vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i]))))
|
|
|
+ index_at_dup_port = i;
|
|
|
+ }
|
|
|
+ /* check that same vlan is not in the tables at different indices */
|
|
|
+ if ((index_at_port != index_at_dup_port) &&
|
|
|
+ (index_at_port >= 0) &&
|
|
|
+ (index_at_dup_port >= 0))
|
|
|
+ can_mf_bond = false;
|
|
|
+
|
|
|
+ /* If the vlan is already in the primary table, the slot must be
|
|
|
+ * available in the duplicate table as well.
|
|
|
+ */
|
|
|
+ if (index_at_port >= 0 && index_at_dup_port < 0 &&
|
|
|
+ dup_table->refs[index_at_port]) {
|
|
|
+ can_mf_bond = false;
|
|
|
+ }
|
|
|
+ /* If the vlan is already in the duplicate table, check that the
|
|
|
+ * corresponding index is not occupied in the primary table, or
|
|
|
+ * the primary table already contains the vlan at the same index.
|
|
|
+ * Otherwise, you cannot bond (primary contains a different vlan
|
|
|
+ * at that index).
|
|
|
+ */
|
|
|
+ if (index_at_dup_port >= 0) {
|
|
|
+ if (!table->refs[index_at_dup_port] ||
|
|
|
+ (vlan == (MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[index_at_dup_port]))))
|
|
|
+ free_for_dup = index_at_dup_port;
|
|
|
+ else
|
|
|
+ can_mf_bond = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
for (i = MLX4_VLAN_REGULAR; i < MLX4_MAX_VLAN_NUM; i++) {
|
|
|
- if (free < 0 && (table->refs[i] == 0)) {
|
|
|
- free = i;
|
|
|
- continue;
|
|
|
+ if (!table->refs[i]) {
|
|
|
+ if (free < 0)
|
|
|
+ free = i;
|
|
|
+ if (free_for_dup < 0 && need_mf_bond && can_mf_bond) {
|
|
|
+ if (!dup_table->refs[i])
|
|
|
+ free_for_dup = i;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- if (table->refs[i] &&
|
|
|
+ if ((table->refs[i] || table->is_dup[i]) &&
|
|
|
(vlan == (MLX4_VLAN_MASK &
|
|
|
be32_to_cpu(table->entries[i])))) {
|
|
|
/* Vlan already registered, increase references count */
|
|
|
+ mlx4_dbg(dev, "vlan %u is already registered.\n", vlan);
|
|
|
*index = i;
|
|
|
++table->refs[i];
|
|
|
+ if (dup) {
|
|
|
+ u16 dup_vlan = MLX4_VLAN_MASK & be32_to_cpu(dup_table->entries[i]);
|
|
|
+
|
|
|
+ if (dup_vlan != vlan || !dup_table->is_dup[i]) {
|
|
|
+ mlx4_warn(dev, "register vlan: expected duplicate vlan %u on port %d index %d\n",
|
|
|
+ vlan, dup_port, i);
|
|
|
+ }
|
|
|
+ }
|
|
|
goto out;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (need_mf_bond && (free_for_dup < 0)) {
|
|
|
+ if (dup) {
|
|
|
+ mlx4_warn(dev, "Fail to allocate duplicate VLAN table entry\n");
|
|
|
+ mlx4_warn(dev, "High Availability for virtual functions may not work as expected\n");
|
|
|
+ dup = false;
|
|
|
+ }
|
|
|
+ can_mf_bond = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (need_mf_bond && can_mf_bond)
|
|
|
+ free = free_for_dup;
|
|
|
+
|
|
|
if (free < 0) {
|
|
|
err = -ENOMEM;
|
|
|
goto out;
|
|
@@ -412,6 +689,7 @@ int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
|
|
|
|
|
|
/* Register new VLAN */
|
|
|
table->refs[free] = 1;
|
|
|
+ table->is_dup[free] = false;
|
|
|
table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
|
|
|
|
|
|
err = mlx4_set_port_vlan_table(dev, port, table->entries);
|
|
@@ -421,11 +699,35 @@ int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
|
|
|
table->entries[free] = 0;
|
|
|
goto out;
|
|
|
}
|
|
|
+ ++table->total;
|
|
|
+ if (dup) {
|
|
|
+ dup_table->refs[free] = 0;
|
|
|
+ dup_table->is_dup[free] = true;
|
|
|
+ dup_table->entries[free] = cpu_to_be32(vlan | MLX4_VLAN_VALID);
|
|
|
+
|
|
|
+ err = mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries);
|
|
|
+ if (unlikely(err)) {
|
|
|
+ mlx4_warn(dev, "Failed adding duplicate vlan: %u\n", vlan);
|
|
|
+ dup_table->is_dup[free] = false;
|
|
|
+ dup_table->entries[free] = 0;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ ++dup_table->total;
|
|
|
+ }
|
|
|
|
|
|
*index = free;
|
|
|
- ++table->total;
|
|
|
out:
|
|
|
- mutex_unlock(&table->mutex);
|
|
|
+ if (need_mf_bond) {
|
|
|
+ if (port == 2) {
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ mutex_unlock(&dup_table->mutex);
|
|
|
+ } else {
|
|
|
+ mutex_unlock(&dup_table->mutex);
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ }
|
|
|
return err;
|
|
|
}
|
|
|
|
|
@@ -455,8 +757,22 @@ void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
|
|
|
{
|
|
|
struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
|
|
|
int index;
|
|
|
+ bool dup = mlx4_is_mf_bonded(dev);
|
|
|
+ u8 dup_port = (port == 1) ? 2 : 1;
|
|
|
+ struct mlx4_vlan_table *dup_table = &mlx4_priv(dev)->port[dup_port].vlan_table;
|
|
|
+
|
|
|
+ if (dup) {
|
|
|
+ if (port == 1) {
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ mutex_lock(&dup_table->mutex);
|
|
|
+ } else {
|
|
|
+ mutex_lock(&dup_table->mutex);
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ mutex_lock(&table->mutex);
|
|
|
+ }
|
|
|
|
|
|
- mutex_lock(&table->mutex);
|
|
|
if (mlx4_find_cached_vlan(dev, port, vlan, &index)) {
|
|
|
mlx4_warn(dev, "vlan 0x%x is not in the vlan table\n", vlan);
|
|
|
goto out;
|
|
@@ -467,16 +783,38 @@ void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (--table->refs[index]) {
|
|
|
+ if (--table->refs[index] || table->is_dup[index]) {
|
|
|
mlx4_dbg(dev, "Have %d more references for index %d, no need to modify vlan table\n",
|
|
|
table->refs[index], index);
|
|
|
+ if (!table->refs[index])
|
|
|
+ dup_table->is_dup[index] = false;
|
|
|
goto out;
|
|
|
}
|
|
|
table->entries[index] = 0;
|
|
|
- mlx4_set_port_vlan_table(dev, port, table->entries);
|
|
|
+ if (mlx4_set_port_vlan_table(dev, port, table->entries))
|
|
|
+ mlx4_warn(dev, "Fail to set vlan in port %d during unregister\n", port);
|
|
|
--table->total;
|
|
|
+ if (dup) {
|
|
|
+ dup_table->is_dup[index] = false;
|
|
|
+ if (dup_table->refs[index])
|
|
|
+ goto out;
|
|
|
+ dup_table->entries[index] = 0;
|
|
|
+ if (mlx4_set_port_vlan_table(dev, dup_port, dup_table->entries))
|
|
|
+ mlx4_warn(dev, "Fail to set vlan in duplicate port %d during unregister\n", dup_port);
|
|
|
+ --dup_table->total;
|
|
|
+ }
|
|
|
out:
|
|
|
- mutex_unlock(&table->mutex);
|
|
|
+ if (dup) {
|
|
|
+ if (port == 2) {
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ mutex_unlock(&dup_table->mutex);
|
|
|
+ } else {
|
|
|
+ mutex_unlock(&dup_table->mutex);
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ mutex_unlock(&table->mutex);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
|
|
@@ -495,6 +833,220 @@ void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, u16 vlan)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(mlx4_unregister_vlan);
|
|
|
|
|
|
+int mlx4_bond_mac_table(struct mlx4_dev *dev)
|
|
|
+{
|
|
|
+ struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table;
|
|
|
+ struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table;
|
|
|
+ int ret = 0;
|
|
|
+ int i;
|
|
|
+ bool update1 = false;
|
|
|
+ bool update2 = false;
|
|
|
+
|
|
|
+ mutex_lock(&t1->mutex);
|
|
|
+ mutex_lock(&t2->mutex);
|
|
|
+ for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
|
|
|
+ if ((t1->entries[i] != t2->entries[i]) &&
|
|
|
+ t1->entries[i] && t2->entries[i]) {
|
|
|
+ mlx4_warn(dev, "can't duplicate entry %d in mac table\n", i);
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto unlock;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
|
|
|
+ if (t1->entries[i] && !t2->entries[i]) {
|
|
|
+ t2->entries[i] = t1->entries[i];
|
|
|
+ t2->is_dup[i] = true;
|
|
|
+ update2 = true;
|
|
|
+ } else if (!t1->entries[i] && t2->entries[i]) {
|
|
|
+ t1->entries[i] = t2->entries[i];
|
|
|
+ t1->is_dup[i] = true;
|
|
|
+ update1 = true;
|
|
|
+ } else if (t1->entries[i] && t2->entries[i]) {
|
|
|
+ t1->is_dup[i] = true;
|
|
|
+ t2->is_dup[i] = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (update1) {
|
|
|
+ ret = mlx4_set_port_mac_table(dev, 1, t1->entries);
|
|
|
+ if (ret)
|
|
|
+ mlx4_warn(dev, "failed to set MAC table for port 1 (%d)\n", ret);
|
|
|
+ }
|
|
|
+ if (!ret && update2) {
|
|
|
+ ret = mlx4_set_port_mac_table(dev, 2, t2->entries);
|
|
|
+ if (ret)
|
|
|
+ mlx4_warn(dev, "failed to set MAC table for port 2 (%d)\n", ret);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ mlx4_warn(dev, "failed to create mirror MAC tables\n");
|
|
|
+unlock:
|
|
|
+ mutex_unlock(&t2->mutex);
|
|
|
+ mutex_unlock(&t1->mutex);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+int mlx4_unbond_mac_table(struct mlx4_dev *dev)
|
|
|
+{
|
|
|
+ struct mlx4_mac_table *t1 = &mlx4_priv(dev)->port[1].mac_table;
|
|
|
+ struct mlx4_mac_table *t2 = &mlx4_priv(dev)->port[2].mac_table;
|
|
|
+ int ret = 0;
|
|
|
+ int ret1;
|
|
|
+ int i;
|
|
|
+ bool update1 = false;
|
|
|
+ bool update2 = false;
|
|
|
+
|
|
|
+ mutex_lock(&t1->mutex);
|
|
|
+ mutex_lock(&t2->mutex);
|
|
|
+ for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
|
|
|
+ if (t1->entries[i] != t2->entries[i]) {
|
|
|
+ mlx4_warn(dev, "mac table is in an unexpected state when trying to unbond\n");
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto unlock;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
|
|
|
+ if (!t1->entries[i])
|
|
|
+ continue;
|
|
|
+ t1->is_dup[i] = false;
|
|
|
+ if (!t1->refs[i]) {
|
|
|
+ t1->entries[i] = 0;
|
|
|
+ update1 = true;
|
|
|
+ }
|
|
|
+ t2->is_dup[i] = false;
|
|
|
+ if (!t2->refs[i]) {
|
|
|
+ t2->entries[i] = 0;
|
|
|
+ update2 = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (update1) {
|
|
|
+ ret = mlx4_set_port_mac_table(dev, 1, t1->entries);
|
|
|
+ if (ret)
|
|
|
+ mlx4_warn(dev, "failed to unmirror MAC tables for port 1(%d)\n", ret);
|
|
|
+ }
|
|
|
+ if (update2) {
|
|
|
+ ret1 = mlx4_set_port_mac_table(dev, 2, t2->entries);
|
|
|
+ if (ret1) {
|
|
|
+ mlx4_warn(dev, "failed to unmirror MAC tables for port 2(%d)\n", ret1);
|
|
|
+ ret = ret1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+unlock:
|
|
|
+ mutex_unlock(&t2->mutex);
|
|
|
+ mutex_unlock(&t1->mutex);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+int mlx4_bond_vlan_table(struct mlx4_dev *dev)
|
|
|
+{
|
|
|
+ struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table;
|
|
|
+ struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table;
|
|
|
+ int ret = 0;
|
|
|
+ int i;
|
|
|
+ bool update1 = false;
|
|
|
+ bool update2 = false;
|
|
|
+
|
|
|
+ mutex_lock(&t1->mutex);
|
|
|
+ mutex_lock(&t2->mutex);
|
|
|
+ for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
|
|
|
+ if ((t1->entries[i] != t2->entries[i]) &&
|
|
|
+ t1->entries[i] && t2->entries[i]) {
|
|
|
+ mlx4_warn(dev, "can't duplicate entry %d in vlan table\n", i);
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto unlock;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
|
|
|
+ if (t1->entries[i] && !t2->entries[i]) {
|
|
|
+ t2->entries[i] = t1->entries[i];
|
|
|
+ t2->is_dup[i] = true;
|
|
|
+ update2 = true;
|
|
|
+ } else if (!t1->entries[i] && t2->entries[i]) {
|
|
|
+ t1->entries[i] = t2->entries[i];
|
|
|
+ t1->is_dup[i] = true;
|
|
|
+ update1 = true;
|
|
|
+ } else if (t1->entries[i] && t2->entries[i]) {
|
|
|
+ t1->is_dup[i] = true;
|
|
|
+ t2->is_dup[i] = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (update1) {
|
|
|
+ ret = mlx4_set_port_vlan_table(dev, 1, t1->entries);
|
|
|
+ if (ret)
|
|
|
+ mlx4_warn(dev, "failed to set VLAN table for port 1 (%d)\n", ret);
|
|
|
+ }
|
|
|
+ if (!ret && update2) {
|
|
|
+ ret = mlx4_set_port_vlan_table(dev, 2, t2->entries);
|
|
|
+ if (ret)
|
|
|
+ mlx4_warn(dev, "failed to set VLAN table for port 2 (%d)\n", ret);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ mlx4_warn(dev, "failed to create mirror VLAN tables\n");
|
|
|
+unlock:
|
|
|
+ mutex_unlock(&t2->mutex);
|
|
|
+ mutex_unlock(&t1->mutex);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+int mlx4_unbond_vlan_table(struct mlx4_dev *dev)
|
|
|
+{
|
|
|
+ struct mlx4_vlan_table *t1 = &mlx4_priv(dev)->port[1].vlan_table;
|
|
|
+ struct mlx4_vlan_table *t2 = &mlx4_priv(dev)->port[2].vlan_table;
|
|
|
+ int ret = 0;
|
|
|
+ int ret1;
|
|
|
+ int i;
|
|
|
+ bool update1 = false;
|
|
|
+ bool update2 = false;
|
|
|
+
|
|
|
+ mutex_lock(&t1->mutex);
|
|
|
+ mutex_lock(&t2->mutex);
|
|
|
+ for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
|
|
|
+ if (t1->entries[i] != t2->entries[i]) {
|
|
|
+ mlx4_warn(dev, "vlan table is in an unexpected state when trying to unbond\n");
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto unlock;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < MLX4_MAX_VLAN_NUM; i++) {
|
|
|
+ if (!t1->entries[i])
|
|
|
+ continue;
|
|
|
+ t1->is_dup[i] = false;
|
|
|
+ if (!t1->refs[i]) {
|
|
|
+ t1->entries[i] = 0;
|
|
|
+ update1 = true;
|
|
|
+ }
|
|
|
+ t2->is_dup[i] = false;
|
|
|
+ if (!t2->refs[i]) {
|
|
|
+ t2->entries[i] = 0;
|
|
|
+ update2 = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (update1) {
|
|
|
+ ret = mlx4_set_port_vlan_table(dev, 1, t1->entries);
|
|
|
+ if (ret)
|
|
|
+ mlx4_warn(dev, "failed to unmirror VLAN tables for port 1(%d)\n", ret);
|
|
|
+ }
|
|
|
+ if (update2) {
|
|
|
+ ret1 = mlx4_set_port_vlan_table(dev, 2, t2->entries);
|
|
|
+ if (ret1) {
|
|
|
+ mlx4_warn(dev, "failed to unmirror VLAN tables for port 2(%d)\n", ret1);
|
|
|
+ ret = ret1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+unlock:
|
|
|
+ mutex_unlock(&t2->mutex);
|
|
|
+ mutex_unlock(&t1->mutex);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
|
|
|
{
|
|
|
struct mlx4_cmd_mailbox *inmailbox, *outmailbox;
|