brintos

brintos / linux-shallow public Read only

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