300 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* Copyright(c) 2023 Intel Corporation */3 4#include <linux/bitfield.h>5#include <linux/debugfs.h>6#include <linux/kernel.h>7 8#include "adf_accel_devices.h"9#include "adf_admin.h"10#include "adf_common_drv.h"11#include "adf_cnv_dbgfs.h"12#include "qat_compression.h"13 14#define CNV_DEBUGFS_FILENAME "cnv_errors"15#define CNV_MIN_PADDING 1616 17#define CNV_ERR_INFO_MASK GENMASK(11, 0)18#define CNV_ERR_TYPE_MASK GENMASK(15, 12)19#define CNV_SLICE_ERR_SIGN_BIT_INDEX 720#define CNV_DELTA_ERR_SIGN_BIT_INDEX 1121 22enum cnv_error_type {23 CNV_ERR_TYPE_NONE,24 CNV_ERR_TYPE_CHECKSUM,25 CNV_ERR_TYPE_DECOMP_PRODUCED_LENGTH,26 CNV_ERR_TYPE_DECOMPRESSION,27 CNV_ERR_TYPE_TRANSLATION,28 CNV_ERR_TYPE_DECOMP_CONSUMED_LENGTH,29 CNV_ERR_TYPE_UNKNOWN,30 CNV_ERR_TYPES_COUNT31};32 33#define CNV_ERROR_TYPE_GET(latest_err) \34 min_t(u16, u16_get_bits(latest_err, CNV_ERR_TYPE_MASK), CNV_ERR_TYPE_UNKNOWN)35 36#define CNV_GET_DELTA_ERR_INFO(latest_error) \37 sign_extend32(latest_error, CNV_DELTA_ERR_SIGN_BIT_INDEX)38 39#define CNV_GET_SLICE_ERR_INFO(latest_error) \40 sign_extend32(latest_error, CNV_SLICE_ERR_SIGN_BIT_INDEX)41 42#define CNV_GET_DEFAULT_ERR_INFO(latest_error) \43 u16_get_bits(latest_error, CNV_ERR_INFO_MASK)44 45enum cnv_fields {46 CNV_ERR_COUNT,47 CNV_LATEST_ERR,48 CNV_FIELDS_COUNT49};50 51static const char * const cnv_field_names[CNV_FIELDS_COUNT] = {52 [CNV_ERR_COUNT] = "Total Errors",53 [CNV_LATEST_ERR] = "Last Error",54};55 56static const char * const cnv_error_names[CNV_ERR_TYPES_COUNT] = {57 [CNV_ERR_TYPE_NONE] = "No Error",58 [CNV_ERR_TYPE_CHECKSUM] = "Checksum Error",59 [CNV_ERR_TYPE_DECOMP_PRODUCED_LENGTH] = "Length Error-P",60 [CNV_ERR_TYPE_DECOMPRESSION] = "Decomp Error",61 [CNV_ERR_TYPE_TRANSLATION] = "Xlat Error",62 [CNV_ERR_TYPE_DECOMP_CONSUMED_LENGTH] = "Length Error-C",63 [CNV_ERR_TYPE_UNKNOWN] = "Unknown Error",64};65 66struct ae_cnv_errors {67 u16 ae;68 u16 err_cnt;69 u16 latest_err;70 bool is_comp_ae;71};72 73struct cnv_err_stats {74 u16 ae_count;75 struct ae_cnv_errors ae_cnv_errors[];76};77 78static s16 get_err_info(u8 error_type, u16 latest)79{80 switch (error_type) {81 case CNV_ERR_TYPE_DECOMP_PRODUCED_LENGTH:82 case CNV_ERR_TYPE_DECOMP_CONSUMED_LENGTH:83 return CNV_GET_DELTA_ERR_INFO(latest);84 case CNV_ERR_TYPE_DECOMPRESSION:85 case CNV_ERR_TYPE_TRANSLATION:86 return CNV_GET_SLICE_ERR_INFO(latest);87 default:88 return CNV_GET_DEFAULT_ERR_INFO(latest);89 }90}91 92static void *qat_cnv_errors_seq_start(struct seq_file *sfile, loff_t *pos)93{94 struct cnv_err_stats *err_stats = sfile->private;95 96 if (*pos == 0)97 return SEQ_START_TOKEN;98 99 if (*pos > err_stats->ae_count)100 return NULL;101 102 return &err_stats->ae_cnv_errors[*pos - 1];103}104 105static void *qat_cnv_errors_seq_next(struct seq_file *sfile, void *v,106 loff_t *pos)107{108 struct cnv_err_stats *err_stats = sfile->private;109 110 (*pos)++;111 112 if (*pos > err_stats->ae_count)113 return NULL;114 115 return &err_stats->ae_cnv_errors[*pos - 1];116}117 118static void qat_cnv_errors_seq_stop(struct seq_file *sfile, void *v)119{120}121 122static int qat_cnv_errors_seq_show(struct seq_file *sfile, void *v)123{124 struct ae_cnv_errors *ae_errors;125 unsigned int i;126 s16 err_info;127 u8 err_type;128 129 if (v == SEQ_START_TOKEN) {130 seq_puts(sfile, "AE ");131 for (i = 0; i < CNV_FIELDS_COUNT; ++i)132 seq_printf(sfile, " %*s", CNV_MIN_PADDING,133 cnv_field_names[i]);134 } else {135 ae_errors = v;136 137 if (!ae_errors->is_comp_ae)138 return 0;139 140 err_type = CNV_ERROR_TYPE_GET(ae_errors->latest_err);141 err_info = get_err_info(err_type, ae_errors->latest_err);142 143 seq_printf(sfile, "%d:", ae_errors->ae);144 seq_printf(sfile, " %*d", CNV_MIN_PADDING, ae_errors->err_cnt);145 seq_printf(sfile, "%*s [%d]", CNV_MIN_PADDING,146 cnv_error_names[err_type], err_info);147 }148 seq_putc(sfile, '\n');149 150 return 0;151}152 153static const struct seq_operations qat_cnv_errors_sops = {154 .start = qat_cnv_errors_seq_start,155 .next = qat_cnv_errors_seq_next,156 .stop = qat_cnv_errors_seq_stop,157 .show = qat_cnv_errors_seq_show,158};159 160/**161 * cnv_err_stats_alloc() - Get CNV stats for the provided device.162 * @accel_dev: Pointer to a QAT acceleration device163 *164 * Allocates and populates table of CNV errors statistics for each non-admin AE165 * available through the supplied acceleration device. The caller becomes the166 * owner of such memory and is responsible for the deallocation through a call167 * to kfree().168 *169 * Returns: a pointer to a dynamically allocated struct cnv_err_stats on success170 * or a negative value on error.171 */172static struct cnv_err_stats *cnv_err_stats_alloc(struct adf_accel_dev *accel_dev)173{174 struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);175 struct cnv_err_stats *err_stats;176 unsigned long ae_count;177 unsigned long ae_mask;178 size_t err_stats_size;179 unsigned long ae;180 unsigned int i;181 u16 latest_err;182 u16 err_cnt;183 int ret;184 185 if (!adf_dev_started(accel_dev)) {186 dev_err(&GET_DEV(accel_dev), "QAT Device not started\n");187 return ERR_PTR(-EBUSY);188 }189 190 /* Ignore the admin AEs */191 ae_mask = hw_data->ae_mask & ~hw_data->admin_ae_mask;192 ae_count = hweight_long(ae_mask);193 if (unlikely(!ae_count))194 return ERR_PTR(-EINVAL);195 196 err_stats_size = struct_size(err_stats, ae_cnv_errors, ae_count);197 err_stats = kmalloc(err_stats_size, GFP_KERNEL);198 if (!err_stats)199 return ERR_PTR(-ENOMEM);200 201 err_stats->ae_count = ae_count;202 203 i = 0;204 for_each_set_bit(ae, &ae_mask, GET_MAX_ACCELENGINES(accel_dev)) {205 ret = adf_get_cnv_stats(accel_dev, ae, &err_cnt, &latest_err);206 if (ret) {207 dev_dbg(&GET_DEV(accel_dev),208 "Failed to get CNV stats for ae %ld, [%d].\n",209 ae, ret);210 err_stats->ae_cnv_errors[i++].is_comp_ae = false;211 continue;212 }213 err_stats->ae_cnv_errors[i].is_comp_ae = true;214 err_stats->ae_cnv_errors[i].latest_err = latest_err;215 err_stats->ae_cnv_errors[i].err_cnt = err_cnt;216 err_stats->ae_cnv_errors[i].ae = ae;217 i++;218 }219 220 return err_stats;221}222 223static int qat_cnv_errors_file_open(struct inode *inode, struct file *file)224{225 struct adf_accel_dev *accel_dev = inode->i_private;226 struct seq_file *cnv_errors_seq_file;227 struct cnv_err_stats *cnv_err_stats;228 int ret;229 230 cnv_err_stats = cnv_err_stats_alloc(accel_dev);231 if (IS_ERR(cnv_err_stats))232 return PTR_ERR(cnv_err_stats);233 234 ret = seq_open(file, &qat_cnv_errors_sops);235 if (unlikely(ret)) {236 kfree(cnv_err_stats);237 return ret;238 }239 240 cnv_errors_seq_file = file->private_data;241 cnv_errors_seq_file->private = cnv_err_stats;242 return ret;243}244 245static int qat_cnv_errors_file_release(struct inode *inode, struct file *file)246{247 struct seq_file *cnv_errors_seq_file = file->private_data;248 249 kfree(cnv_errors_seq_file->private);250 cnv_errors_seq_file->private = NULL;251 252 return seq_release(inode, file);253}254 255static const struct file_operations qat_cnv_fops = {256 .owner = THIS_MODULE,257 .open = qat_cnv_errors_file_open,258 .read = seq_read,259 .llseek = seq_lseek,260 .release = qat_cnv_errors_file_release,261};262 263static ssize_t no_comp_file_read(struct file *f, char __user *buf, size_t count,264 loff_t *pos)265{266 char *file_msg = "No engine configured for comp\n";267 268 return simple_read_from_buffer(buf, count, pos, file_msg,269 strlen(file_msg));270}271 272static const struct file_operations qat_cnv_no_comp_fops = {273 .owner = THIS_MODULE,274 .read = no_comp_file_read,275};276 277void adf_cnv_dbgfs_add(struct adf_accel_dev *accel_dev)278{279 const struct file_operations *fops;280 void *data;281 282 if (adf_hw_dev_has_compression(accel_dev)) {283 fops = &qat_cnv_fops;284 data = accel_dev;285 } else {286 fops = &qat_cnv_no_comp_fops;287 data = NULL;288 }289 290 accel_dev->cnv_dbgfile = debugfs_create_file(CNV_DEBUGFS_FILENAME, 0400,291 accel_dev->debugfs_dir,292 data, fops);293}294 295void adf_cnv_dbgfs_rm(struct adf_accel_dev *accel_dev)296{297 debugfs_remove(accel_dev->cnv_dbgfile);298 accel_dev->cnv_dbgfile = NULL;299}300