1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2023 Intel Corporation */
3 #include <linux/bitops.h>
4 #include <linux/debugfs.h>
7 #include <linux/kernel.h>
8 #include <linux/seq_file.h>
9 #include <linux/types.h>
11 #include "adf_accel_devices.h"
12 #include "adf_admin.h"
13 #include "adf_common_drv.h"
14 #include "adf_fw_counters.h"
16 #define ADF_FW_COUNTERS_MAX_PADDING 16
18 enum adf_fw_counters_types {
24 static const char * const adf_fw_counter_names[] = {
25 [ADF_FW_REQUESTS] = "Requests",
26 [ADF_FW_RESPONSES] = "Responses",
29 static_assert(ARRAY_SIZE(adf_fw_counter_names) == ADF_FW_COUNTERS_COUNT);
31 struct adf_ae_counters {
33 u64 values[ADF_FW_COUNTERS_COUNT];
36 struct adf_fw_counters {
38 struct adf_ae_counters ae_counters[] __counted_by(ae_count);
41 static void adf_fw_counters_parse_ae_values(struct adf_ae_counters *ae_counters, u32 ae,
42 u64 req_count, u64 resp_count)
45 ae_counters->values[ADF_FW_REQUESTS] = req_count;
46 ae_counters->values[ADF_FW_RESPONSES] = resp_count;
49 static int adf_fw_counters_load_from_device(struct adf_accel_dev *accel_dev,
50 struct adf_fw_counters *fw_counters)
52 struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
53 unsigned long ae_mask;
57 /* Ignore the admin AEs */
58 ae_mask = hw_data->ae_mask & ~hw_data->admin_ae_mask;
60 if (hweight_long(ae_mask) > fw_counters->ae_count)
64 for_each_set_bit(ae, &ae_mask, GET_MAX_ACCELENGINES(accel_dev)) {
65 u64 req_count, resp_count;
68 ret = adf_get_ae_fw_counters(accel_dev, ae, &req_count, &resp_count);
72 adf_fw_counters_parse_ae_values(&fw_counters->ae_counters[i++], ae,
73 req_count, resp_count);
79 static struct adf_fw_counters *adf_fw_counters_allocate(unsigned long ae_count)
81 struct adf_fw_counters *fw_counters;
83 if (unlikely(!ae_count))
84 return ERR_PTR(-EINVAL);
86 fw_counters = kmalloc(struct_size(fw_counters, ae_counters, ae_count), GFP_KERNEL);
88 return ERR_PTR(-ENOMEM);
90 fw_counters->ae_count = ae_count;
96 * adf_fw_counters_get() - Return FW counters for the provided device.
97 * @accel_dev: Pointer to a QAT acceleration device
99 * Allocates and returns a table of counters containing execution statistics
100 * for each non-admin AE available through the supplied acceleration device.
101 * The caller becomes the owner of such memory and is responsible for
102 * the deallocation through a call to kfree().
104 * Returns: a pointer to a dynamically allocated struct adf_fw_counters
105 * on success, or a negative value on error.
107 static struct adf_fw_counters *adf_fw_counters_get(struct adf_accel_dev *accel_dev)
109 struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);
110 struct adf_fw_counters *fw_counters;
111 unsigned long ae_count;
114 if (!adf_dev_started(accel_dev)) {
115 dev_err(&GET_DEV(accel_dev), "QAT Device not started\n");
116 return ERR_PTR(-EFAULT);
119 /* Ignore the admin AEs */
120 ae_count = hweight_long(hw_data->ae_mask & ~hw_data->admin_ae_mask);
122 fw_counters = adf_fw_counters_allocate(ae_count);
123 if (IS_ERR(fw_counters))
126 ret = adf_fw_counters_load_from_device(accel_dev, fw_counters);
129 dev_err(&GET_DEV(accel_dev),
130 "Failed to create QAT fw_counters file table [%d].\n", ret);
137 static void *qat_fw_counters_seq_start(struct seq_file *sfile, loff_t *pos)
139 struct adf_fw_counters *fw_counters = sfile->private;
142 return SEQ_START_TOKEN;
144 if (*pos > fw_counters->ae_count)
147 return &fw_counters->ae_counters[*pos - 1];
150 static void *qat_fw_counters_seq_next(struct seq_file *sfile, void *v, loff_t *pos)
152 struct adf_fw_counters *fw_counters = sfile->private;
156 if (*pos > fw_counters->ae_count)
159 return &fw_counters->ae_counters[*pos - 1];
162 static void qat_fw_counters_seq_stop(struct seq_file *sfile, void *v) {}
164 static int qat_fw_counters_seq_show(struct seq_file *sfile, void *v)
168 if (v == SEQ_START_TOKEN) {
169 seq_puts(sfile, "AE ");
170 for (i = 0; i < ADF_FW_COUNTERS_COUNT; ++i)
171 seq_printf(sfile, " %*s", ADF_FW_COUNTERS_MAX_PADDING,
172 adf_fw_counter_names[i]);
174 struct adf_ae_counters *ae_counters = (struct adf_ae_counters *)v;
176 seq_printf(sfile, "%2d:", ae_counters->ae);
177 for (i = 0; i < ADF_FW_COUNTERS_COUNT; ++i)
178 seq_printf(sfile, " %*llu", ADF_FW_COUNTERS_MAX_PADDING,
179 ae_counters->values[i]);
181 seq_putc(sfile, '\n');
186 static const struct seq_operations qat_fw_counters_sops = {
187 .start = qat_fw_counters_seq_start,
188 .next = qat_fw_counters_seq_next,
189 .stop = qat_fw_counters_seq_stop,
190 .show = qat_fw_counters_seq_show,
193 static int qat_fw_counters_file_open(struct inode *inode, struct file *file)
195 struct adf_accel_dev *accel_dev = inode->i_private;
196 struct seq_file *fw_counters_seq_file;
197 struct adf_fw_counters *fw_counters;
200 fw_counters = adf_fw_counters_get(accel_dev);
201 if (IS_ERR(fw_counters))
202 return PTR_ERR(fw_counters);
204 ret = seq_open(file, &qat_fw_counters_sops);
210 fw_counters_seq_file = file->private_data;
211 fw_counters_seq_file->private = fw_counters;
215 static int qat_fw_counters_file_release(struct inode *inode, struct file *file)
217 struct seq_file *seq = file->private_data;
222 return seq_release(inode, file); }
224 static const struct file_operations qat_fw_counters_fops = {
225 .owner = THIS_MODULE,
226 .open = qat_fw_counters_file_open,
229 .release = qat_fw_counters_file_release,
233 * adf_fw_counters_dbgfs_add() - Create a debugfs file containing FW
234 * execution counters.
235 * @accel_dev: Pointer to a QAT acceleration device
237 * Function creates a file to display a table with statistics for the given
238 * QAT acceleration device. The table stores device specific execution values
239 * for each AE, such as the number of requests sent to the FW and responses
240 * received from the FW.
244 void adf_fw_counters_dbgfs_add(struct adf_accel_dev *accel_dev)
246 accel_dev->fw_cntr_dbgfile = debugfs_create_file("fw_counters", 0400,
247 accel_dev->debugfs_dir,
249 &qat_fw_counters_fops);
253 * adf_fw_counters_dbgfs_rm() - Remove the debugfs file containing FW counters.
254 * @accel_dev: Pointer to a QAT acceleration device.
256 * Function removes the file providing the table of statistics for the given
257 * QAT acceleration device.
261 void adf_fw_counters_dbgfs_rm(struct adf_accel_dev *accel_dev)
263 debugfs_remove(accel_dev->fw_cntr_dbgfile);
264 accel_dev->fw_cntr_dbgfile = NULL;