1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /* Copyright(c) 2007-2022 Intel Corporation */
3 #include <sys/types.h>
4 #include <sys/sysctl.h>
5 #include <sys/systm.h>
6 #include "adf_cnvnr_freq_counters.h"
7 #include "adf_common_drv.h"
8 #include "adf_cfg.h"
9 #include "icp_qat_fw_init_admin.h"
10 
11 #define ADF_CNVNR_ERR_MASK 0xFFF
12 
13 #define LINE                                                                   \
14 	"+-----------------------------------------------------------------+\n"
15 #define BANNER                                                                 \
16 	"|             CNV Error Freq Statistics for Qat Device            |\n"
17 #define NEW_LINE "\n"
18 #define REPORT_ENTRY_FORMAT                                                    \
19 	"|[AE %2d]: TotalErrors: %5d : LastError: %s [%5d]  |\n"
20 #define MAX_LINE_LENGTH 128
21 #define MAX_REPORT_SIZE ((ADF_MAX_ACCELENGINES + 3) * MAX_LINE_LENGTH)
22 
23 #define PRINT_LINE(line)                                                       \
24 	(snprintf(                                                             \
25 	    report_ptr, MAX_REPORT_SIZE - (report_ptr - report), "%s", line))
26 
27 const char  *cnvnr_err_str[] = {"No Error      ",
28 				"Checksum Error",
29 				"Length Error-P",
30 				"Decomp Error  ",
31 				"Xlat Error    ",
32 				"Length Error-C",
33 				"Unknown Error "};
34 
35 /* Handler for HB status check */
36 static int qat_cnvnr_ctrs_dbg_read(SYSCTL_HANDLER_ARGS)
37 {
38 	struct adf_accel_dev *accel_dev = arg1;
39 	struct adf_hw_device_data *hw_device;
40 	struct icp_qat_fw_init_admin_req request;
41 	struct icp_qat_fw_init_admin_resp response;
42 	unsigned long dc_ae_msk = 0;
43 	u8 num_aes = 0, ae = 0, error_type = 0, bytes_written = 0;
44 	s16 latest_error = 0;
45 	char report[MAX_REPORT_SIZE];
46 	char *report_ptr = report;
47 
48 	/* Defensive check */
49 	if (!accel_dev || accel_dev->accel_id > ADF_MAX_DEVICES)
50 		return EINVAL;
51 
52 	if (!adf_dev_started(accel_dev)) {
53 		device_printf(GET_DEV(accel_dev), "QAT Device not started\n");
54 		return EINVAL;
55 	}
56 
57 	hw_device = accel_dev->hw_device;
58 	if (!hw_device) {
59 		device_printf(GET_DEV(accel_dev), "Failed to get hw_device.\n");
60 		return EFAULT;
61 	}
62 
63 	/* Clean report memory */
64 	explicit_bzero(report, sizeof(report));
65 
66 	/* Adding banner to report */
67 	bytes_written = PRINT_LINE(NEW_LINE);
68 	if (bytes_written <= 0)
69 		return EINVAL;
70 	report_ptr += bytes_written;
71 
72 	bytes_written = PRINT_LINE(LINE);
73 	if (bytes_written <= 0)
74 		return EINVAL;
75 	report_ptr += bytes_written;
76 
77 	bytes_written = PRINT_LINE(BANNER);
78 	if (bytes_written <= 0)
79 		return EINVAL;
80 	report_ptr += bytes_written;
81 
82 	bytes_written = PRINT_LINE(LINE);
83 	if (bytes_written <= 0)
84 		return EINVAL;
85 	report_ptr += bytes_written;
86 
87 	if (accel_dev->au_info)
88 		dc_ae_msk = accel_dev->au_info->dc_ae_msk;
89 
90 	/* Extracting number of Acceleration Engines */
91 	num_aes = hw_device->get_num_aes(hw_device);
92 	for (ae = 0; ae < num_aes; ae++) {
93 		if (accel_dev->au_info && !test_bit(ae, &dc_ae_msk))
94 			continue;
95 		explicit_bzero(&response,
96 			       sizeof(struct icp_qat_fw_init_admin_resp));
97 		request.cmd_id = ICP_QAT_FW_CNV_STATS_GET;
98 		if (adf_put_admin_msg_sync(
99 			accel_dev, ae, &request, &response) ||
100 		    response.status) {
101 			return EFAULT;
102 		}
103 		error_type = CNV_ERROR_TYPE_GET(response.latest_error);
104 		if (error_type == CNV_ERR_TYPE_DECOMP_PRODUCED_LENGTH_ERROR ||
105 		    error_type == CNV_ERR_TYPE_DECOMP_CONSUMED_LENGTH_ERROR) {
106 			latest_error =
107 			    CNV_ERROR_LENGTH_DELTA_GET(response.latest_error);
108 		} else if (error_type == CNV_ERR_TYPE_DECOMPRESSION_ERROR ||
109 			   error_type == CNV_ERR_TYPE_TRANSLATION_ERROR) {
110 			latest_error =
111 			    CNV_ERROR_DECOMP_STATUS_GET(response.latest_error);
112 		} else {
113 			latest_error =
114 			    response.latest_error & ADF_CNVNR_ERR_MASK;
115 		}
116 
117 		bytes_written =
118 		    snprintf(report_ptr,
119 			     MAX_REPORT_SIZE - (report_ptr - report),
120 			     REPORT_ENTRY_FORMAT,
121 			     ae,
122 			     response.error_count,
123 			     cnvnr_err_str[error_type],
124 			     latest_error);
125 		if (bytes_written <= 0) {
126 			printf("ERROR: No space left in CnV ctrs line buffer\n"
127 			       "\tAcceleration ID: %d, Engine: %d\n",
128 			       accel_dev->accel_id,
129 			       ae);
130 			break;
131 		}
132 		report_ptr += bytes_written;
133 	}
134 
135 	sysctl_handle_string(oidp, report, sizeof(report), req);
136 	return 0;
137 }
138 
139 int
140 adf_cnvnr_freq_counters_add(struct adf_accel_dev *accel_dev)
141 {
142 	struct sysctl_ctx_list *qat_sysctl_ctx;
143 	struct sysctl_oid *qat_cnvnr_ctrs_sysctl_tree;
144 	struct sysctl_oid *oid_rc;
145 
146 	/* Defensive checks */
147 	if (!accel_dev)
148 		return EINVAL;
149 
150 	/* Creating context and tree */
151 	qat_sysctl_ctx =
152 	    device_get_sysctl_ctx(accel_dev->accel_pci_dev.pci_dev);
153 	qat_cnvnr_ctrs_sysctl_tree =
154 	    device_get_sysctl_tree(accel_dev->accel_pci_dev.pci_dev);
155 
156 	/* Create "cnv_error" string type leaf - with callback */
157 	oid_rc = SYSCTL_ADD_PROC(qat_sysctl_ctx,
158 				 SYSCTL_CHILDREN(qat_cnvnr_ctrs_sysctl_tree),
159 				 OID_AUTO,
160 				 "cnv_error",
161 				 CTLTYPE_STRING | CTLFLAG_RD,
162 				 accel_dev,
163 				 0,
164 				 qat_cnvnr_ctrs_dbg_read,
165 				 "IU",
166 				 "QAT CnVnR status");
167 
168 	if (!oid_rc) {
169 		printf("ERROR: Memory allocation failed\n");
170 		return ENOMEM;
171 	}
172 	return 0;
173 }
174 
175 void
176 adf_cnvnr_freq_counters_remove(struct adf_accel_dev *accel_dev)
177 {
178 }
179