1*865b50feSLucas Segarra Fernandez // SPDX-License-Identifier: GPL-2.0-only
2*865b50feSLucas Segarra Fernandez /* Copyright(c) 2023 Intel Corporation */
3*865b50feSLucas Segarra Fernandez #include <linux/bitops.h>
4*865b50feSLucas Segarra Fernandez #include <linux/debugfs.h>
5*865b50feSLucas Segarra Fernandez #include <linux/err.h>
6*865b50feSLucas Segarra Fernandez #include <linux/fs.h>
7*865b50feSLucas Segarra Fernandez #include <linux/kernel.h>
8*865b50feSLucas Segarra Fernandez #include <linux/seq_file.h>
9*865b50feSLucas Segarra Fernandez #include <linux/types.h>
10*865b50feSLucas Segarra Fernandez
11*865b50feSLucas Segarra Fernandez #include "adf_accel_devices.h"
12*865b50feSLucas Segarra Fernandez #include "adf_common_drv.h"
13*865b50feSLucas Segarra Fernandez #include "adf_fw_counters.h"
14*865b50feSLucas Segarra Fernandez
15*865b50feSLucas Segarra Fernandez #define ADF_FW_COUNTERS_MAX_PADDING 16
16*865b50feSLucas Segarra Fernandez
17*865b50feSLucas Segarra Fernandez enum adf_fw_counters_types {
18*865b50feSLucas Segarra Fernandez ADF_FW_REQUESTS,
19*865b50feSLucas Segarra Fernandez ADF_FW_RESPONSES,
20*865b50feSLucas Segarra Fernandez ADF_FW_COUNTERS_COUNT
21*865b50feSLucas Segarra Fernandez };
22*865b50feSLucas Segarra Fernandez
23*865b50feSLucas Segarra Fernandez static const char * const adf_fw_counter_names[] = {
24*865b50feSLucas Segarra Fernandez [ADF_FW_REQUESTS] = "Requests",
25*865b50feSLucas Segarra Fernandez [ADF_FW_RESPONSES] = "Responses",
26*865b50feSLucas Segarra Fernandez };
27*865b50feSLucas Segarra Fernandez
28*865b50feSLucas Segarra Fernandez static_assert(ARRAY_SIZE(adf_fw_counter_names) == ADF_FW_COUNTERS_COUNT);
29*865b50feSLucas Segarra Fernandez
30*865b50feSLucas Segarra Fernandez struct adf_ae_counters {
31*865b50feSLucas Segarra Fernandez u16 ae;
32*865b50feSLucas Segarra Fernandez u64 values[ADF_FW_COUNTERS_COUNT];
33*865b50feSLucas Segarra Fernandez };
34*865b50feSLucas Segarra Fernandez
35*865b50feSLucas Segarra Fernandez struct adf_fw_counters {
36*865b50feSLucas Segarra Fernandez u16 ae_count;
37*865b50feSLucas Segarra Fernandez struct adf_ae_counters ae_counters[];
38*865b50feSLucas Segarra Fernandez };
39*865b50feSLucas Segarra Fernandez
adf_fw_counters_parse_ae_values(struct adf_ae_counters * ae_counters,u32 ae,u64 req_count,u64 resp_count)40*865b50feSLucas Segarra Fernandez static void adf_fw_counters_parse_ae_values(struct adf_ae_counters *ae_counters, u32 ae,
41*865b50feSLucas Segarra Fernandez u64 req_count, u64 resp_count)
42*865b50feSLucas Segarra Fernandez {
43*865b50feSLucas Segarra Fernandez ae_counters->ae = ae;
44*865b50feSLucas Segarra Fernandez ae_counters->values[ADF_FW_REQUESTS] = req_count;
45*865b50feSLucas Segarra Fernandez ae_counters->values[ADF_FW_RESPONSES] = resp_count;
46*865b50feSLucas Segarra Fernandez }
47*865b50feSLucas Segarra Fernandez
adf_fw_counters_load_from_device(struct adf_accel_dev * accel_dev,struct adf_fw_counters * fw_counters)48*865b50feSLucas Segarra Fernandez static int adf_fw_counters_load_from_device(struct adf_accel_dev *accel_dev,
49*865b50feSLucas Segarra Fernandez struct adf_fw_counters *fw_counters)
50*865b50feSLucas Segarra Fernandez {
51*865b50feSLucas Segarra Fernandez struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
52*865b50feSLucas Segarra Fernandez unsigned long ae_mask;
53*865b50feSLucas Segarra Fernandez unsigned int i;
54*865b50feSLucas Segarra Fernandez unsigned long ae;
55*865b50feSLucas Segarra Fernandez
56*865b50feSLucas Segarra Fernandez /* Ignore the admin AEs */
57*865b50feSLucas Segarra Fernandez ae_mask = hw_data->ae_mask & ~hw_data->admin_ae_mask;
58*865b50feSLucas Segarra Fernandez
59*865b50feSLucas Segarra Fernandez if (hweight_long(ae_mask) > fw_counters->ae_count)
60*865b50feSLucas Segarra Fernandez return -EINVAL;
61*865b50feSLucas Segarra Fernandez
62*865b50feSLucas Segarra Fernandez i = 0;
63*865b50feSLucas Segarra Fernandez for_each_set_bit(ae, &ae_mask, GET_MAX_ACCELENGINES(accel_dev)) {
64*865b50feSLucas Segarra Fernandez u64 req_count, resp_count;
65*865b50feSLucas Segarra Fernandez int ret;
66*865b50feSLucas Segarra Fernandez
67*865b50feSLucas Segarra Fernandez ret = adf_get_ae_fw_counters(accel_dev, ae, &req_count, &resp_count);
68*865b50feSLucas Segarra Fernandez if (ret)
69*865b50feSLucas Segarra Fernandez return ret;
70*865b50feSLucas Segarra Fernandez
71*865b50feSLucas Segarra Fernandez adf_fw_counters_parse_ae_values(&fw_counters->ae_counters[i++], ae,
72*865b50feSLucas Segarra Fernandez req_count, resp_count);
73*865b50feSLucas Segarra Fernandez }
74*865b50feSLucas Segarra Fernandez
75*865b50feSLucas Segarra Fernandez return 0;
76*865b50feSLucas Segarra Fernandez }
77*865b50feSLucas Segarra Fernandez
adf_fw_counters_allocate(unsigned long ae_count)78*865b50feSLucas Segarra Fernandez static struct adf_fw_counters *adf_fw_counters_allocate(unsigned long ae_count)
79*865b50feSLucas Segarra Fernandez {
80*865b50feSLucas Segarra Fernandez struct adf_fw_counters *fw_counters;
81*865b50feSLucas Segarra Fernandez
82*865b50feSLucas Segarra Fernandez if (unlikely(!ae_count))
83*865b50feSLucas Segarra Fernandez return ERR_PTR(-EINVAL);
84*865b50feSLucas Segarra Fernandez
85*865b50feSLucas Segarra Fernandez fw_counters = kmalloc(struct_size(fw_counters, ae_counters, ae_count), GFP_KERNEL);
86*865b50feSLucas Segarra Fernandez if (!fw_counters)
87*865b50feSLucas Segarra Fernandez return ERR_PTR(-ENOMEM);
88*865b50feSLucas Segarra Fernandez
89*865b50feSLucas Segarra Fernandez fw_counters->ae_count = ae_count;
90*865b50feSLucas Segarra Fernandez
91*865b50feSLucas Segarra Fernandez return fw_counters;
92*865b50feSLucas Segarra Fernandez }
93*865b50feSLucas Segarra Fernandez
94*865b50feSLucas Segarra Fernandez /**
95*865b50feSLucas Segarra Fernandez * adf_fw_counters_get() - Return FW counters for the provided device.
96*865b50feSLucas Segarra Fernandez * @accel_dev: Pointer to a QAT acceleration device
97*865b50feSLucas Segarra Fernandez *
98*865b50feSLucas Segarra Fernandez * Allocates and returns a table of counters containing execution statistics
99*865b50feSLucas Segarra Fernandez * for each non-admin AE available through the supplied acceleration device.
100*865b50feSLucas Segarra Fernandez * The caller becomes the owner of such memory and is responsible for
101*865b50feSLucas Segarra Fernandez * the deallocation through a call to kfree().
102*865b50feSLucas Segarra Fernandez *
103*865b50feSLucas Segarra Fernandez * Returns: a pointer to a dynamically allocated struct adf_fw_counters
104*865b50feSLucas Segarra Fernandez * on success, or a negative value on error.
105*865b50feSLucas Segarra Fernandez */
adf_fw_counters_get(struct adf_accel_dev * accel_dev)106*865b50feSLucas Segarra Fernandez static struct adf_fw_counters *adf_fw_counters_get(struct adf_accel_dev *accel_dev)
107*865b50feSLucas Segarra Fernandez {
108*865b50feSLucas Segarra Fernandez struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
109*865b50feSLucas Segarra Fernandez struct adf_fw_counters *fw_counters;
110*865b50feSLucas Segarra Fernandez unsigned long ae_count;
111*865b50feSLucas Segarra Fernandez int ret;
112*865b50feSLucas Segarra Fernandez
113*865b50feSLucas Segarra Fernandez if (!adf_dev_started(accel_dev)) {
114*865b50feSLucas Segarra Fernandez dev_err(&GET_DEV(accel_dev), "QAT Device not started\n");
115*865b50feSLucas Segarra Fernandez return ERR_PTR(-EFAULT);
116*865b50feSLucas Segarra Fernandez }
117*865b50feSLucas Segarra Fernandez
118*865b50feSLucas Segarra Fernandez /* Ignore the admin AEs */
119*865b50feSLucas Segarra Fernandez ae_count = hweight_long(hw_data->ae_mask & ~hw_data->admin_ae_mask);
120*865b50feSLucas Segarra Fernandez
121*865b50feSLucas Segarra Fernandez fw_counters = adf_fw_counters_allocate(ae_count);
122*865b50feSLucas Segarra Fernandez if (IS_ERR(fw_counters))
123*865b50feSLucas Segarra Fernandez return fw_counters;
124*865b50feSLucas Segarra Fernandez
125*865b50feSLucas Segarra Fernandez ret = adf_fw_counters_load_from_device(accel_dev, fw_counters);
126*865b50feSLucas Segarra Fernandez if (ret) {
127*865b50feSLucas Segarra Fernandez kfree(fw_counters);
128*865b50feSLucas Segarra Fernandez dev_err(&GET_DEV(accel_dev),
129*865b50feSLucas Segarra Fernandez "Failed to create QAT fw_counters file table [%d].\n", ret);
130*865b50feSLucas Segarra Fernandez return ERR_PTR(ret);
131*865b50feSLucas Segarra Fernandez }
132*865b50feSLucas Segarra Fernandez
133*865b50feSLucas Segarra Fernandez return fw_counters;
134*865b50feSLucas Segarra Fernandez }
135*865b50feSLucas Segarra Fernandez
qat_fw_counters_seq_start(struct seq_file * sfile,loff_t * pos)136*865b50feSLucas Segarra Fernandez static void *qat_fw_counters_seq_start(struct seq_file *sfile, loff_t *pos)
137*865b50feSLucas Segarra Fernandez {
138*865b50feSLucas Segarra Fernandez struct adf_fw_counters *fw_counters = sfile->private;
139*865b50feSLucas Segarra Fernandez
140*865b50feSLucas Segarra Fernandez if (*pos == 0)
141*865b50feSLucas Segarra Fernandez return SEQ_START_TOKEN;
142*865b50feSLucas Segarra Fernandez
143*865b50feSLucas Segarra Fernandez if (*pos > fw_counters->ae_count)
144*865b50feSLucas Segarra Fernandez return NULL;
145*865b50feSLucas Segarra Fernandez
146*865b50feSLucas Segarra Fernandez return &fw_counters->ae_counters[*pos - 1];
147*865b50feSLucas Segarra Fernandez }
148*865b50feSLucas Segarra Fernandez
qat_fw_counters_seq_next(struct seq_file * sfile,void * v,loff_t * pos)149*865b50feSLucas Segarra Fernandez static void *qat_fw_counters_seq_next(struct seq_file *sfile, void *v, loff_t *pos)
150*865b50feSLucas Segarra Fernandez {
151*865b50feSLucas Segarra Fernandez struct adf_fw_counters *fw_counters = sfile->private;
152*865b50feSLucas Segarra Fernandez
153*865b50feSLucas Segarra Fernandez (*pos)++;
154*865b50feSLucas Segarra Fernandez
155*865b50feSLucas Segarra Fernandez if (*pos > fw_counters->ae_count)
156*865b50feSLucas Segarra Fernandez return NULL;
157*865b50feSLucas Segarra Fernandez
158*865b50feSLucas Segarra Fernandez return &fw_counters->ae_counters[*pos - 1];
159*865b50feSLucas Segarra Fernandez }
160*865b50feSLucas Segarra Fernandez
qat_fw_counters_seq_stop(struct seq_file * sfile,void * v)161*865b50feSLucas Segarra Fernandez static void qat_fw_counters_seq_stop(struct seq_file *sfile, void *v) {}
162*865b50feSLucas Segarra Fernandez
qat_fw_counters_seq_show(struct seq_file * sfile,void * v)163*865b50feSLucas Segarra Fernandez static int qat_fw_counters_seq_show(struct seq_file *sfile, void *v)
164*865b50feSLucas Segarra Fernandez {
165*865b50feSLucas Segarra Fernandez int i;
166*865b50feSLucas Segarra Fernandez
167*865b50feSLucas Segarra Fernandez if (v == SEQ_START_TOKEN) {
168*865b50feSLucas Segarra Fernandez seq_puts(sfile, "AE ");
169*865b50feSLucas Segarra Fernandez for (i = 0; i < ADF_FW_COUNTERS_COUNT; ++i)
170*865b50feSLucas Segarra Fernandez seq_printf(sfile, " %*s", ADF_FW_COUNTERS_MAX_PADDING,
171*865b50feSLucas Segarra Fernandez adf_fw_counter_names[i]);
172*865b50feSLucas Segarra Fernandez } else {
173*865b50feSLucas Segarra Fernandez struct adf_ae_counters *ae_counters = (struct adf_ae_counters *)v;
174*865b50feSLucas Segarra Fernandez
175*865b50feSLucas Segarra Fernandez seq_printf(sfile, "%2d:", ae_counters->ae);
176*865b50feSLucas Segarra Fernandez for (i = 0; i < ADF_FW_COUNTERS_COUNT; ++i)
177*865b50feSLucas Segarra Fernandez seq_printf(sfile, " %*llu", ADF_FW_COUNTERS_MAX_PADDING,
178*865b50feSLucas Segarra Fernandez ae_counters->values[i]);
179*865b50feSLucas Segarra Fernandez }
180*865b50feSLucas Segarra Fernandez seq_putc(sfile, '\n');
181*865b50feSLucas Segarra Fernandez
182*865b50feSLucas Segarra Fernandez return 0;
183*865b50feSLucas Segarra Fernandez }
184*865b50feSLucas Segarra Fernandez
185*865b50feSLucas Segarra Fernandez static const struct seq_operations qat_fw_counters_sops = {
186*865b50feSLucas Segarra Fernandez .start = qat_fw_counters_seq_start,
187*865b50feSLucas Segarra Fernandez .next = qat_fw_counters_seq_next,
188*865b50feSLucas Segarra Fernandez .stop = qat_fw_counters_seq_stop,
189*865b50feSLucas Segarra Fernandez .show = qat_fw_counters_seq_show,
190*865b50feSLucas Segarra Fernandez };
191*865b50feSLucas Segarra Fernandez
qat_fw_counters_file_open(struct inode * inode,struct file * file)192*865b50feSLucas Segarra Fernandez static int qat_fw_counters_file_open(struct inode *inode, struct file *file)
193*865b50feSLucas Segarra Fernandez {
194*865b50feSLucas Segarra Fernandez struct adf_accel_dev *accel_dev = inode->i_private;
195*865b50feSLucas Segarra Fernandez struct seq_file *fw_counters_seq_file;
196*865b50feSLucas Segarra Fernandez struct adf_fw_counters *fw_counters;
197*865b50feSLucas Segarra Fernandez int ret;
198*865b50feSLucas Segarra Fernandez
199*865b50feSLucas Segarra Fernandez fw_counters = adf_fw_counters_get(accel_dev);
200*865b50feSLucas Segarra Fernandez if (IS_ERR(fw_counters))
201*865b50feSLucas Segarra Fernandez return PTR_ERR(fw_counters);
202*865b50feSLucas Segarra Fernandez
203*865b50feSLucas Segarra Fernandez ret = seq_open(file, &qat_fw_counters_sops);
204*865b50feSLucas Segarra Fernandez if (unlikely(ret)) {
205*865b50feSLucas Segarra Fernandez kfree(fw_counters);
206*865b50feSLucas Segarra Fernandez return ret;
207*865b50feSLucas Segarra Fernandez }
208*865b50feSLucas Segarra Fernandez
209*865b50feSLucas Segarra Fernandez fw_counters_seq_file = file->private_data;
210*865b50feSLucas Segarra Fernandez fw_counters_seq_file->private = fw_counters;
211*865b50feSLucas Segarra Fernandez return ret;
212*865b50feSLucas Segarra Fernandez }
213*865b50feSLucas Segarra Fernandez
qat_fw_counters_file_release(struct inode * inode,struct file * file)214*865b50feSLucas Segarra Fernandez static int qat_fw_counters_file_release(struct inode *inode, struct file *file)
215*865b50feSLucas Segarra Fernandez {
216*865b50feSLucas Segarra Fernandez struct seq_file *seq = file->private_data;
217*865b50feSLucas Segarra Fernandez
218*865b50feSLucas Segarra Fernandez kfree(seq->private);
219*865b50feSLucas Segarra Fernandez seq->private = NULL;
220*865b50feSLucas Segarra Fernandez
221*865b50feSLucas Segarra Fernandez return seq_release(inode, file); }
222*865b50feSLucas Segarra Fernandez
223*865b50feSLucas Segarra Fernandez static const struct file_operations qat_fw_counters_fops = {
224*865b50feSLucas Segarra Fernandez .owner = THIS_MODULE,
225*865b50feSLucas Segarra Fernandez .open = qat_fw_counters_file_open,
226*865b50feSLucas Segarra Fernandez .read = seq_read,
227*865b50feSLucas Segarra Fernandez .llseek = seq_lseek,
228*865b50feSLucas Segarra Fernandez .release = qat_fw_counters_file_release,
229*865b50feSLucas Segarra Fernandez };
230*865b50feSLucas Segarra Fernandez
231*865b50feSLucas Segarra Fernandez /**
232*865b50feSLucas Segarra Fernandez * adf_fw_counters_dbgfs_add() - Create a debugfs file containing FW
233*865b50feSLucas Segarra Fernandez * execution counters.
234*865b50feSLucas Segarra Fernandez * @accel_dev: Pointer to a QAT acceleration device
235*865b50feSLucas Segarra Fernandez *
236*865b50feSLucas Segarra Fernandez * Function creates a file to display a table with statistics for the given
237*865b50feSLucas Segarra Fernandez * QAT acceleration device. The table stores device specific execution values
238*865b50feSLucas Segarra Fernandez * for each AE, such as the number of requests sent to the FW and responses
239*865b50feSLucas Segarra Fernandez * received from the FW.
240*865b50feSLucas Segarra Fernandez *
241*865b50feSLucas Segarra Fernandez * Return: void
242*865b50feSLucas Segarra Fernandez */
adf_fw_counters_dbgfs_add(struct adf_accel_dev * accel_dev)243*865b50feSLucas Segarra Fernandez void adf_fw_counters_dbgfs_add(struct adf_accel_dev *accel_dev)
244*865b50feSLucas Segarra Fernandez {
245*865b50feSLucas Segarra Fernandez accel_dev->fw_cntr_dbgfile = debugfs_create_file("fw_counters", 0400,
246*865b50feSLucas Segarra Fernandez accel_dev->debugfs_dir,
247*865b50feSLucas Segarra Fernandez accel_dev,
248*865b50feSLucas Segarra Fernandez &qat_fw_counters_fops);
249*865b50feSLucas Segarra Fernandez }
250*865b50feSLucas Segarra Fernandez
251*865b50feSLucas Segarra Fernandez /**
252*865b50feSLucas Segarra Fernandez * adf_fw_counters_dbgfs_rm() - Remove the debugfs file containing FW counters.
253*865b50feSLucas Segarra Fernandez * @accel_dev: Pointer to a QAT acceleration device.
254*865b50feSLucas Segarra Fernandez *
255*865b50feSLucas Segarra Fernandez * Function removes the file providing the table of statistics for the given
256*865b50feSLucas Segarra Fernandez * QAT acceleration device.
257*865b50feSLucas Segarra Fernandez *
258*865b50feSLucas Segarra Fernandez * Return: void
259*865b50feSLucas Segarra Fernandez */
adf_fw_counters_dbgfs_rm(struct adf_accel_dev * accel_dev)260*865b50feSLucas Segarra Fernandez void adf_fw_counters_dbgfs_rm(struct adf_accel_dev *accel_dev)
261*865b50feSLucas Segarra Fernandez {
262*865b50feSLucas Segarra Fernandez debugfs_remove(accel_dev->fw_cntr_dbgfile);
263*865b50feSLucas Segarra Fernandez accel_dev->fw_cntr_dbgfile = NULL;
264*865b50feSLucas Segarra Fernandez }
265