net/mlx4_core: Fix register/unreg vlan flow
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx4 / port.c
index 10c57c8..d3d3106 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <linux/errno.h>
 #include <linux/if_ether.h>
+#include <linux/if_vlan.h>
 #include <linux/export.h>
 
 #include <linux/mlx4/cmd.h>
@@ -140,8 +141,9 @@ int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
                }
 
                if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
-                       /* MAC already registered, Must not have duplicates */
-                       err = -EEXIST;
+                       /* MAC already registered, increment ref count */
+                       err = i;
+                       ++table->refs[i];
                        goto out;
                }
        }
@@ -164,7 +166,7 @@ int __mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac)
                table->entries[free] = 0;
                goto out;
        }
-
+       table->refs[free] = 1;
        err = free;
        ++table->total;
 out:
@@ -205,12 +207,16 @@ void __mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, u64 mac)
        struct mlx4_mac_table *table = &info->mac_table;
        int index;
 
-       index = find_index(dev, table, mac);
-
        mutex_lock(&table->mutex);
+       index = find_index(dev, table, mac);
 
        if (validate_index(dev, table, index))
                goto out;
+       if (--table->refs[index]) {
+               mlx4_dbg(dev, "Have more references for index %d,"
+                        "no need to modify mac table\n", index);
+               goto out;
+       }
 
        table->entries[index] = 0;
        mlx4_set_port_mac_table(dev, port, table->entries);
@@ -278,7 +284,7 @@ static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
        memcpy(mailbox->buf, entries, MLX4_VLAN_TABLE_SIZE);
        in_mod = MLX4_SET_PORT_VLAN_TABLE << 8 | port;
        err = mlx4_cmd(dev, mailbox->dma, in_mod, 1, MLX4_CMD_SET_PORT,
-                      MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
+                      MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
 
        mlx4_free_cmd_mailbox(dev, mailbox);
 
@@ -304,7 +310,7 @@ int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx)
 }
 EXPORT_SYMBOL_GPL(mlx4_find_cached_vlan);
 
-static int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
+int __mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan,
                                int *index)
 {
        struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
@@ -364,6 +370,9 @@ int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
        u64 out_param = 0;
        int err;
 
+       if (vlan > 4095)
+               return -EINVAL;
+
        if (mlx4_is_mfunc(dev)) {
                set_param_l(&out_param, port);
                err = mlx4_cmd_imm(dev, vlan, &out_param, RES_VLAN,
@@ -378,7 +387,7 @@ int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index)
 }
 EXPORT_SYMBOL_GPL(mlx4_register_vlan);
 
-static void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
+void __mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
 {
        struct mlx4_vlan_table *table = &mlx4_priv(dev)->port[port].vlan_table;
 
@@ -406,18 +415,14 @@ out:
 
 void mlx4_unregister_vlan(struct mlx4_dev *dev, u8 port, int index)
 {
-       u64 in_param = 0;
-       int err;
+       u64 out_param = 0;
 
        if (mlx4_is_mfunc(dev)) {
-               set_param_l(&in_param, port);
-               err = mlx4_cmd(dev, in_param, RES_VLAN, RES_OP_RESERVE_AND_MAP,
-                              MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A,
-                              MLX4_CMD_WRAPPED);
-               if (!err)
-                       mlx4_warn(dev, "Failed freeing vlan at index:%d\n",
-                                       index);
-
+               set_param_l(&out_param, port);
+               (void) mlx4_cmd_imm(dev, index, &out_param, RES_VLAN,
+                                   RES_OP_RESERVE_AND_MAP,
+                                   MLX4_CMD_FREE_RES, MLX4_CMD_TIME_CLASS_A,
+                                   MLX4_CMD_WRAPPED);
                return;
        }
        __mlx4_unregister_vlan(dev, port, index);
@@ -517,7 +522,8 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
                        /* Mtu is configured as the max MTU among all the
                         * the functions on the port. */
                        mtu = be16_to_cpu(gen_context->mtu);
-                       mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port]);
+                       mtu = min_t(int, mtu, dev->caps.eth_mtu_cap[port] +
+                                   ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
                        prev_mtu = slave_st->mtu[port];
                        slave_st->mtu[port] = mtu;
                        if (mtu > master->max_mtu[port])