111820Sjulian// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 211820Sjulian/* Copyright (c) 2019 Mellanox Technologies */ 311820Sjulian 411820Sjulian#include <linux/mlx5/driver.h> 511820Sjulian#include "mlx5_core.h" 611820Sjulian#include "lib/pci_vsc.h" 711820Sjulian#include "lib/mlx5.h" 811820Sjulian 911820Sjulian#define BAD_ACCESS 0xBADACCE5 1011820Sjulian#define MLX5_PROTECTED_CR_SCAN_CRSPACE 0x7 1111820Sjulian 1211820Sjulianstatic bool mlx5_crdump_enabled(struct mlx5_core_dev *dev) 1311820Sjulian{ 1411820Sjulian return !!dev->priv.health.crdump_size; 1511820Sjulian} 1611820Sjulian 1711820Sjulianstatic int mlx5_crdump_fill(struct mlx5_core_dev *dev, u32 *cr_data) 1811820Sjulian{ 1911820Sjulian u32 crdump_size = dev->priv.health.crdump_size; 2011820Sjulian int i, ret; 2111820Sjulian 2211820Sjulian for (i = 0; i < (crdump_size / 4); i++) 2311820Sjulian cr_data[i] = BAD_ACCESS; 2411820Sjulian 2511820Sjulian ret = mlx5_vsc_gw_read_block_fast(dev, cr_data, crdump_size); 2611820Sjulian if (ret <= 0) { 2711820Sjulian if (ret == 0) 2811820Sjulian return -EIO; 2911820Sjulian return ret; 3011820Sjulian } 3111820Sjulian 3211820Sjulian if (crdump_size != ret) { 3311820Sjulian mlx5_core_warn(dev, "failed to read full dump, read %d out of %u\n", 3411820Sjulian ret, crdump_size); 3511820Sjulian return -EINVAL; 3611820Sjulian } 3750479Speter 3811820Sjulian return 0; 3911820Sjulian} 4011820Sjulian 41122760Strhodesint mlx5_crdump_collect(struct mlx5_core_dev *dev, u32 *cr_data) 4211820Sjulian{ 4311820Sjulian int ret; 4411820Sjulian 4511820Sjulian if (!mlx5_crdump_enabled(dev)) 4611820Sjulian return -ENODEV; 4711820Sjulian 4811820Sjulian ret = mlx5_vsc_gw_lock(dev); 4911820Sjulian if (ret) { 5011820Sjulian mlx5_core_warn(dev, "crdump: failed to lock vsc gw err %d\n", 5111820Sjulian ret); 5211820Sjulian return ret; 5311820Sjulian } 5411820Sjulian /* Verify no other PF is running cr-dump or sw reset */ 5511820Sjulian ret = mlx5_vsc_sem_set_space(dev, MLX5_SEMAPHORE_SW_RESET, 5611820Sjulian MLX5_VSC_LOCK); 5711820Sjulian if (ret) { 5811820Sjulian if (ret == -EBUSY) 5911820Sjulian mlx5_core_info(dev, "SW reset semaphore is already in use\n"); 6011820Sjulian else 6127244Sjhay mlx5_core_warn(dev, "Failed to lock SW reset semaphore\n"); 6211820Sjulian goto unlock_gw; 6311820Sjulian } 6411820Sjulian 6511820Sjulian ret = mlx5_vsc_gw_set_space(dev, MLX5_VSC_SPACE_SCAN_CRSPACE, NULL); 6611820Sjulian if (ret) 6711820Sjulian goto unlock_sem; 6811820Sjulian 6911820Sjulian ret = mlx5_crdump_fill(dev, cr_data); 7011820Sjulian 7111820Sjulianunlock_sem: 7211820Sjulian mlx5_vsc_sem_set_space(dev, MLX5_SEMAPHORE_SW_RESET, MLX5_VSC_UNLOCK); 7311820Sjulianunlock_gw: 7411820Sjulian mlx5_vsc_gw_unlock(dev); 7511820Sjulian return ret; 7611820Sjulian} 7711820Sjulian 7811820Sjulianint mlx5_crdump_enable(struct mlx5_core_dev *dev) 7911820Sjulian{ 8011820Sjulian struct mlx5_priv *priv = &dev->priv; 8111820Sjulian u32 space_size; 8211820Sjulian int ret; 8311820Sjulian 8411820Sjulian if (!mlx5_core_is_pf(dev) || !mlx5_vsc_accessible(dev) || 8511820Sjulian mlx5_crdump_enabled(dev)) 8611820Sjulian return 0; 8711820Sjulian 8811820Sjulian ret = mlx5_vsc_gw_lock(dev); 8911820Sjulian if (ret) 9011820Sjulian return ret; 9111820Sjulian 9211820Sjulian /* Check if space is supported and get space size */ 9311820Sjulian ret = mlx5_vsc_gw_set_space(dev, MLX5_VSC_SPACE_SCAN_CRSPACE, 9411820Sjulian &space_size); 9511820Sjulian if (ret) { 9611820Sjulian /* Unlock and mask error since space is not supported */ 9711820Sjulian mlx5_vsc_gw_unlock(dev); 9811820Sjulian return 0; 9911820Sjulian } 10011820Sjulian 10111820Sjulian if (!space_size) { 10211820Sjulian mlx5_core_warn(dev, "Invalid Crspace size, zero\n"); 10311820Sjulian mlx5_vsc_gw_unlock(dev); 10411820Sjulian return -EINVAL; 10511820Sjulian } 10611820Sjulian 10711820Sjulian ret = mlx5_vsc_gw_unlock(dev); 10811820Sjulian if (ret) 10911820Sjulian return ret; 11011820Sjulian 11111820Sjulian priv->health.crdump_size = space_size; 11211820Sjulian return 0; 11311820Sjulian} 11411820Sjulian 11511820Sjulianvoid mlx5_crdump_disable(struct mlx5_core_dev *dev) 11611820Sjulian{ 11711820Sjulian dev->priv.health.crdump_size = 0; 11811820Sjulian} 11911820Sjulian