File Index
Files and directories
Sign in
FILE

adf_tl_debugfs.c

File preview with syntax highlighting.

linux-6.19.14/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/* Copyright (c) 2023 Intel Corporation. */
  3#define dev_fmt(fmt) "Telemetry debugfs: " fmt
  4
  5#include <linux/atomic.h>
  6#include <linux/debugfs.h>
  7#include <linux/dev_printk.h>
  8#include <linux/dcache.h>
  9#include <linux/file.h>
 10#include <linux/kernel.h>
 11#include <linux/math64.h>
 12#include <linux/mutex.h>
 13#include <linux/seq_file.h>
 14#include <linux/slab.h>
 15#include <linux/units.h>
 16
 17#include "adf_accel_devices.h"
 18#include "adf_cfg_strings.h"
 19#include "adf_telemetry.h"
 20#include "adf_tl_debugfs.h"
 21
 22#define TL_VALUE_MIN_PADDING	20
 23#define TL_KEY_MIN_PADDING	23
 24#define TL_RP_SRV_UNKNOWN	"Unknown"
 25
 26static int tl_collect_values_u32(struct adf_telemetry *telemetry,
 27				 size_t counter_offset, u64 *arr)
 28{
 29	unsigned int samples, hb_idx, i;
 30	u32 *regs_hist_buff;
 31	u32 counter_val;
 32
 33	samples = min(telemetry->msg_cnt, telemetry->hbuffs);
 34	hb_idx = telemetry->hb_num + telemetry->hbuffs - samples;
 35
 36	mutex_lock(&telemetry->regs_hist_lock);
 37
 38	for (i = 0; i < samples; i++) {
 39		regs_hist_buff = telemetry->regs_hist_buff[hb_idx % telemetry->hbuffs];
 40		counter_val = regs_hist_buff[counter_offset / sizeof(counter_val)];
 41		arr[i] = counter_val;
 42		hb_idx++;
 43	}
 44
 45	mutex_unlock(&telemetry->regs_hist_lock);
 46
 47	return samples;
 48}
 49
 50static int tl_collect_values_u64(struct adf_telemetry *telemetry,
 51				 size_t counter_offset, u64 *arr)
 52{
 53	unsigned int samples, hb_idx, i;
 54	u64 *regs_hist_buff;
 55	u64 counter_val;
 56
 57	samples = min(telemetry->msg_cnt, telemetry->hbuffs);
 58	hb_idx = telemetry->hb_num + telemetry->hbuffs - samples;
 59
 60	mutex_lock(&telemetry->regs_hist_lock);
 61
 62	for (i = 0; i < samples; i++) {
 63		regs_hist_buff = telemetry->regs_hist_buff[hb_idx % telemetry->hbuffs];
 64		counter_val = regs_hist_buff[counter_offset / sizeof(counter_val)];
 65		arr[i] = counter_val;
 66		hb_idx++;
 67	}
 68
 69	mutex_unlock(&telemetry->regs_hist_lock);
 70
 71	return samples;
 72}
 73
 74/**
 75 * avg_array() - Return average of values within an array.
 76 * @array: Array of values.
 77 * @len: Number of elements.
 78 *
 79 * This algorithm computes average of an array without running into overflow.
 80 *
 81 * Return: average of values.
 82 */
 83#define avg_array(array, len) (				\
 84{							\
 85	typeof(&(array)[0]) _array = (array);		\
 86	__unqual_scalar_typeof(_array[0]) _x = 0;	\
 87	__unqual_scalar_typeof(_array[0]) _y = 0;	\
 88	__unqual_scalar_typeof(_array[0]) _a, _b;	\
 89	typeof(len) _len = (len);			\
 90	size_t _i;					\
 91							\
 92	for (_i = 0; _i < _len; _i++) {			\
 93		_a = _array[_i];			\
 94		_b = do_div(_a, _len);			\
 95		_x += _a;				\
 96		if (_y >= _len - _b) {			\
 97			_x++;				\
 98			_y -= _len - _b;		\
 99		} else {				\
100			_y += _b;			\
101		}					\
102	}						\
103	do_div(_y, _len);				\
104	(_x + _y);					\
105})
106
107/* Calculation function for simple counter. */
108static int tl_calc_count(struct adf_telemetry *telemetry,
109			 const struct adf_tl_dbg_counter *ctr,
110			 struct adf_tl_dbg_aggr_values *vals)
111{
112	struct adf_tl_hw_data *tl_data = &GET_TL_DATA(telemetry->accel_dev);
113	u64 *hist_vals;
114	int sample_cnt;
115	int ret = 0;
116
117	hist_vals = kmalloc_array(tl_data->num_hbuff, sizeof(*hist_vals),
118				  GFP_KERNEL);
119	if (!hist_vals)
120		return -ENOMEM;
121
122	memset(vals, 0, sizeof(*vals));
123	sample_cnt = tl_collect_values_u32(telemetry, ctr->offset1, hist_vals);
124	if (!sample_cnt)
125		goto out_free_hist_vals;
126
127	vals->curr = hist_vals[sample_cnt - 1];
128	vals->min = min_array(hist_vals, sample_cnt);
129	vals->max = max_array(hist_vals, sample_cnt);
130	vals->avg = avg_array(hist_vals, sample_cnt);
131
132out_free_hist_vals:
133	kfree(hist_vals);
134	return ret;
135}
136
137/* Convert CPP bus cycles to ns. */
138static int tl_cycles_to_ns(struct adf_telemetry *telemetry,
139			   const struct adf_tl_dbg_counter *ctr,
140			   struct adf_tl_dbg_aggr_values *vals)
141{
142	struct adf_tl_hw_data *tl_data = &GET_TL_DATA(telemetry->accel_dev);
143	u8 cpp_ns_per_cycle = tl_data->cpp_ns_per_cycle;
144	int ret;
145
146	ret = tl_calc_count(telemetry, ctr, vals);
147	if (ret)
148		return ret;
149
150	vals->curr *= cpp_ns_per_cycle;
151	vals->min *= cpp_ns_per_cycle;
152	vals->max *= cpp_ns_per_cycle;
153	vals->avg *= cpp_ns_per_cycle;
154
155	return 0;
156}
157
158/*
159 * Compute latency cumulative average with division of accumulated value
160 * by sample count. Returned value is in ns.
161 */
162static int tl_lat_acc_avg(struct adf_telemetry *telemetry,
163			  const struct adf_tl_dbg_counter *ctr,
164			  struct adf_tl_dbg_aggr_values *vals)
165{
166	struct adf_tl_hw_data *tl_data = &GET_TL_DATA(telemetry->accel_dev);
167	u8 cpp_ns_per_cycle = tl_data->cpp_ns_per_cycle;
168	u8 num_hbuff = tl_data->num_hbuff;
169	int sample_cnt, i;
170	u64 *hist_vals;
171	u64 *hist_cnt;
172	int ret = 0;
173
174	hist_vals = kmalloc_array(num_hbuff, sizeof(*hist_vals), GFP_KERNEL);
175	if (!hist_vals)
176		return -ENOMEM;
177
178	hist_cnt = kmalloc_array(num_hbuff, sizeof(*hist_cnt), GFP_KERNEL);
179	if (!hist_cnt) {
180		ret = -ENOMEM;
181		goto out_free_hist_vals;
182	}
183
184	memset(vals, 0, sizeof(*vals));
185	sample_cnt = tl_collect_values_u64(telemetry, ctr->offset1, hist_vals);
186	if (!sample_cnt)
187		goto out_free_hist_cnt;
188
189	tl_collect_values_u32(telemetry, ctr->offset2, hist_cnt);
190
191	for (i = 0; i < sample_cnt; i++) {
192		/* Avoid division by 0 if count is 0. */
193		if (hist_cnt[i])
194			hist_vals[i] = div_u64(hist_vals[i] * cpp_ns_per_cycle,
195					       hist_cnt[i]);
196		else
197			hist_vals[i] = 0;
198	}
199
200	vals->curr = hist_vals[sample_cnt - 1];
201	vals->min = min_array(hist_vals, sample_cnt);
202	vals->max = max_array(hist_vals, sample_cnt);
203	vals->avg = avg_array(hist_vals, sample_cnt);
204
205out_free_hist_cnt:
206	kfree(hist_cnt);
207out_free_hist_vals:
208	kfree(hist_vals);
209	return ret;
210}
211
212/* Convert HW raw bandwidth units to Mbps. */
213static int tl_bw_hw_units_to_mbps(struct adf_telemetry *telemetry,
214				  const struct adf_tl_dbg_counter *ctr,
215				  struct adf_tl_dbg_aggr_values *vals)
216{
217	struct adf_tl_hw_data *tl_data = &GET_TL_DATA(telemetry->accel_dev);
218	u16 bw_hw_2_bits = tl_data->bw_units_to_bytes * BITS_PER_BYTE;
219	u64 *hist_vals;
220	int sample_cnt;
221	int ret = 0;
222
223	hist_vals = kmalloc_array(tl_data->num_hbuff, sizeof(*hist_vals),
224				  GFP_KERNEL);
225	if (!hist_vals)
226		return -ENOMEM;
227
228	memset(vals, 0, sizeof(*vals));
229	sample_cnt = tl_collect_values_u32(telemetry, ctr->offset1, hist_vals);
230	if (!sample_cnt)
231		goto out_free_hist_vals;
232
233	vals->curr = div_u64(hist_vals[sample_cnt - 1] * bw_hw_2_bits, MEGA);
234	vals->min = div_u64(min_array(hist_vals, sample_cnt) * bw_hw_2_bits, MEGA);
235	vals->max = div_u64(max_array(hist_vals, sample_cnt) * bw_hw_2_bits, MEGA);
236	vals->avg = div_u64(avg_array(hist_vals, sample_cnt) * bw_hw_2_bits, MEGA);
237
238out_free_hist_vals:
239	kfree(hist_vals);
240	return ret;
241}
242
243static void tl_seq_printf_counter(struct adf_telemetry *telemetry,
244				  struct seq_file *s, const char *name,
245				  struct adf_tl_dbg_aggr_values *vals)
246{
247	seq_printf(s, "%-*s", TL_KEY_MIN_PADDING, name);
248	seq_printf(s, "%*llu", TL_VALUE_MIN_PADDING, vals->curr);
249	if (atomic_read(&telemetry->state) > 1) {
250		seq_printf(s, "%*llu", TL_VALUE_MIN_PADDING, vals->min);
251		seq_printf(s, "%*llu", TL_VALUE_MIN_PADDING, vals->max);
252		seq_printf(s, "%*llu", TL_VALUE_MIN_PADDING, vals->avg);
253	}
254	seq_puts(s, "\n");
255}
256
257static int tl_calc_and_print_counter(struct adf_telemetry *telemetry,
258				     struct seq_file *s,
259				     const struct adf_tl_dbg_counter *ctr,
260				     const char *name)
261{
262	const char *counter_name = name ? name : ctr->name;
263	enum adf_tl_counter_type type = ctr->type;
264	struct adf_tl_dbg_aggr_values vals;
265	int ret;
266
267	switch (type) {
268	case ADF_TL_SIMPLE_COUNT:
269		ret = tl_calc_count(telemetry, ctr, &vals);
270		break;
271	case ADF_TL_COUNTER_NS:
272		ret = tl_cycles_to_ns(telemetry, ctr, &vals);
273		break;
274	case ADF_TL_COUNTER_NS_AVG:
275		ret = tl_lat_acc_avg(telemetry, ctr, &vals);
276		break;
277	case ADF_TL_COUNTER_MBPS:
278		ret = tl_bw_hw_units_to_mbps(telemetry, ctr, &vals);
279		break;
280	default:
281		return -EINVAL;
282	}
283
284	if (ret)
285		return ret;
286
287	tl_seq_printf_counter(telemetry, s, counter_name, &vals);
288
289	return 0;
290}
291
292static int tl_print_sl_counter(struct adf_telemetry *telemetry,
293			       const struct adf_tl_dbg_counter *ctr,
294			       struct seq_file *s, u8 cnt_id)
295{
296	size_t sl_regs_sz = GET_TL_DATA(telemetry->accel_dev).slice_reg_sz;
297	struct adf_tl_dbg_counter slice_ctr;
298	size_t offset_inc = cnt_id * sl_regs_sz;
299	char cnt_name[MAX_COUNT_NAME_SIZE];
300
301	snprintf(cnt_name, MAX_COUNT_NAME_SIZE, "%s%d", ctr->name, cnt_id);
302	slice_ctr = *ctr;
303	slice_ctr.offset1 += offset_inc;
304
305	return tl_calc_and_print_counter(telemetry, s, &slice_ctr, cnt_name);
306}
307
308static int tl_calc_and_print_sl_counters(struct adf_accel_dev *accel_dev,
309					 struct seq_file *s, u8 cnt_type, u8 cnt_id)
310{
311	struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev);
312	struct adf_telemetry *telemetry = accel_dev->telemetry;
313	const struct adf_tl_dbg_counter *sl_tl_util_counters;
314	const struct adf_tl_dbg_counter *sl_tl_exec_counters;
315	const struct adf_tl_dbg_counter *ctr;
316	int ret;
317
318	sl_tl_util_counters = tl_data->sl_util_counters;
319	sl_tl_exec_counters = tl_data->sl_exec_counters;
320
321	ctr = &sl_tl_util_counters[cnt_type];
322
323	ret = tl_print_sl_counter(telemetry, ctr, s, cnt_id);
324	if (ret) {
325		dev_notice(&GET_DEV(accel_dev),
326			   "invalid slice utilization counter type\n");
327		return ret;
328	}
329
330	ctr = &sl_tl_exec_counters[cnt_type];
331
332	ret = tl_print_sl_counter(telemetry, ctr, s, cnt_id);
333	if (ret) {
334		dev_notice(&GET_DEV(accel_dev),
335			   "invalid slice execution counter type\n");
336		return ret;
337	}
338
339	return 0;
340}
341
342static int tl_print_cmdq_counter(struct adf_telemetry *telemetry,
343				 const struct adf_tl_dbg_counter *ctr,
344				 struct seq_file *s, u8 cnt_id, u8 counter)
345{
346	size_t cmdq_regs_sz = GET_TL_DATA(telemetry->accel_dev).cmdq_reg_sz;
347	size_t offset_inc = cnt_id * cmdq_regs_sz;
348	struct adf_tl_dbg_counter slice_ctr;
349	char cnt_name[MAX_COUNT_NAME_SIZE];
350
351	slice_ctr = *(ctr + counter);
352	slice_ctr.offset1 += offset_inc;
353	snprintf(cnt_name, MAX_COUNT_NAME_SIZE, "%s%d", slice_ctr.name, cnt_id);
354
355	return tl_calc_and_print_counter(telemetry, s, &slice_ctr, cnt_name);
356}
357
358static int tl_calc_and_print_cmdq_counters(struct adf_accel_dev *accel_dev,
359					   struct seq_file *s, u8 cnt_type,
360					   u8 cnt_id)
361{
362	struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev);
363	struct adf_telemetry *telemetry = accel_dev->telemetry;
364	const struct adf_tl_dbg_counter **cmdq_tl_counters;
365	const struct adf_tl_dbg_counter *ctr;
366	u8 counter;
367	int ret;
368
369	cmdq_tl_counters = tl_data->cmdq_counters;
370	ctr = cmdq_tl_counters[cnt_type];
371
372	for (counter = 0; counter < tl_data->num_cmdq_counters; counter++) {
373		ret = tl_print_cmdq_counter(telemetry, ctr, s, cnt_id, counter);
374		if (ret) {
375			dev_notice(&GET_DEV(accel_dev),
376				   "invalid slice utilization counter type\n");
377			return ret;
378		}
379	}
380
381	return 0;
382}
383
384static void tl_print_msg_cnt(struct seq_file *s, u32 msg_cnt)
385{
386	seq_printf(s, "%-*s", TL_KEY_MIN_PADDING, SNAPSHOT_CNT_MSG);
387	seq_printf(s, "%*u\n", TL_VALUE_MIN_PADDING, msg_cnt);
388}
389
390static int tl_print_dev_data(struct adf_accel_dev *accel_dev,
391			     struct seq_file *s)
392{
393	struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev);
394	struct adf_telemetry *telemetry = accel_dev->telemetry;
395	const struct adf_tl_dbg_counter *dev_tl_counters;
396	u8 num_dev_counters = tl_data->num_dev_counters;
397	u8 *cmdq_cnt = (u8 *)&telemetry->cmdq_cnt;
398	u8 *sl_cnt = (u8 *)&telemetry->slice_cnt;
399	const struct adf_tl_dbg_counter *ctr;
400	unsigned int i;
401	int ret;
402	u8 j;
403
404	if (!atomic_read(&telemetry->state)) {
405		dev_info(&GET_DEV(accel_dev), "not enabled\n");
406		return -EPERM;
407	}
408
409	dev_tl_counters = tl_data->dev_counters;
410
411	tl_print_msg_cnt(s, telemetry->msg_cnt);
412
413	/* Print device level telemetry. */
414	for (i = 0; i < num_dev_counters; i++) {
415		ctr = &dev_tl_counters[i];
416		ret = tl_calc_and_print_counter(telemetry, s, ctr, NULL);
417		if (ret) {
418			dev_notice(&GET_DEV(accel_dev),
419				   "invalid counter type\n");
420			return ret;
421		}
422	}
423
424	/* Print per slice telemetry. */
425	for (i = 0; i < ADF_TL_SL_CNT_COUNT; i++) {
426		for (j = 0; j < sl_cnt[i]; j++) {
427			ret = tl_calc_and_print_sl_counters(accel_dev, s, i, j);
428			if (ret)
429				return ret;
430		}
431	}
432
433	/* Print per command queue telemetry. */
434	for (i = 0; i < ADF_TL_SL_CNT_COUNT; i++) {
435		for (j = 0; j < cmdq_cnt[i]; j++) {
436			ret = tl_calc_and_print_cmdq_counters(accel_dev, s, i, j);
437			if (ret)
438				return ret;
439		}
440	}
441
442	return 0;
443}
444
445static int tl_dev_data_show(struct seq_file *s, void *unused)
446{
447	struct adf_accel_dev *accel_dev = s->private;
448
449	if (!accel_dev)
450		return -EINVAL;
451
452	return tl_print_dev_data(accel_dev, s);
453}
454DEFINE_SHOW_ATTRIBUTE(tl_dev_data);
455
456static int tl_control_show(struct seq_file *s, void *unused)
457{
458	struct adf_accel_dev *accel_dev = s->private;
459
460	if (!accel_dev)
461		return -EINVAL;
462
463	seq_printf(s, "%d\n", atomic_read(&accel_dev->telemetry->state));
464
465	return 0;
466}
467
468static ssize_t tl_control_write(struct file *file, const char __user *userbuf,
469				size_t count, loff_t *ppos)
470{
471	struct seq_file *seq_f = file->private_data;
472	struct adf_accel_dev *accel_dev;
473	struct adf_telemetry *telemetry;
474	struct adf_tl_hw_data *tl_data;
475	struct device *dev;
476	u32 input;
477	int ret;
478
479	accel_dev = seq_f->private;
480	if (!accel_dev)
481		return -EINVAL;
482
483	tl_data = &GET_TL_DATA(accel_dev);
484	telemetry = accel_dev->telemetry;
485	dev = &GET_DEV(accel_dev);
486
487	mutex_lock(&telemetry->wr_lock);
488
489	ret = kstrtou32_from_user(userbuf, count, 10, &input);
490	if (ret)
491		goto unlock_and_exit;
492
493	if (input > tl_data->num_hbuff) {
494		dev_info(dev, "invalid control input\n");
495		ret = -EINVAL;
496		goto unlock_and_exit;
497	}
498
499	/* If input is 0, just stop telemetry. */
500	if (!input) {
501		ret = adf_tl_halt(accel_dev);
502		if (!ret)
503			ret = count;
504
505		goto unlock_and_exit;
506	}
507
508	/* If TL is already enabled, stop it. */
509	if (atomic_read(&telemetry->state)) {
510		dev_info(dev, "already enabled, restarting.\n");
511		ret = adf_tl_halt(accel_dev);
512		if (ret)
513			goto unlock_and_exit;
514	}
515
516	ret = adf_tl_run(accel_dev, input);
517	if (ret)
518		goto unlock_and_exit;
519
520	ret = count;
521
522unlock_and_exit:
523	mutex_unlock(&telemetry->wr_lock);
524	return ret;
525}
526DEFINE_SHOW_STORE_ATTRIBUTE(tl_control);
527
528static int adf_tl_dbg_change_rp_index(struct adf_accel_dev *accel_dev,
529				      unsigned int new_rp_num,
530				      unsigned int rp_regs_index)
531{
532	struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
533	struct adf_telemetry *telemetry = accel_dev->telemetry;
534	struct device *dev = &GET_DEV(accel_dev);
535	unsigned int i;
536	u8 curr_state;
537	int ret;
538
539	if (new_rp_num >= hw_data->num_rps) {
540		dev_info(dev, "invalid Ring Pair number selected\n");
541		return -EINVAL;
542	}
543
544	for (i = 0; i < hw_data->tl_data.max_rp; i++) {
545		if (telemetry->rp_num_indexes[i] == new_rp_num) {
546			dev_info(dev, "RP nr: %d is already selected in slot rp_%c_data\n",
547				 new_rp_num, ADF_TL_DBG_RP_ALPHA_INDEX(i));
548			return 0;
549		}
550	}
551
552	dev_dbg(dev, "selecting RP nr %u into slot rp_%c_data\n",
553		new_rp_num, ADF_TL_DBG_RP_ALPHA_INDEX(rp_regs_index));
554
555	curr_state = atomic_read(&telemetry->state);
556
557	if (curr_state) {
558		ret = adf_tl_halt(accel_dev);
559		if (ret)
560			return ret;
561
562		telemetry->rp_num_indexes[rp_regs_index] = new_rp_num;
563
564		ret = adf_tl_run(accel_dev, curr_state);
565		if (ret)
566			return ret;
567	} else {
568		telemetry->rp_num_indexes[rp_regs_index] = new_rp_num;
569	}
570
571	return 0;
572}
573
574static void tl_print_rp_srv(struct adf_accel_dev *accel_dev, struct seq_file *s,
575			    u8 rp_idx)
576{
577	u32 banks_per_vf = GET_HW_DATA(accel_dev)->num_banks_per_vf;
578	enum adf_cfg_service_type svc;
579
580	seq_printf(s, "%-*s", TL_KEY_MIN_PADDING, RP_SERVICE_TYPE);
581
582	svc = GET_SRV_TYPE(accel_dev, rp_idx % banks_per_vf);
583	switch (svc) {
584	case COMP:
585		seq_printf(s, "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_DC);
586		break;
587	case SYM:
588		seq_printf(s, "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_SYM);
589		break;
590	case ASYM:
591		seq_printf(s, "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_ASYM);
592		break;
593	case DECOMP:
594		seq_printf(s, "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_DECOMP);
595		break;
596	default:
597		seq_printf(s, "%*s\n", TL_VALUE_MIN_PADDING, TL_RP_SRV_UNKNOWN);
598		break;
599	}
600}
601
602static int tl_print_rp_data(struct adf_accel_dev *accel_dev, struct seq_file *s,
603			    u8 rp_regs_index)
604{
605	struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev);
606	struct adf_telemetry *telemetry = accel_dev->telemetry;
607	const struct adf_tl_dbg_counter *rp_tl_counters;
608	u8 num_rp_counters = tl_data->num_rp_counters;
609	size_t rp_regs_sz = tl_data->rp_reg_sz;
610	struct adf_tl_dbg_counter ctr;
611	unsigned int i;
612	u8 rp_idx;
613	int ret;
614
615	if (!atomic_read(&telemetry->state)) {
616		dev_info(&GET_DEV(accel_dev), "not enabled\n");
617		return -EPERM;
618	}
619
620	rp_tl_counters = tl_data->rp_counters;
621	rp_idx = telemetry->rp_num_indexes[rp_regs_index];
622
623	if (rp_idx == ADF_TL_RP_REGS_DISABLED) {
624		dev_info(&GET_DEV(accel_dev), "no RP number selected in rp_%c_data\n",
625			 ADF_TL_DBG_RP_ALPHA_INDEX(rp_regs_index));
626		return -EPERM;
627	}
628
629	tl_print_msg_cnt(s, telemetry->msg_cnt);
630	seq_printf(s, "%-*s", TL_KEY_MIN_PADDING, RP_NUM_INDEX);
631	seq_printf(s, "%*d\n", TL_VALUE_MIN_PADDING, rp_idx);
632	tl_print_rp_srv(accel_dev, s, rp_idx);
633
634	for (i = 0; i < num_rp_counters; i++) {
635		ctr = rp_tl_counters[i];
636		ctr.offset1 += rp_regs_sz * rp_regs_index;
637		ctr.offset2 += rp_regs_sz * rp_regs_index;
638		ret = tl_calc_and_print_counter(telemetry, s, &ctr, NULL);
639		if (ret) {
640			dev_dbg(&GET_DEV(accel_dev),
641				"invalid RP counter type\n");
642			return ret;
643		}
644	}
645
646	return 0;
647}
648
649static int tl_rp_data_show(struct seq_file *s, void *unused)
650{
651	struct adf_accel_dev *accel_dev = s->private;
652	u8 rp_regs_index;
653
654	if (!accel_dev)
655		return -EINVAL;
656
657	rp_regs_index = debugfs_get_aux_num(s->file);
658
659	return tl_print_rp_data(accel_dev, s, rp_regs_index);
660}
661
662static ssize_t tl_rp_data_write(struct file *file, const char __user *userbuf,
663				size_t count, loff_t *ppos)
664{
665	struct seq_file *seq_f = file->private_data;
666	struct adf_accel_dev *accel_dev;
667	struct adf_telemetry *telemetry;
668	unsigned int new_rp_num;
669	u8 rp_regs_index;
670	int ret;
671
672	accel_dev = seq_f->private;
673	if (!accel_dev)
674		return -EINVAL;
675
676	telemetry = accel_dev->telemetry;
677
678	mutex_lock(&telemetry->wr_lock);
679
680	rp_regs_index = debugfs_get_aux_num(file);
681
682	ret = kstrtou32_from_user(userbuf, count, 10, &new_rp_num);
683	if (ret)
684		goto unlock_and_exit;
685
686	ret = adf_tl_dbg_change_rp_index(accel_dev, new_rp_num, rp_regs_index);
687	if (ret)
688		goto unlock_and_exit;
689
690	ret = count;
691
692unlock_and_exit:
693	mutex_unlock(&telemetry->wr_lock);
694	return ret;
695}
696DEFINE_SHOW_STORE_ATTRIBUTE(tl_rp_data);
697
698void adf_tl_dbgfs_add(struct adf_accel_dev *accel_dev)
699{
700	struct adf_telemetry *telemetry = accel_dev->telemetry;
701	struct dentry *parent = accel_dev->debugfs_dir;
702	u8 max_rp = GET_TL_DATA(accel_dev).max_rp;
703	char name[ADF_TL_RP_REGS_FNAME_SIZE];
704	struct dentry *dir;
705	unsigned int i;
706
707	if (!telemetry)
708		return;
709
710	dir = debugfs_create_dir("telemetry", parent);
711	accel_dev->telemetry->dbg_dir = dir;
712	debugfs_create_file("device_data", 0444, dir, accel_dev, &tl_dev_data_fops);
713	debugfs_create_file("control", 0644, dir, accel_dev, &tl_control_fops);
714
715	for (i = 0; i < max_rp; i++) {
716		snprintf(name, sizeof(name), ADF_TL_RP_REGS_FNAME,
717			 ADF_TL_DBG_RP_ALPHA_INDEX(i));
718		debugfs_create_file_aux_num(name, 0644, dir, accel_dev, i,
719					    &tl_rp_data_fops);
720	}
721}
722
723void adf_tl_dbgfs_rm(struct adf_accel_dev *accel_dev)
724{
725	struct adf_telemetry *telemetry = accel_dev->telemetry;
726	struct dentry *dbg_dir;
727
728	if (!telemetry)
729		return;
730
731	dbg_dir = telemetry->dbg_dir;
732
733	debugfs_remove_recursive(dbg_dir);
734
735	if (atomic_read(&telemetry->state))
736		adf_tl_halt(accel_dev);
737}
~/ Read-only file preview.