root/drivers/net/ethernet/mellanox/mlx5/core/sriov.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sriov_restore_guids
  2. mlx5_device_enable_sriov
  3. mlx5_device_disable_sriov
  4. mlx5_sriov_enable
  5. mlx5_sriov_disable
  6. mlx5_core_sriov_configure
  7. mlx5_sriov_attach
  8. mlx5_sriov_detach
  9. mlx5_get_max_vfs
  10. mlx5_sriov_init
  11. mlx5_sriov_cleanup

   1 /*
   2  * Copyright (c) 2014, Mellanox Technologies inc.  All rights reserved.
   3  *
   4  * This software is available to you under a choice of one of two
   5  * licenses.  You may choose to be licensed under the terms of the GNU
   6  * General Public License (GPL) Version 2, available from the file
   7  * COPYING in the main directory of this source tree, or the
   8  * OpenIB.org BSD license below:
   9  *
  10  *     Redistribution and use in source and binary forms, with or
  11  *     without modification, are permitted provided that the following
  12  *     conditions are met:
  13  *
  14  *      - Redistributions of source code must retain the above
  15  *        copyright notice, this list of conditions and the following
  16  *        disclaimer.
  17  *
  18  *      - Redistributions in binary form must reproduce the above
  19  *        copyright notice, this list of conditions and the following
  20  *        disclaimer in the documentation and/or other materials
  21  *        provided with the distribution.
  22  *
  23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30  * SOFTWARE.
  31  */
  32 
  33 #include <linux/pci.h>
  34 #include <linux/mlx5/driver.h>
  35 #include <linux/mlx5/vport.h>
  36 #include "mlx5_core.h"
  37 #include "eswitch.h"
  38 
  39 static int sriov_restore_guids(struct mlx5_core_dev *dev, int vf)
  40 {
  41         struct mlx5_core_sriov *sriov = &dev->priv.sriov;
  42         struct mlx5_hca_vport_context *in;
  43         int err = 0;
  44 
  45         /* Restore sriov guid and policy settings */
  46         if (sriov->vfs_ctx[vf].node_guid ||
  47             sriov->vfs_ctx[vf].port_guid ||
  48             sriov->vfs_ctx[vf].policy != MLX5_POLICY_INVALID) {
  49                 in = kzalloc(sizeof(*in), GFP_KERNEL);
  50                 if (!in)
  51                         return -ENOMEM;
  52 
  53                 in->node_guid = sriov->vfs_ctx[vf].node_guid;
  54                 in->port_guid = sriov->vfs_ctx[vf].port_guid;
  55                 in->policy = sriov->vfs_ctx[vf].policy;
  56                 in->field_select =
  57                         !!(in->port_guid) * MLX5_HCA_VPORT_SEL_PORT_GUID |
  58                         !!(in->node_guid) * MLX5_HCA_VPORT_SEL_NODE_GUID |
  59                         !!(in->policy) * MLX5_HCA_VPORT_SEL_STATE_POLICY;
  60 
  61                 err = mlx5_core_modify_hca_vport_context(dev, 1, 1, vf + 1, in);
  62                 if (err)
  63                         mlx5_core_warn(dev, "modify vport context failed, unable to restore VF %d settings\n", vf);
  64 
  65                 kfree(in);
  66         }
  67 
  68         return err;
  69 }
  70 
  71 static int mlx5_device_enable_sriov(struct mlx5_core_dev *dev, int num_vfs)
  72 {
  73         struct mlx5_core_sriov *sriov = &dev->priv.sriov;
  74         int err;
  75         int vf;
  76 
  77         if (!MLX5_ESWITCH_MANAGER(dev))
  78                 goto enable_vfs_hca;
  79 
  80         mlx5_eswitch_update_num_of_vfs(dev->priv.eswitch, num_vfs);
  81         err = mlx5_eswitch_enable(dev->priv.eswitch, MLX5_ESWITCH_LEGACY);
  82         if (err) {
  83                 mlx5_core_warn(dev,
  84                                "failed to enable eswitch SRIOV (%d)\n", err);
  85                 return err;
  86         }
  87 
  88 enable_vfs_hca:
  89         for (vf = 0; vf < num_vfs; vf++) {
  90                 err = mlx5_core_enable_hca(dev, vf + 1);
  91                 if (err) {
  92                         mlx5_core_warn(dev, "failed to enable VF %d (%d)\n", vf, err);
  93                         continue;
  94                 }
  95                 sriov->vfs_ctx[vf].enabled = 1;
  96                 if (MLX5_CAP_GEN(dev, port_type) == MLX5_CAP_PORT_TYPE_IB) {
  97                         err = sriov_restore_guids(dev, vf);
  98                         if (err) {
  99                                 mlx5_core_warn(dev,
 100                                                "failed to restore VF %d settings, err %d\n",
 101                                                vf, err);
 102                                 continue;
 103                         }
 104                 }
 105                 mlx5_core_dbg(dev, "successfully enabled VF* %d\n", vf);
 106         }
 107 
 108         return 0;
 109 }
 110 
 111 static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev)
 112 {
 113         struct mlx5_core_sriov *sriov = &dev->priv.sriov;
 114         int num_vfs = pci_num_vf(dev->pdev);
 115         int err;
 116         int vf;
 117 
 118         for (vf = num_vfs - 1; vf >= 0; vf--) {
 119                 if (!sriov->vfs_ctx[vf].enabled)
 120                         continue;
 121                 err = mlx5_core_disable_hca(dev, vf + 1);
 122                 if (err) {
 123                         mlx5_core_warn(dev, "failed to disable VF %d\n", vf);
 124                         continue;
 125                 }
 126                 sriov->vfs_ctx[vf].enabled = 0;
 127         }
 128 
 129         if (MLX5_ESWITCH_MANAGER(dev))
 130                 mlx5_eswitch_disable(dev->priv.eswitch);
 131 
 132         if (mlx5_wait_for_pages(dev, &dev->priv.vfs_pages))
 133                 mlx5_core_warn(dev, "timeout reclaiming VFs pages\n");
 134 }
 135 
 136 static int mlx5_sriov_enable(struct pci_dev *pdev, int num_vfs)
 137 {
 138         struct mlx5_core_dev *dev  = pci_get_drvdata(pdev);
 139         int err;
 140 
 141         err = mlx5_device_enable_sriov(dev, num_vfs);
 142         if (err) {
 143                 mlx5_core_warn(dev, "mlx5_device_enable_sriov failed : %d\n", err);
 144                 return err;
 145         }
 146 
 147         err = pci_enable_sriov(pdev, num_vfs);
 148         if (err) {
 149                 mlx5_core_warn(dev, "pci_enable_sriov failed : %d\n", err);
 150                 mlx5_device_disable_sriov(dev);
 151         }
 152         return err;
 153 }
 154 
 155 static void mlx5_sriov_disable(struct pci_dev *pdev)
 156 {
 157         struct mlx5_core_dev *dev  = pci_get_drvdata(pdev);
 158 
 159         pci_disable_sriov(pdev);
 160         mlx5_device_disable_sriov(dev);
 161 }
 162 
 163 int mlx5_core_sriov_configure(struct pci_dev *pdev, int num_vfs)
 164 {
 165         struct mlx5_core_dev *dev  = pci_get_drvdata(pdev);
 166         struct mlx5_core_sriov *sriov = &dev->priv.sriov;
 167         int err = 0;
 168 
 169         mlx5_core_dbg(dev, "requested num_vfs %d\n", num_vfs);
 170 
 171         if (num_vfs)
 172                 err = mlx5_sriov_enable(pdev, num_vfs);
 173         else
 174                 mlx5_sriov_disable(pdev);
 175 
 176         if (!err)
 177                 sriov->num_vfs = num_vfs;
 178         return err ? err : num_vfs;
 179 }
 180 
 181 int mlx5_sriov_attach(struct mlx5_core_dev *dev)
 182 {
 183         if (!mlx5_core_is_pf(dev) || !pci_num_vf(dev->pdev))
 184                 return 0;
 185 
 186         /* If sriov VFs exist in PCI level, enable them in device level */
 187         return mlx5_device_enable_sriov(dev, pci_num_vf(dev->pdev));
 188 }
 189 
 190 void mlx5_sriov_detach(struct mlx5_core_dev *dev)
 191 {
 192         if (!mlx5_core_is_pf(dev))
 193                 return;
 194 
 195         mlx5_device_disable_sriov(dev);
 196 }
 197 
 198 static u16 mlx5_get_max_vfs(struct mlx5_core_dev *dev)
 199 {
 200         u16 host_total_vfs;
 201         const u32 *out;
 202 
 203         if (mlx5_core_is_ecpf_esw_manager(dev)) {
 204                 out = mlx5_esw_query_functions(dev);
 205 
 206                 /* Old FW doesn't support getting total_vfs from esw func
 207                  * but supports getting it from pci_sriov.
 208                  */
 209                 if (IS_ERR(out))
 210                         goto done;
 211                 host_total_vfs = MLX5_GET(query_esw_functions_out, out,
 212                                           host_params_context.host_total_vfs);
 213                 kvfree(out);
 214                 if (host_total_vfs)
 215                         return host_total_vfs;
 216         }
 217 
 218 done:
 219         return pci_sriov_get_totalvfs(dev->pdev);
 220 }
 221 
 222 int mlx5_sriov_init(struct mlx5_core_dev *dev)
 223 {
 224         struct mlx5_core_sriov *sriov = &dev->priv.sriov;
 225         struct pci_dev *pdev = dev->pdev;
 226         int total_vfs;
 227 
 228         if (!mlx5_core_is_pf(dev))
 229                 return 0;
 230 
 231         total_vfs = pci_sriov_get_totalvfs(pdev);
 232         sriov->max_vfs = mlx5_get_max_vfs(dev);
 233         sriov->num_vfs = pci_num_vf(pdev);
 234         sriov->vfs_ctx = kcalloc(total_vfs, sizeof(*sriov->vfs_ctx), GFP_KERNEL);
 235         if (!sriov->vfs_ctx)
 236                 return -ENOMEM;
 237 
 238         return 0;
 239 }
 240 
 241 void mlx5_sriov_cleanup(struct mlx5_core_dev *dev)
 242 {
 243         struct mlx5_core_sriov *sriov = &dev->priv.sriov;
 244 
 245         if (!mlx5_core_is_pf(dev))
 246                 return;
 247 
 248         kfree(sriov->vfs_ctx);
 249 }

/* [<][>][^][v][top][bottom][index][help] */