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