linux/drivers/net/ethernet/mellanox/mlx5/core/diag/rsc_dump.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
   2/* Copyright (c) 2019 Mellanox Technologies. */
   3
   4#include "rsc_dump.h"
   5#include "lib/mlx5.h"
   6
   7#define MLX5_SGMT_TYPE(SGMT) MLX5_SGMT_TYPE_##SGMT
   8#define MLX5_SGMT_STR_ASSING(SGMT)[MLX5_SGMT_TYPE(SGMT)] = #SGMT
   9static const char *const mlx5_rsc_sgmt_name[] = {
  10        MLX5_SGMT_STR_ASSING(HW_CQPC),
  11        MLX5_SGMT_STR_ASSING(HW_SQPC),
  12        MLX5_SGMT_STR_ASSING(HW_RQPC),
  13        MLX5_SGMT_STR_ASSING(FULL_SRQC),
  14        MLX5_SGMT_STR_ASSING(FULL_CQC),
  15        MLX5_SGMT_STR_ASSING(FULL_EQC),
  16        MLX5_SGMT_STR_ASSING(FULL_QPC),
  17        MLX5_SGMT_STR_ASSING(SND_BUFF),
  18        MLX5_SGMT_STR_ASSING(RCV_BUFF),
  19        MLX5_SGMT_STR_ASSING(SRQ_BUFF),
  20        MLX5_SGMT_STR_ASSING(CQ_BUFF),
  21        MLX5_SGMT_STR_ASSING(EQ_BUFF),
  22        MLX5_SGMT_STR_ASSING(SX_SLICE),
  23        MLX5_SGMT_STR_ASSING(SX_SLICE_ALL),
  24        MLX5_SGMT_STR_ASSING(RDB),
  25        MLX5_SGMT_STR_ASSING(RX_SLICE_ALL),
  26        MLX5_SGMT_STR_ASSING(PRM_QUERY_QP),
  27        MLX5_SGMT_STR_ASSING(PRM_QUERY_CQ),
  28        MLX5_SGMT_STR_ASSING(PRM_QUERY_MKEY),
  29};
  30
  31struct mlx5_rsc_dump {
  32        u32 pdn;
  33        struct mlx5_core_mkey mkey;
  34        u16 fw_segment_type[MLX5_SGMT_TYPE_NUM];
  35};
  36
  37struct mlx5_rsc_dump_cmd {
  38        u64 mem_size;
  39        u8 cmd[MLX5_ST_SZ_BYTES(resource_dump)];
  40};
  41
  42static int mlx5_rsc_dump_sgmt_get_by_name(char *name)
  43{
  44        int i;
  45
  46        for (i = 0; i < ARRAY_SIZE(mlx5_rsc_sgmt_name); i++)
  47                if (!strcmp(name, mlx5_rsc_sgmt_name[i]))
  48                        return i;
  49
  50        return -EINVAL;
  51}
  52
  53static void mlx5_rsc_dump_read_menu_sgmt(struct mlx5_rsc_dump *rsc_dump, struct page *page)
  54{
  55        void *data = page_address(page);
  56        enum mlx5_sgmt_type sgmt_idx;
  57        int num_of_items;
  58        char *sgmt_name;
  59        void *member;
  60        void *menu;
  61        int i;
  62
  63        menu = MLX5_ADDR_OF(menu_resource_dump_response, data, menu);
  64        num_of_items = MLX5_GET(resource_dump_menu_segment, menu, num_of_records);
  65
  66        for (i = 0; i < num_of_items; i++) {
  67                member = MLX5_ADDR_OF(resource_dump_menu_segment, menu, record[i]);
  68                sgmt_name =  MLX5_ADDR_OF(resource_dump_menu_record, member, segment_name);
  69                sgmt_idx = mlx5_rsc_dump_sgmt_get_by_name(sgmt_name);
  70                if (sgmt_idx == -EINVAL)
  71                        continue;
  72                rsc_dump->fw_segment_type[sgmt_idx] = MLX5_GET(resource_dump_menu_record,
  73                                                               member, segment_type);
  74        }
  75}
  76
  77static int mlx5_rsc_dump_trigger(struct mlx5_core_dev *dev, struct mlx5_rsc_dump_cmd *cmd,
  78                                 struct page *page)
  79{
  80        struct mlx5_rsc_dump *rsc_dump = dev->rsc_dump;
  81        struct device *ddev = mlx5_core_dma_dev(dev);
  82        u32 out_seq_num;
  83        u32 in_seq_num;
  84        dma_addr_t dma;
  85        int err;
  86
  87        dma = dma_map_page(ddev, page, 0, cmd->mem_size, DMA_FROM_DEVICE);
  88        if (unlikely(dma_mapping_error(ddev, dma)))
  89                return -ENOMEM;
  90
  91        in_seq_num = MLX5_GET(resource_dump, cmd->cmd, seq_num);
  92        MLX5_SET(resource_dump, cmd->cmd, mkey, rsc_dump->mkey.key);
  93        MLX5_SET64(resource_dump, cmd->cmd, address, dma);
  94
  95        err = mlx5_core_access_reg(dev, cmd->cmd, sizeof(cmd->cmd), cmd->cmd,
  96                                   sizeof(cmd->cmd), MLX5_REG_RESOURCE_DUMP, 0, 1);
  97        if (err) {
  98                mlx5_core_err(dev, "Resource dump: Failed to access err %d\n", err);
  99                goto out;
 100        }
 101        out_seq_num = MLX5_GET(resource_dump, cmd->cmd, seq_num);
 102        if (out_seq_num && (in_seq_num + 1 != out_seq_num))
 103                err = -EIO;
 104out:
 105        dma_unmap_page(ddev, dma, cmd->mem_size, DMA_FROM_DEVICE);
 106        return err;
 107}
 108
 109struct mlx5_rsc_dump_cmd *mlx5_rsc_dump_cmd_create(struct mlx5_core_dev *dev,
 110                                                   struct mlx5_rsc_key *key)
 111{
 112        struct mlx5_rsc_dump_cmd *cmd;
 113        int sgmt_type;
 114
 115        if (IS_ERR_OR_NULL(dev->rsc_dump))
 116                return ERR_PTR(-EOPNOTSUPP);
 117
 118        sgmt_type = dev->rsc_dump->fw_segment_type[key->rsc];
 119        if (!sgmt_type && key->rsc != MLX5_SGMT_TYPE_MENU)
 120                return ERR_PTR(-EOPNOTSUPP);
 121
 122        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
 123        if (!cmd) {
 124                mlx5_core_err(dev, "Resource dump: Failed to allocate command\n");
 125                return ERR_PTR(-ENOMEM);
 126        }
 127        MLX5_SET(resource_dump, cmd->cmd, segment_type, sgmt_type);
 128        MLX5_SET(resource_dump, cmd->cmd, index1, key->index1);
 129        MLX5_SET(resource_dump, cmd->cmd, index2, key->index2);
 130        MLX5_SET(resource_dump, cmd->cmd, num_of_obj1, key->num_of_obj1);
 131        MLX5_SET(resource_dump, cmd->cmd, num_of_obj2, key->num_of_obj2);
 132        MLX5_SET(resource_dump, cmd->cmd, size, key->size);
 133        cmd->mem_size = key->size;
 134        return cmd;
 135}
 136EXPORT_SYMBOL(mlx5_rsc_dump_cmd_create);
 137
 138void mlx5_rsc_dump_cmd_destroy(struct mlx5_rsc_dump_cmd *cmd)
 139{
 140        kfree(cmd);
 141}
 142EXPORT_SYMBOL(mlx5_rsc_dump_cmd_destroy);
 143
 144int mlx5_rsc_dump_next(struct mlx5_core_dev *dev, struct mlx5_rsc_dump_cmd *cmd,
 145                       struct page *page, int *size)
 146{
 147        bool more_dump;
 148        int err;
 149
 150        if (IS_ERR_OR_NULL(dev->rsc_dump))
 151                return -EOPNOTSUPP;
 152
 153        err = mlx5_rsc_dump_trigger(dev, cmd, page);
 154        if (err) {
 155                mlx5_core_err(dev, "Resource dump: Failed to trigger dump, %d\n", err);
 156                return err;
 157        }
 158        *size = MLX5_GET(resource_dump, cmd->cmd, size);
 159        more_dump = MLX5_GET(resource_dump, cmd->cmd, more_dump);
 160
 161        return more_dump;
 162}
 163EXPORT_SYMBOL(mlx5_rsc_dump_next);
 164
 165#define MLX5_RSC_DUMP_MENU_SEGMENT 0xffff
 166static int mlx5_rsc_dump_menu(struct mlx5_core_dev *dev)
 167{
 168        struct mlx5_rsc_dump_cmd *cmd = NULL;
 169        struct mlx5_rsc_key key = {};
 170        struct page *page;
 171        int size;
 172        int err;
 173
 174        page = alloc_page(GFP_KERNEL);
 175        if (!page)
 176                return -ENOMEM;
 177
 178        key.rsc = MLX5_SGMT_TYPE_MENU;
 179        key.size = PAGE_SIZE;
 180        cmd  = mlx5_rsc_dump_cmd_create(dev, &key);
 181        if (IS_ERR(cmd)) {
 182                err = PTR_ERR(cmd);
 183                goto free_page;
 184        }
 185        MLX5_SET(resource_dump, cmd->cmd, segment_type, MLX5_RSC_DUMP_MENU_SEGMENT);
 186
 187        do {
 188                err = mlx5_rsc_dump_next(dev, cmd, page, &size);
 189                if (err < 0)
 190                        goto destroy_cmd;
 191
 192                mlx5_rsc_dump_read_menu_sgmt(dev->rsc_dump, page);
 193
 194        } while (err > 0);
 195
 196destroy_cmd:
 197        mlx5_rsc_dump_cmd_destroy(cmd);
 198free_page:
 199        __free_page(page);
 200
 201        return err;
 202}
 203
 204static int mlx5_rsc_dump_create_mkey(struct mlx5_core_dev *mdev, u32 pdn,
 205                                     struct mlx5_core_mkey *mkey)
 206{
 207        int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
 208        void *mkc;
 209        u32 *in;
 210        int err;
 211
 212        in = kvzalloc(inlen, GFP_KERNEL);
 213        if (!in)
 214                return -ENOMEM;
 215
 216        mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
 217        MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);
 218        MLX5_SET(mkc, mkc, lw, 1);
 219        MLX5_SET(mkc, mkc, lr, 1);
 220
 221        MLX5_SET(mkc, mkc, pd, pdn);
 222        MLX5_SET(mkc, mkc, length64, 1);
 223        MLX5_SET(mkc, mkc, qpn, 0xffffff);
 224
 225        err = mlx5_core_create_mkey(mdev, mkey, in, inlen);
 226
 227        kvfree(in);
 228        return err;
 229}
 230
 231struct mlx5_rsc_dump *mlx5_rsc_dump_create(struct mlx5_core_dev *dev)
 232{
 233        struct mlx5_rsc_dump *rsc_dump;
 234
 235        if (!MLX5_CAP_DEBUG(dev, resource_dump)) {
 236                mlx5_core_dbg(dev, "Resource dump: capability not present\n");
 237                return NULL;
 238        }
 239        rsc_dump = kzalloc(sizeof(*rsc_dump), GFP_KERNEL);
 240        if (!rsc_dump)
 241                return ERR_PTR(-ENOMEM);
 242
 243        return rsc_dump;
 244}
 245
 246void mlx5_rsc_dump_destroy(struct mlx5_core_dev *dev)
 247{
 248        if (IS_ERR_OR_NULL(dev->rsc_dump))
 249                return;
 250        kfree(dev->rsc_dump);
 251}
 252
 253int mlx5_rsc_dump_init(struct mlx5_core_dev *dev)
 254{
 255        struct mlx5_rsc_dump *rsc_dump = dev->rsc_dump;
 256        int err;
 257
 258        if (IS_ERR_OR_NULL(dev->rsc_dump))
 259                return 0;
 260
 261        err = mlx5_core_alloc_pd(dev, &rsc_dump->pdn);
 262        if (err) {
 263                mlx5_core_warn(dev, "Resource dump: Failed to allocate PD %d\n", err);
 264                return err;
 265        }
 266        err = mlx5_rsc_dump_create_mkey(dev, rsc_dump->pdn, &rsc_dump->mkey);
 267        if (err) {
 268                mlx5_core_err(dev, "Resource dump: Failed to create mkey, %d\n", err);
 269                goto free_pd;
 270        }
 271        err = mlx5_rsc_dump_menu(dev);
 272        if (err) {
 273                mlx5_core_err(dev, "Resource dump: Failed to read menu, %d\n", err);
 274                goto destroy_mkey;
 275        }
 276        return err;
 277
 278destroy_mkey:
 279        mlx5_core_destroy_mkey(dev, &rsc_dump->mkey);
 280free_pd:
 281        mlx5_core_dealloc_pd(dev, rsc_dump->pdn);
 282        return err;
 283}
 284
 285void mlx5_rsc_dump_cleanup(struct mlx5_core_dev *dev)
 286{
 287        if (IS_ERR_OR_NULL(dev->rsc_dump))
 288                return;
 289
 290        mlx5_core_destroy_mkey(dev, &dev->rsc_dump->mkey);
 291        mlx5_core_dealloc_pd(dev, dev->rsc_dump->pdn);
 292}
 293