net/mlx4_core: Reset RoCE VF gids when guest driver goes down
authorJack Morgenstein <jackm@dev.mellanox.co.il>
Tue, 27 May 2014 06:26:38 +0000 (09:26 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 30 May 2014 23:57:52 +0000 (16:57 -0700)
Reset the GIDs assigned to a VF in the port RoCE GID table when
that guest goes down (either crashes or goes down cleanly).

As part of this fix, we refactor the RoCE gid table driver copy,
moving it to the mlx4_port_info structure (together with the MAC
and VLAN tables).

As with the MAC and VLAN tables, we now use a mutex per port
for the GID table so that modifying the driver copy and
modifying the firmware copy of a port GID table becomes an
atomic operation (thus avoiding driver-copy/FW-copy mismatches).

Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mlx4.h
drivers/net/ethernet/mellanox/mlx4/port.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c

index 7cf9dad..c187d74 100644 (file)
@@ -2044,6 +2044,7 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
        if (!mlx4_is_slave(dev)) {
                mlx4_init_mac_table(dev, &info->mac_table);
                mlx4_init_vlan_table(dev, &info->vlan_table);
+               mlx4_init_roce_gid_table(dev, &info->gid_table);
                info->base_qpn = mlx4_get_base_qpn(dev, port);
        }
 
index 212cea4..8e9eb02 100644 (file)
@@ -695,6 +695,17 @@ struct mlx4_mac_table {
        int                     max;
 };
 
+#define MLX4_ROCE_GID_ENTRY_SIZE       16
+
+struct mlx4_roce_gid_entry {
+       u8 raw[MLX4_ROCE_GID_ENTRY_SIZE];
+};
+
+struct mlx4_roce_gid_table {
+       struct mlx4_roce_gid_entry      roce_gids[MLX4_ROCE_MAX_GIDS];
+       struct mutex                    mutex;
+};
+
 #define MLX4_MAX_VLAN_NUM      128
 #define MLX4_VLAN_TABLE_SIZE   (MLX4_MAX_VLAN_NUM << 2)
 
@@ -758,6 +769,7 @@ struct mlx4_port_info {
        struct device_attribute port_mtu_attr;
        struct mlx4_mac_table   mac_table;
        struct mlx4_vlan_table  vlan_table;
+       struct mlx4_roce_gid_table gid_table;
        int                     base_qpn;
 };
 
@@ -788,10 +800,6 @@ enum {
        MLX4_USE_RR     = 1,
 };
 
-struct mlx4_roce_gid_entry {
-       u8 raw[16];
-};
-
 struct mlx4_priv {
        struct mlx4_dev         dev;
 
@@ -839,7 +847,6 @@ struct mlx4_priv {
        int                     fs_hash_mode;
        u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS];
        __be64                  slave_node_guids[MLX4_MFUNC_MAX];
-       struct mlx4_roce_gid_entry roce_gids[MLX4_MAX_PORTS][MLX4_ROCE_MAX_GIDS];
 
        atomic_t                opreq_count;
        struct work_struct      opreq_task;
@@ -1140,6 +1147,8 @@ int mlx4_change_port_types(struct mlx4_dev *dev,
 
 void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table);
 void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table);
+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);
 
@@ -1149,6 +1158,7 @@ int mlx4_get_slave_from_resource_id(struct mlx4_dev *dev,
                                    enum mlx4_resource resource_type,
                                    u64 resource_id, int *slave);
 void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave_id);
+void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave);
 int mlx4_init_resource_tracker(struct mlx4_dev *dev);
 
 void mlx4_free_resource_tracker(struct mlx4_dev *dev,
index b5b3549..5ec6f20 100644 (file)
@@ -75,6 +75,16 @@ void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table)
        table->total = 0;
 }
 
+void mlx4_init_roce_gid_table(struct mlx4_dev *dev,
+                             struct mlx4_roce_gid_table *table)
+{
+       int i;
+
+       mutex_init(&table->mutex);
+       for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++)
+               memset(table->roce_gids[i].raw, 0, MLX4_ROCE_GID_ENTRY_SIZE);
+}
+
 static int validate_index(struct mlx4_dev *dev,
                          struct mlx4_mac_table *table, int index)
 {
@@ -584,6 +594,84 @@ int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port)
 }
 EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix);
 
+static int mlx4_reset_roce_port_gids(struct mlx4_dev *dev, int slave,
+                                    int port, struct mlx4_cmd_mailbox *mailbox)
+{
+       struct mlx4_roce_gid_entry *gid_entry_mbox;
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int num_gids, base, offset;
+       int i, err;
+
+       num_gids = mlx4_get_slave_num_gids(dev, slave, port);
+       base = mlx4_get_base_gid_ix(dev, slave, port);
+
+       memset(mailbox->buf, 0, MLX4_MAILBOX_SIZE);
+
+       mutex_lock(&(priv->port[port].gid_table.mutex));
+       /* Zero-out gids belonging to that slave in the port GID table */
+       for (i = 0, offset = base; i < num_gids; offset++, i++)
+               memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
+                      zgid_entry.raw, MLX4_ROCE_GID_ENTRY_SIZE);
+
+       /* Now, copy roce port gids table to mailbox for passing to FW */
+       gid_entry_mbox = (struct mlx4_roce_gid_entry *)mailbox->buf;
+       for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
+               memcpy(gid_entry_mbox->raw,
+                      priv->port[port].gid_table.roce_gids[i].raw,
+                      MLX4_ROCE_GID_ENTRY_SIZE);
+
+       err = mlx4_cmd(dev, mailbox->dma,
+                      ((u32)port) | (MLX4_SET_PORT_GID_TABLE << 8), 1,
+                      MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
+                      MLX4_CMD_NATIVE);
+       mutex_unlock(&(priv->port[port].gid_table.mutex));
+       return err;
+}
+
+
+void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave)
+{
+       struct mlx4_active_ports actv_ports;
+       struct mlx4_cmd_mailbox *mailbox;
+       int num_eth_ports, err;
+       int i;
+
+       if (slave < 0 || slave > dev->num_vfs)
+               return;
+
+       actv_ports = mlx4_get_active_ports(dev, slave);
+
+       for (i = 0, num_eth_ports = 0; i < dev->caps.num_ports; i++) {
+               if (test_bit(i, actv_ports.ports)) {
+                       if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
+                               continue;
+                       num_eth_ports++;
+               }
+       }
+
+       if (!num_eth_ports)
+               return;
+
+       /* have ETH ports.  Alloc mailbox for SET_PORT command */
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return;
+
+       for (i = 0; i < dev->caps.num_ports; i++) {
+               if (test_bit(i, actv_ports.ports)) {
+                       if (dev->caps.port_type[i + 1] != MLX4_PORT_TYPE_ETH)
+                               continue;
+                       err = mlx4_reset_roce_port_gids(dev, slave, i + 1, mailbox);
+                       if (err)
+                               mlx4_warn(dev, "Could not reset ETH port GID table for slave %d, port %d (%d)\n",
+                                         slave, i + 1, err);
+               }
+       }
+
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return;
+}
+
 static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
                                u8 op_mod, struct mlx4_cmd_mailbox *inbox)
 {
@@ -692,10 +780,12 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
                        /* 2. Check that do not have duplicates in OTHER
                         *    entries in the port GID table
                         */
+
+                       mutex_lock(&(priv->port[port].gid_table.mutex));
                        for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
                                if (i >= base && i < base + num_gids)
                                        continue; /* don't compare to slave's current gids */
-                               gid_entry_tbl = &priv->roce_gids[port - 1][i];
+                               gid_entry_tbl = &priv->port[port].gid_table.roce_gids[i];
                                if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry)))
                                        continue;
                                gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
@@ -709,6 +799,7 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
                                                mlx4_warn(dev, "requested gid entry for slave:%d "
                                                          "is a duplicate of gid at index %d\n",
                                                          slave, i);
+                                               mutex_unlock(&(priv->port[port].gid_table.mutex));
                                                return -EINVAL;
                                        }
                                }
@@ -717,16 +808,24 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
                        /* insert slave GIDs with memcpy, starting at slave's base index */
                        gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
                        for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++)
-                               memcpy(priv->roce_gids[port - 1][offset].raw, gid_entry_mbox->raw, 16);
+                               memcpy(priv->port[port].gid_table.roce_gids[offset].raw,
+                                      gid_entry_mbox->raw, MLX4_ROCE_GID_ENTRY_SIZE);
 
                        /* Now, copy roce port gids table to current mailbox for passing to FW */
                        gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
                        for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
-                               memcpy(gid_entry_mbox->raw, priv->roce_gids[port - 1][i].raw, 16);
-
-                       break;
+                               memcpy(gid_entry_mbox->raw,
+                                      priv->port[port].gid_table.roce_gids[i].raw,
+                                      MLX4_ROCE_GID_ENTRY_SIZE);
+
+                       err = mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
+                                      MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
+                                      MLX4_CMD_NATIVE);
+                       mutex_unlock(&(priv->port[port].gid_table.mutex));
+                       return err;
                }
-               return mlx4_cmd(dev, inbox->dma, in_mod, op_mod,
+
+               return mlx4_cmd(dev, inbox->dma, in_mod & 0xffff, op_mod,
                                MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
                                MLX4_CMD_NATIVE);
        }
@@ -1099,7 +1198,8 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
        num_vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
 
        for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
-               if (!memcmp(priv->roce_gids[port - 1][i].raw, gid, 16)) {
+               if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid,
+                           MLX4_ROCE_GID_ENTRY_SIZE)) {
                        found_ix = i;
                        break;
                }
@@ -1187,7 +1287,8 @@ int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id,
        if (!mlx4_is_master(dev))
                return -EINVAL;
 
-       memcpy(gid, priv->roce_gids[port - 1][slave_id].raw, 16);
+       memcpy(gid, priv->port[port].gid_table.roce_gids[slave_id].raw,
+              MLX4_ROCE_GID_ENTRY_SIZE);
        return 0;
 }
 EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
index 8f1254a..f16e539 100644 (file)
@@ -586,6 +586,7 @@ void mlx4_free_resource_tracker(struct mlx4_dev *dev,
                        }
                        /* free master's vlans */
                        i = dev->caps.function;
+                       mlx4_reset_roce_gids(dev, i);
                        mutex_lock(&priv->mfunc.master.res_tracker.slave_list[i].mutex);
                        rem_slave_vlans(dev, i);
                        mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[i].mutex);
@@ -4681,7 +4682,7 @@ static void rem_slave_xrcdns(struct mlx4_dev *dev, int slave)
 void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-
+       mlx4_reset_roce_gids(dev, slave);
        mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
        rem_slave_vlans(dev, slave);
        rem_slave_macs(dev, slave);