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 u32 mkey; 34 u32 number_of_menu_items; 35 u16 fw_segment_type[MLX5_SGMT_TYPE_NUM]; 36}; 37 38struct mlx5_rsc_dump_cmd { 39 u64 mem_size; 40 u8 cmd[MLX5_ST_SZ_BYTES(resource_dump)]; 41}; 42 43static int mlx5_rsc_dump_sgmt_get_by_name(char *name) 44{ 45 int i; 46 47 for (i = 0; i < ARRAY_SIZE(mlx5_rsc_sgmt_name); i++) 48 if (!strcmp(name, mlx5_rsc_sgmt_name[i])) 49 return i; 50 51 return -EINVAL; 52} 53 54#define MLX5_RSC_DUMP_MENU_HEADER_SIZE (MLX5_ST_SZ_BYTES(resource_dump_info_segment) + \ 55 MLX5_ST_SZ_BYTES(resource_dump_command_segment) + \ 56 MLX5_ST_SZ_BYTES(resource_dump_menu_segment)) 57 58static int mlx5_rsc_dump_read_menu_sgmt(struct mlx5_rsc_dump *rsc_dump, struct page *page, 59 int read_size, int start_idx) 60{ 61 void *data = page_address(page); 62 enum mlx5_sgmt_type sgmt_idx; 63 int num_of_items; 64 char *sgmt_name; 65 void *member; 66 int size = 0; 67 void *menu; 68 int i; 69 70 if (!start_idx) { 71 menu = MLX5_ADDR_OF(menu_resource_dump_response, data, menu); 72 rsc_dump->number_of_menu_items = MLX5_GET(resource_dump_menu_segment, menu, 73 num_of_records); 74 size = MLX5_RSC_DUMP_MENU_HEADER_SIZE; 75 data += size; 76 } 77 num_of_items = rsc_dump->number_of_menu_items; 78 79 for (i = 0; start_idx + i < num_of_items; i++) { 80 size += MLX5_ST_SZ_BYTES(resource_dump_menu_record); 81 if (size >= read_size) 82 return start_idx + i; 83 84 member = data + MLX5_ST_SZ_BYTES(resource_dump_menu_record) * i; 85 sgmt_name = MLX5_ADDR_OF(resource_dump_menu_record, member, segment_name); 86 sgmt_idx = mlx5_rsc_dump_sgmt_get_by_name(sgmt_name); 87 if (sgmt_idx == -EINVAL) 88 continue; 89 rsc_dump->fw_segment_type[sgmt_idx] = MLX5_GET(resource_dump_menu_record, 90 member, segment_type); 91 } 92 return 0; 93} 94 95static int mlx5_rsc_dump_trigger(struct mlx5_core_dev *dev, struct mlx5_rsc_dump_cmd *cmd, 96 struct page *page) 97{ 98 struct mlx5_rsc_dump *rsc_dump = dev->rsc_dump; 99 struct device *ddev = mlx5_core_dma_dev(dev); 100 u32 out_seq_num; 101 u32 in_seq_num; 102 dma_addr_t dma; 103 int err; 104 105 dma = dma_map_page(ddev, page, 0, cmd->mem_size, DMA_FROM_DEVICE); 106 if (unlikely(dma_mapping_error(ddev, dma))) 107 return -ENOMEM; 108 109 in_seq_num = MLX5_GET(resource_dump, cmd->cmd, seq_num); 110 MLX5_SET(resource_dump, cmd->cmd, mkey, rsc_dump->mkey); 111 MLX5_SET64(resource_dump, cmd->cmd, address, dma); 112 113 err = mlx5_core_access_reg(dev, cmd->cmd, sizeof(cmd->cmd), cmd->cmd, 114 sizeof(cmd->cmd), MLX5_REG_RESOURCE_DUMP, 0, 1); 115 if (err) { 116 mlx5_core_err(dev, "Resource dump: Failed to access err %d\n", err); 117 goto out; 118 } 119 out_seq_num = MLX5_GET(resource_dump, cmd->cmd, seq_num); 120 if (out_seq_num && (in_seq_num + 1 != out_seq_num)) 121 err = -EIO; 122out: 123 dma_unmap_page(ddev, dma, cmd->mem_size, DMA_FROM_DEVICE); 124 return err; 125} 126 127struct mlx5_rsc_dump_cmd *mlx5_rsc_dump_cmd_create(struct mlx5_core_dev *dev, 128 struct mlx5_rsc_key *key) 129{ 130 struct mlx5_rsc_dump_cmd *cmd; 131 int sgmt_type; 132 133 if (IS_ERR_OR_NULL(dev->rsc_dump)) 134 return ERR_PTR(-EOPNOTSUPP); 135 136 sgmt_type = dev->rsc_dump->fw_segment_type[key->rsc]; 137 if (!sgmt_type && key->rsc != MLX5_SGMT_TYPE_MENU) 138 return ERR_PTR(-EOPNOTSUPP); 139 140 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 141 if (!cmd) { 142 mlx5_core_err(dev, "Resource dump: Failed to allocate command\n"); 143 return ERR_PTR(-ENOMEM); 144 } 145 MLX5_SET(resource_dump, cmd->cmd, segment_type, sgmt_type); 146 MLX5_SET(resource_dump, cmd->cmd, index1, key->index1); 147 MLX5_SET(resource_dump, cmd->cmd, index2, key->index2); 148 MLX5_SET(resource_dump, cmd->cmd, num_of_obj1, key->num_of_obj1); 149 MLX5_SET(resource_dump, cmd->cmd, num_of_obj2, key->num_of_obj2); 150 MLX5_SET(resource_dump, cmd->cmd, size, key->size); 151 cmd->mem_size = key->size; 152 return cmd; 153} 154EXPORT_SYMBOL(mlx5_rsc_dump_cmd_create); 155 156void mlx5_rsc_dump_cmd_destroy(struct mlx5_rsc_dump_cmd *cmd) 157{ 158 kfree(cmd); 159} 160EXPORT_SYMBOL(mlx5_rsc_dump_cmd_destroy); 161 162int mlx5_rsc_dump_next(struct mlx5_core_dev *dev, struct mlx5_rsc_dump_cmd *cmd, 163 struct page *page, int *size) 164{ 165 bool more_dump; 166 int err; 167 168 if (IS_ERR_OR_NULL(dev->rsc_dump)) 169 return -EOPNOTSUPP; 170 171 err = mlx5_rsc_dump_trigger(dev, cmd, page); 172 if (err) { 173 mlx5_core_err(dev, "Resource dump: Failed to trigger dump, %d\n", err); 174 return err; 175 } 176 *size = MLX5_GET(resource_dump, cmd->cmd, size); 177 more_dump = MLX5_GET(resource_dump, cmd->cmd, more_dump); 178 179 return more_dump; 180} 181EXPORT_SYMBOL(mlx5_rsc_dump_next); 182 183#define MLX5_RSC_DUMP_MENU_SEGMENT 0xffff 184static int mlx5_rsc_dump_menu(struct mlx5_core_dev *dev) 185{ 186 struct mlx5_rsc_dump_cmd *cmd = NULL; 187 struct mlx5_rsc_key key = {}; 188 struct page *page; 189 int start_idx = 0; 190 int size; 191 int err; 192 193 page = alloc_page(GFP_KERNEL); 194 if (!page) 195 return -ENOMEM; 196 197 key.rsc = MLX5_SGMT_TYPE_MENU; 198 key.size = PAGE_SIZE; 199 cmd = mlx5_rsc_dump_cmd_create(dev, &key); 200 if (IS_ERR(cmd)) { 201 err = PTR_ERR(cmd); 202 goto free_page; 203 } 204 MLX5_SET(resource_dump, cmd->cmd, segment_type, MLX5_RSC_DUMP_MENU_SEGMENT); 205 206 do { 207 err = mlx5_rsc_dump_next(dev, cmd, page, &size); 208 if (err < 0) 209 goto destroy_cmd; 210 211 start_idx = mlx5_rsc_dump_read_menu_sgmt(dev->rsc_dump, page, size, start_idx); 212 213 } while (err > 0); 214 215destroy_cmd: 216 mlx5_rsc_dump_cmd_destroy(cmd); 217free_page: 218 __free_page(page); 219 220 return err; 221} 222 223static int mlx5_rsc_dump_create_mkey(struct mlx5_core_dev *mdev, u32 pdn, 224 u32 *mkey) 225{ 226 int inlen = MLX5_ST_SZ_BYTES(create_mkey_in); 227 void *mkc; 228 u32 *in; 229 int err; 230 231 in = kvzalloc(inlen, GFP_KERNEL); 232 if (!in) 233 return -ENOMEM; 234 235 mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry); 236 MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA); 237 MLX5_SET(mkc, mkc, lw, 1); 238 MLX5_SET(mkc, mkc, lr, 1); 239 240 MLX5_SET(mkc, mkc, pd, pdn); 241 MLX5_SET(mkc, mkc, length64, 1); 242 MLX5_SET(mkc, mkc, qpn, 0xffffff); 243 244 err = mlx5_core_create_mkey(mdev, mkey, in, inlen); 245 246 kvfree(in); 247 return err; 248} 249 250struct mlx5_rsc_dump *mlx5_rsc_dump_create(struct mlx5_core_dev *dev) 251{ 252 struct mlx5_rsc_dump *rsc_dump; 253 254 if (!MLX5_CAP_DEBUG(dev, resource_dump)) { 255 mlx5_core_dbg(dev, "Resource dump: capability not present\n"); 256 return NULL; 257 } 258 rsc_dump = kzalloc(sizeof(*rsc_dump), GFP_KERNEL); 259 if (!rsc_dump) 260 return ERR_PTR(-ENOMEM); 261 262 return rsc_dump; 263} 264 265void mlx5_rsc_dump_destroy(struct mlx5_core_dev *dev) 266{ 267 if (IS_ERR_OR_NULL(dev->rsc_dump)) 268 return; 269 kfree(dev->rsc_dump); 270} 271 272int mlx5_rsc_dump_init(struct mlx5_core_dev *dev) 273{ 274 struct mlx5_rsc_dump *rsc_dump = dev->rsc_dump; 275 int err; 276 277 if (IS_ERR_OR_NULL(dev->rsc_dump)) 278 return 0; 279 280 err = mlx5_core_alloc_pd(dev, &rsc_dump->pdn); 281 if (err) { 282 mlx5_core_warn(dev, "Resource dump: Failed to allocate PD %d\n", err); 283 return err; 284 } 285 err = mlx5_rsc_dump_create_mkey(dev, rsc_dump->pdn, &rsc_dump->mkey); 286 if (err) { 287 mlx5_core_err(dev, "Resource dump: Failed to create mkey, %d\n", err); 288 goto free_pd; 289 } 290 err = mlx5_rsc_dump_menu(dev); 291 if (err) { 292 mlx5_core_err(dev, "Resource dump: Failed to read menu, %d\n", err); 293 goto destroy_mkey; 294 } 295 return err; 296 297destroy_mkey: 298 mlx5_core_destroy_mkey(dev, rsc_dump->mkey); 299free_pd: 300 mlx5_core_dealloc_pd(dev, rsc_dump->pdn); 301 return err; 302} 303 304void mlx5_rsc_dump_cleanup(struct mlx5_core_dev *dev) 305{ 306 if (IS_ERR_OR_NULL(dev->rsc_dump)) 307 return; 308 309 mlx5_core_destroy_mkey(dev, dev->rsc_dump->mkey); 310 mlx5_core_dealloc_pd(dev, dev->rsc_dump->pdn); 311} 312