0001
0002
0003
0004 #include <linux/mlx5/driver.h>
0005 #include "mlx5_core.h"
0006 #include "lib/pci_vsc.h"
0007 #include "lib/mlx5.h"
0008
0009 #define BAD_ACCESS 0xBADACCE5
0010 #define MLX5_PROTECTED_CR_SCAN_CRSPACE 0x7
0011
0012 static bool mlx5_crdump_enabled(struct mlx5_core_dev *dev)
0013 {
0014 return !!dev->priv.health.crdump_size;
0015 }
0016
0017 static int mlx5_crdump_fill(struct mlx5_core_dev *dev, u32 *cr_data)
0018 {
0019 u32 crdump_size = dev->priv.health.crdump_size;
0020 int i, ret;
0021
0022 for (i = 0; i < (crdump_size / 4); i++)
0023 cr_data[i] = BAD_ACCESS;
0024
0025 ret = mlx5_vsc_gw_read_block_fast(dev, cr_data, crdump_size);
0026 if (ret <= 0) {
0027 if (ret == 0)
0028 return -EIO;
0029 return ret;
0030 }
0031
0032 if (crdump_size != ret) {
0033 mlx5_core_warn(dev, "failed to read full dump, read %d out of %u\n",
0034 ret, crdump_size);
0035 return -EINVAL;
0036 }
0037
0038 return 0;
0039 }
0040
0041 int mlx5_crdump_collect(struct mlx5_core_dev *dev, u32 *cr_data)
0042 {
0043 int ret;
0044
0045 if (!mlx5_crdump_enabled(dev))
0046 return -ENODEV;
0047
0048 ret = mlx5_vsc_gw_lock(dev);
0049 if (ret) {
0050 mlx5_core_warn(dev, "crdump: failed to lock vsc gw err %d\n",
0051 ret);
0052 return ret;
0053 }
0054
0055 ret = mlx5_vsc_sem_set_space(dev, MLX5_SEMAPHORE_SW_RESET,
0056 MLX5_VSC_LOCK);
0057 if (ret) {
0058 mlx5_core_warn(dev, "Failed to lock SW reset semaphore\n");
0059 goto unlock_gw;
0060 }
0061
0062 ret = mlx5_vsc_gw_set_space(dev, MLX5_VSC_SPACE_SCAN_CRSPACE, NULL);
0063 if (ret)
0064 goto unlock_sem;
0065
0066 ret = mlx5_crdump_fill(dev, cr_data);
0067
0068 unlock_sem:
0069 mlx5_vsc_sem_set_space(dev, MLX5_SEMAPHORE_SW_RESET, MLX5_VSC_UNLOCK);
0070 unlock_gw:
0071 mlx5_vsc_gw_unlock(dev);
0072 return ret;
0073 }
0074
0075 int mlx5_crdump_enable(struct mlx5_core_dev *dev)
0076 {
0077 struct mlx5_priv *priv = &dev->priv;
0078 u32 space_size;
0079 int ret;
0080
0081 if (!mlx5_core_is_pf(dev) || !mlx5_vsc_accessible(dev) ||
0082 mlx5_crdump_enabled(dev))
0083 return 0;
0084
0085 ret = mlx5_vsc_gw_lock(dev);
0086 if (ret)
0087 return ret;
0088
0089
0090 ret = mlx5_vsc_gw_set_space(dev, MLX5_VSC_SPACE_SCAN_CRSPACE,
0091 &space_size);
0092 if (ret) {
0093
0094 mlx5_vsc_gw_unlock(dev);
0095 return 0;
0096 }
0097
0098 if (!space_size) {
0099 mlx5_core_warn(dev, "Invalid Crspace size, zero\n");
0100 mlx5_vsc_gw_unlock(dev);
0101 return -EINVAL;
0102 }
0103
0104 ret = mlx5_vsc_gw_unlock(dev);
0105 if (ret)
0106 return ret;
0107
0108 priv->health.crdump_size = space_size;
0109 return 0;
0110 }
0111
0112 void mlx5_crdump_disable(struct mlx5_core_dev *dev)
0113 {
0114 dev->priv.health.crdump_size = 0;
0115 }