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 9 static 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 31 struct mlx5_rsc_dump { 32 u32 pdn; 33 struct mlx5_core_mkey mkey; 34 u16 fw_segment_type[MLX5_SGMT_TYPE_NUM]; 35 }; 36 37 struct mlx5_rsc_dump_cmd { 38 u64 mem_size; 39 u8 cmd[MLX5_ST_SZ_BYTES(resource_dump)]; 40 }; 41 42 static 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 53 static 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 77 static 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 = &dev->pdev->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; 104 out: 105 dma_unmap_page(ddev, dma, cmd->mem_size, DMA_FROM_DEVICE); 106 return err; 107 } 108 109 struct 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 } 136 EXPORT_SYMBOL(mlx5_rsc_dump_cmd_create); 137 138 void mlx5_rsc_dump_cmd_destroy(struct mlx5_rsc_dump_cmd *cmd) 139 { 140 kfree(cmd); 141 } 142 EXPORT_SYMBOL(mlx5_rsc_dump_cmd_destroy); 143 144 int 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 } 163 EXPORT_SYMBOL(mlx5_rsc_dump_next); 164 165 #define MLX5_RSC_DUMP_MENU_SEGMENT 0xffff 166 static 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 196 destroy_cmd: 197 mlx5_rsc_dump_cmd_destroy(cmd); 198 free_page: 199 __free_page(page); 200 201 return err; 202 } 203 204 static 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 231 struct 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 246 void 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 253 int 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 278 destroy_mkey: 279 mlx5_core_destroy_mkey(dev, &rsc_dump->mkey); 280 free_pd: 281 mlx5_core_dealloc_pd(dev, rsc_dump->pdn); 282 return err; 283 } 284 285 void 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