xref: /linux/drivers/infiniband/hw/ionic/ionic_hw_stats.c (revision 570f7e331f5febb30f1384817463c7e42b65ca7d)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
3 
4 #include <linux/dma-mapping.h>
5 
6 #include "ionic_fw.h"
7 #include "ionic_ibdev.h"
8 
9 static int ionic_v1_stat_normalize(struct ionic_v1_stat *hw_stats,
10 				   int hw_stats_count)
11 {
12 	int hw_stat_i;
13 
14 	for (hw_stat_i = 0; hw_stat_i < hw_stats_count; ++hw_stat_i) {
15 		struct ionic_v1_stat *stat = &hw_stats[hw_stat_i];
16 
17 		stat->type_off = be32_to_cpu(stat->be_type_off);
18 		stat->name[sizeof(stat->name) - 1] = 0;
19 		if (ionic_v1_stat_type(stat) == IONIC_V1_STAT_TYPE_NONE)
20 			break;
21 	}
22 
23 	return hw_stat_i;
24 }
25 
26 static void ionic_fill_stats_desc(struct rdma_stat_desc *hw_stats_hdrs,
27 				  struct ionic_v1_stat *hw_stats,
28 				  int hw_stats_count)
29 {
30 	int hw_stat_i;
31 
32 	for (hw_stat_i = 0; hw_stat_i < hw_stats_count; ++hw_stat_i) {
33 		struct ionic_v1_stat *stat = &hw_stats[hw_stat_i];
34 
35 		hw_stats_hdrs[hw_stat_i].name = stat->name;
36 	}
37 }
38 
39 static u64 ionic_v1_stat_val(struct ionic_v1_stat *stat,
40 			     void *vals_buf, size_t vals_len)
41 {
42 	unsigned int off = ionic_v1_stat_off(stat);
43 	int type = ionic_v1_stat_type(stat);
44 
45 #define __ionic_v1_stat_validate(__type)		\
46 	((off + sizeof(__type) <= vals_len) &&		\
47 	 (IS_ALIGNED(off, sizeof(__type))))
48 
49 	switch (type) {
50 	case IONIC_V1_STAT_TYPE_8:
51 		if (__ionic_v1_stat_validate(u8))
52 			return *(u8 *)(vals_buf + off);
53 		break;
54 	case IONIC_V1_STAT_TYPE_LE16:
55 		if (__ionic_v1_stat_validate(__le16))
56 			return le16_to_cpu(*(__le16 *)(vals_buf + off));
57 		break;
58 	case IONIC_V1_STAT_TYPE_LE32:
59 		if (__ionic_v1_stat_validate(__le32))
60 			return le32_to_cpu(*(__le32 *)(vals_buf + off));
61 		break;
62 	case IONIC_V1_STAT_TYPE_LE64:
63 		if (__ionic_v1_stat_validate(__le64))
64 			return le64_to_cpu(*(__le64 *)(vals_buf + off));
65 		break;
66 	case IONIC_V1_STAT_TYPE_BE16:
67 		if (__ionic_v1_stat_validate(__be16))
68 			return be16_to_cpu(*(__be16 *)(vals_buf + off));
69 		break;
70 	case IONIC_V1_STAT_TYPE_BE32:
71 		if (__ionic_v1_stat_validate(__be32))
72 			return be32_to_cpu(*(__be32 *)(vals_buf + off));
73 		break;
74 	case IONIC_V1_STAT_TYPE_BE64:
75 		if (__ionic_v1_stat_validate(__be64))
76 			return be64_to_cpu(*(__be64 *)(vals_buf + off));
77 		break;
78 	}
79 
80 	return ~0ull;
81 #undef __ionic_v1_stat_validate
82 }
83 
84 static int ionic_hw_stats_cmd(struct ionic_ibdev *dev,
85 			      dma_addr_t dma, size_t len, int qid, int op)
86 {
87 	struct ionic_admin_wr wr = {
88 		.work = COMPLETION_INITIALIZER_ONSTACK(wr.work),
89 		.wqe = {
90 			.op = op,
91 			.len = cpu_to_le16(IONIC_ADMIN_STATS_HDRS_IN_V1_LEN),
92 			.cmd.stats = {
93 				.dma_addr = cpu_to_le64(dma),
94 				.length = cpu_to_le32(len),
95 				.id_ver = cpu_to_le32(qid),
96 			},
97 		}
98 	};
99 
100 	if (dev->lif_cfg.admin_opcodes <= op)
101 		return -EBADRQC;
102 
103 	ionic_admin_post(dev, &wr);
104 
105 	return ionic_admin_wait(dev, &wr, IONIC_ADMIN_F_INTERRUPT);
106 }
107 
108 static int ionic_init_hw_stats(struct ionic_ibdev *dev)
109 {
110 	dma_addr_t hw_stats_dma;
111 	int rc, hw_stats_count;
112 
113 	if (dev->hw_stats_hdrs)
114 		return 0;
115 
116 	dev->hw_stats_count = 0;
117 
118 	/* buffer for current values from the device */
119 	dev->hw_stats_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
120 	if (!dev->hw_stats_buf) {
121 		rc = -ENOMEM;
122 		goto err_buf;
123 	}
124 
125 	/* buffer for names, sizes, offsets of values */
126 	dev->hw_stats = kzalloc(PAGE_SIZE, GFP_KERNEL);
127 	if (!dev->hw_stats) {
128 		rc = -ENOMEM;
129 		goto err_hw_stats;
130 	}
131 
132 	/* request the names, sizes, offsets */
133 	hw_stats_dma = dma_map_single(dev->lif_cfg.hwdev, dev->hw_stats,
134 				      PAGE_SIZE, DMA_FROM_DEVICE);
135 	rc = dma_mapping_error(dev->lif_cfg.hwdev, hw_stats_dma);
136 	if (rc)
137 		goto err_dma;
138 
139 	rc = ionic_hw_stats_cmd(dev, hw_stats_dma, PAGE_SIZE, 0,
140 				IONIC_V1_ADMIN_STATS_HDRS);
141 	if (rc)
142 		goto err_cmd;
143 
144 	dma_unmap_single(dev->lif_cfg.hwdev, hw_stats_dma, PAGE_SIZE, DMA_FROM_DEVICE);
145 
146 	/* normalize and count the number of hw_stats */
147 	hw_stats_count =
148 		ionic_v1_stat_normalize(dev->hw_stats,
149 					PAGE_SIZE / sizeof(*dev->hw_stats));
150 	if (!hw_stats_count) {
151 		rc = -ENODATA;
152 		goto err_dma;
153 	}
154 
155 	dev->hw_stats_count = hw_stats_count;
156 
157 	/* alloc and init array of names, for alloc_hw_stats */
158 	dev->hw_stats_hdrs = kzalloc_objs(*dev->hw_stats_hdrs, hw_stats_count);
159 	if (!dev->hw_stats_hdrs) {
160 		rc = -ENOMEM;
161 		goto err_dma;
162 	}
163 
164 	ionic_fill_stats_desc(dev->hw_stats_hdrs, dev->hw_stats,
165 			      hw_stats_count);
166 
167 	return 0;
168 
169 err_cmd:
170 	dma_unmap_single(dev->lif_cfg.hwdev, hw_stats_dma, PAGE_SIZE, DMA_FROM_DEVICE);
171 err_dma:
172 	kfree(dev->hw_stats);
173 err_hw_stats:
174 	kfree(dev->hw_stats_buf);
175 err_buf:
176 	dev->hw_stats_count = 0;
177 	dev->hw_stats = NULL;
178 	dev->hw_stats_buf = NULL;
179 	dev->hw_stats_hdrs = NULL;
180 	return rc;
181 }
182 
183 static struct rdma_hw_stats *ionic_alloc_hw_stats(struct ib_device *ibdev,
184 						  u32 port)
185 {
186 	struct ionic_ibdev *dev = to_ionic_ibdev(ibdev);
187 
188 	if (port != 1)
189 		return NULL;
190 
191 	return rdma_alloc_hw_stats_struct(dev->hw_stats_hdrs,
192 					  dev->hw_stats_count,
193 					  RDMA_HW_STATS_DEFAULT_LIFESPAN);
194 }
195 
196 static int ionic_get_hw_stats(struct ib_device *ibdev,
197 			      struct rdma_hw_stats *hw_stats,
198 			      u32 port, int index)
199 {
200 	struct ionic_ibdev *dev = to_ionic_ibdev(ibdev);
201 	dma_addr_t hw_stats_dma;
202 	int rc, hw_stat_i;
203 
204 	if (port != 1)
205 		return -EINVAL;
206 
207 	hw_stats_dma = dma_map_single(dev->lif_cfg.hwdev, dev->hw_stats_buf,
208 				      PAGE_SIZE, DMA_FROM_DEVICE);
209 	rc = dma_mapping_error(dev->lif_cfg.hwdev, hw_stats_dma);
210 	if (rc)
211 		goto err_dma;
212 
213 	rc = ionic_hw_stats_cmd(dev, hw_stats_dma, PAGE_SIZE,
214 				0, IONIC_V1_ADMIN_STATS_VALS);
215 	if (rc)
216 		goto err_cmd;
217 
218 	dma_unmap_single(dev->lif_cfg.hwdev, hw_stats_dma,
219 			 PAGE_SIZE, DMA_FROM_DEVICE);
220 
221 	for (hw_stat_i = 0; hw_stat_i < dev->hw_stats_count; ++hw_stat_i)
222 		hw_stats->value[hw_stat_i] =
223 			ionic_v1_stat_val(&dev->hw_stats[hw_stat_i],
224 					  dev->hw_stats_buf, PAGE_SIZE);
225 
226 	return hw_stat_i;
227 
228 err_cmd:
229 	dma_unmap_single(dev->lif_cfg.hwdev, hw_stats_dma,
230 			 PAGE_SIZE, DMA_FROM_DEVICE);
231 err_dma:
232 	return rc;
233 }
234 
235 static struct rdma_hw_stats *
236 ionic_counter_alloc_stats(struct rdma_counter *counter)
237 {
238 	struct ionic_rdma_counter *cntr = to_ionic_rdma_counter(counter);
239 	struct ionic_ibdev *dev = to_ionic_ibdev(counter->device);
240 	struct rdma_hw_stats *stats;
241 	int id;
242 
243 	cntr->vals = kzalloc(PAGE_SIZE, GFP_KERNEL);
244 	if (!cntr->vals)
245 		return NULL;
246 
247 	id = ida_alloc_max(&dev->counter_stats->counter_ida,
248 			   IONIC_MAX_QPID, GFP_KERNEL);
249 	if (id < 0)
250 		goto err_ida;
251 
252 	counter->id = id;
253 
254 	stats = rdma_alloc_hw_stats_struct(dev->counter_stats->stats_hdrs,
255 					   dev->counter_stats->queue_stats_count,
256 					   RDMA_HW_STATS_DEFAULT_LIFESPAN);
257 	if (!stats)
258 		goto err_hw_stats;
259 
260 	return stats;
261 
262 err_hw_stats:
263 	ida_free(&dev->counter_stats->counter_ida, id);
264 err_ida:
265 	kfree(cntr->vals);
266 
267 	return NULL;
268 }
269 
270 static int ionic_counter_dealloc(struct rdma_counter *counter)
271 {
272 	struct ionic_ibdev *dev = to_ionic_ibdev(counter->device);
273 	struct ionic_rdma_counter *cntr = to_ionic_rdma_counter(counter);
274 
275 	ida_free(&dev->counter_stats->counter_ida, counter->id);
276 	kfree(cntr->vals);
277 
278 	return 0;
279 }
280 
281 static int ionic_counter_bind_qp(struct rdma_counter *counter,
282 				 struct ib_qp *ibqp,
283 				 u32 port)
284 {
285 	struct ionic_rdma_counter *cntr = to_ionic_rdma_counter(counter);
286 	struct ionic_qp *qp = to_ionic_qp(ibqp);
287 
288 	list_add_tail(&qp->qp_list_counter, &cntr->qp_list);
289 	ibqp->counter = counter;
290 
291 	return 0;
292 }
293 
294 static int ionic_counter_unbind_qp(struct ib_qp *ibqp, u32 port)
295 {
296 	struct ionic_qp *qp = to_ionic_qp(ibqp);
297 
298 	if (ibqp->counter) {
299 		list_del(&qp->qp_list_counter);
300 		ibqp->counter = NULL;
301 	}
302 
303 	return 0;
304 }
305 
306 static int ionic_counter_update_stats(struct rdma_counter *counter)
307 {
308 	struct ionic_rdma_counter *cntr = to_ionic_rdma_counter(counter);
309 	struct ionic_ibdev *dev = to_ionic_ibdev(counter->device);
310 	struct ionic_counter_stats *cs = dev->counter_stats;
311 	dma_addr_t hw_stats_dma;
312 	struct ionic_qp *qp;
313 	int rc, stat_i = 0;
314 
315 	hw_stats_dma = dma_map_single(dev->lif_cfg.hwdev, cntr->vals,
316 				      PAGE_SIZE, DMA_FROM_DEVICE);
317 	rc = dma_mapping_error(dev->lif_cfg.hwdev, hw_stats_dma);
318 	if (rc)
319 		return rc;
320 
321 	memset(counter->stats->value, 0,
322 	       sizeof(u64) * counter->stats->num_counters);
323 
324 	list_for_each_entry(qp, &cntr->qp_list, qp_list_counter) {
325 		rc = ionic_hw_stats_cmd(dev, hw_stats_dma, PAGE_SIZE,
326 					qp->qpid,
327 					IONIC_V1_ADMIN_QP_STATS_VALS);
328 		if (rc)
329 			goto err_cmd;
330 
331 		for (stat_i = 0; stat_i < cs->queue_stats_count; ++stat_i)
332 			counter->stats->value[stat_i] +=
333 				ionic_v1_stat_val(&cs->hdr[stat_i],
334 						  cntr->vals,
335 						  PAGE_SIZE);
336 	}
337 
338 	dma_unmap_single(dev->lif_cfg.hwdev, hw_stats_dma, PAGE_SIZE, DMA_FROM_DEVICE);
339 	return stat_i;
340 
341 err_cmd:
342 	dma_unmap_single(dev->lif_cfg.hwdev, hw_stats_dma, PAGE_SIZE, DMA_FROM_DEVICE);
343 
344 	return rc;
345 }
346 
347 static int ionic_alloc_counters(struct ionic_ibdev *dev)
348 {
349 	struct ionic_counter_stats *cs = dev->counter_stats;
350 	int rc, hw_stats_count;
351 	dma_addr_t hdr_dma;
352 
353 	/* buffer for names, sizes, offsets of values */
354 	cs->hdr = kzalloc(PAGE_SIZE, GFP_KERNEL);
355 	if (!cs->hdr)
356 		return -ENOMEM;
357 
358 	hdr_dma = dma_map_single(dev->lif_cfg.hwdev, cs->hdr,
359 				 PAGE_SIZE, DMA_FROM_DEVICE);
360 	rc = dma_mapping_error(dev->lif_cfg.hwdev, hdr_dma);
361 	if (rc)
362 		goto err_dma;
363 
364 	rc = ionic_hw_stats_cmd(dev, hdr_dma, PAGE_SIZE, 0,
365 				IONIC_V1_ADMIN_QP_STATS_HDRS);
366 	if (rc)
367 		goto err_cmd;
368 
369 	dma_unmap_single(dev->lif_cfg.hwdev, hdr_dma, PAGE_SIZE, DMA_FROM_DEVICE);
370 
371 	/* normalize and count the number of hw_stats */
372 	hw_stats_count = ionic_v1_stat_normalize(cs->hdr,
373 						 PAGE_SIZE / sizeof(*cs->hdr));
374 	if (!hw_stats_count) {
375 		rc = -ENODATA;
376 		goto err_dma;
377 	}
378 
379 	cs->queue_stats_count = hw_stats_count;
380 
381 	/* alloc and init array of names */
382 	cs->stats_hdrs = kzalloc_objs(*cs->stats_hdrs, hw_stats_count);
383 	if (!cs->stats_hdrs) {
384 		rc = -ENOMEM;
385 		goto err_dma;
386 	}
387 
388 	ionic_fill_stats_desc(cs->stats_hdrs, cs->hdr, hw_stats_count);
389 
390 	return 0;
391 
392 err_cmd:
393 	dma_unmap_single(dev->lif_cfg.hwdev, hdr_dma, PAGE_SIZE, DMA_FROM_DEVICE);
394 err_dma:
395 	kfree(cs->hdr);
396 
397 	return rc;
398 }
399 
400 static const struct ib_device_ops ionic_hw_stats_ops = {
401 	.driver_id = RDMA_DRIVER_IONIC,
402 	.alloc_hw_port_stats = ionic_alloc_hw_stats,
403 	.get_hw_stats = ionic_get_hw_stats,
404 };
405 
406 static void ionic_counter_init(struct rdma_counter *counter)
407 {
408 	struct ionic_rdma_counter *cntr = to_ionic_rdma_counter(counter);
409 
410 	INIT_LIST_HEAD(&cntr->qp_list);
411 }
412 
413 static const struct ib_device_ops ionic_counter_stats_ops = {
414 	.counter_alloc_stats = ionic_counter_alloc_stats,
415 	.counter_dealloc = ionic_counter_dealloc,
416 	.counter_bind_qp = ionic_counter_bind_qp,
417 	.counter_unbind_qp = ionic_counter_unbind_qp,
418 	.counter_update_stats = ionic_counter_update_stats,
419 	.counter_init = ionic_counter_init,
420 
421 	INIT_RDMA_OBJ_SIZE(rdma_counter, ionic_rdma_counter, rdma_counter),
422 };
423 
424 void ionic_stats_init(struct ionic_ibdev *dev)
425 {
426 	u16 stats_type = dev->lif_cfg.stats_type;
427 	int rc;
428 
429 	if (stats_type & IONIC_LIF_RDMA_STAT_GLOBAL) {
430 		rc = ionic_init_hw_stats(dev);
431 		if (rc)
432 			ibdev_dbg(&dev->ibdev, "Failed to init hw stats\n");
433 		else
434 			ib_set_device_ops(&dev->ibdev, &ionic_hw_stats_ops);
435 	}
436 
437 	if (stats_type & IONIC_LIF_RDMA_STAT_QP) {
438 		dev->counter_stats = kzalloc_obj(*dev->counter_stats);
439 		if (!dev->counter_stats)
440 			return;
441 
442 		rc = ionic_alloc_counters(dev);
443 		if (rc) {
444 			ibdev_dbg(&dev->ibdev, "Failed to init counter stats\n");
445 			kfree(dev->counter_stats);
446 			dev->counter_stats = NULL;
447 			return;
448 		}
449 
450 		ida_init(&dev->counter_stats->counter_ida);
451 
452 		ib_set_device_ops(&dev->ibdev, &ionic_counter_stats_ops);
453 	}
454 }
455 
456 void ionic_stats_cleanup(struct ionic_ibdev *dev)
457 {
458 	if (dev->counter_stats) {
459 		ida_destroy(&dev->counter_stats->counter_ida);
460 		kfree(dev->counter_stats->hdr);
461 		kfree(dev->counter_stats->stats_hdrs);
462 		kfree(dev->counter_stats);
463 		dev->counter_stats = NULL;
464 	}
465 
466 	kfree(dev->hw_stats);
467 	kfree(dev->hw_stats_buf);
468 	kfree(dev->hw_stats_hdrs);
469 }
470