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_accel_devices.h"
7 #include "adf_cfg.h"
8 #include "adf_cfg_sysctl.h"
9 #include "adf_cfg_device.h"
10 #include "adf_common_drv.h"
11 #include <sys/mutex.h>
12 #include <sys/sbuf.h>
13 
14 #define ADF_CFG_SYSCTL_BUF_SZ ADF_CFG_MAX_VAL
15 #define ADF_CFG_UP_STR "up"
16 #define ADF_CFG_DOWN_STR "down"
17 
18 #define ADF_CFG_MAX_USER_PROCESSES 64
19 
20 static int
21 adf_cfg_down(struct adf_accel_dev *accel_dev)
22 {
23 	int ret = 0;
24 
25 	if (!adf_dev_started(accel_dev)) {
26 		device_printf(GET_DEV(accel_dev),
27 			      "Device qat_dev%d already down\n",
28 			      accel_dev->accel_id);
29 		return 0;
30 	}
31 
32 	if (adf_dev_in_use(accel_dev)) {
33 		pr_err("QAT: Device %d in use\n", accel_dev->accel_id);
34 		goto out;
35 	}
36 
37 	if (adf_dev_stop(accel_dev)) {
38 		device_printf(GET_DEV(accel_dev),
39 			      "Failed to stop qat_dev%d\n",
40 			      accel_dev->accel_id);
41 		ret = EFAULT;
42 		goto out;
43 	}
44 
45 	adf_dev_shutdown(accel_dev);
46 
47 out:
48 	return ret;
49 }
50 
51 static int
52 adf_cfg_up(struct adf_accel_dev *accel_dev)
53 {
54 	int ret;
55 
56 	if (adf_dev_started(accel_dev))
57 		return 0;
58 
59 	if (NULL == accel_dev->hw_device->config_device)
60 		return ENXIO;
61 
62 	ret = accel_dev->hw_device->config_device(accel_dev);
63 	if (ret) {
64 		device_printf(GET_DEV(accel_dev),
65 			      "Failed to start qat_dev%d\n",
66 			      accel_dev->accel_id);
67 		return ret;
68 	}
69 
70 	ret = adf_dev_init(accel_dev);
71 	if (!ret)
72 		ret = adf_dev_start(accel_dev);
73 
74 	if (ret) {
75 		device_printf(GET_DEV(accel_dev),
76 			      "Failed to start qat_dev%d\n",
77 			      accel_dev->accel_id);
78 		adf_dev_stop(accel_dev);
79 		adf_dev_shutdown(accel_dev);
80 	}
81 
82 	if (!ret) {
83 		struct adf_cfg_device *cfg_dev = NULL;
84 
85 		cfg_dev = accel_dev->cfg->dev;
86 		adf_cfg_device_clear(cfg_dev, accel_dev);
87 		free(cfg_dev, M_QAT);
88 		accel_dev->cfg->dev = NULL;
89 	}
90 
91 	return 0;
92 }
93 
94 static const char *const cfg_serv[] =
95     { "sym;asym", "sym", "asym", "dc", "sym;dc", "asym;dc", "cy", "cy;dc" };
96 
97 static const char *const cfg_mode[] = { "ks;us", "us", "ks" };
98 
99 static int adf_cfg_sysctl_services_handle(SYSCTL_HANDLER_ARGS)
100 {
101 	struct adf_cfg_device_data *dev_cfg_data;
102 	struct adf_accel_dev *accel_dev;
103 	char buf[ADF_CFG_SYSCTL_BUF_SZ];
104 	unsigned int len;
105 	int ret = 0;
106 	int i = 0;
107 
108 	accel_dev = arg1;
109 	if (!accel_dev)
110 		return ENXIO;
111 
112 	dev_cfg_data = accel_dev->cfg;
113 	if (!dev_cfg_data)
114 		return ENXIO;
115 
116 	strlcpy(buf, dev_cfg_data->cfg_services, sizeof(buf));
117 
118 	ret = sysctl_handle_string(oidp, buf, sizeof(buf), req);
119 	if (ret != 0 || req->newptr == NULL)
120 		return ret;
121 
122 	/* Handle config change */
123 	if (adf_dev_started(accel_dev)) {
124 		device_printf(
125 		    GET_DEV(accel_dev),
126 		    "QAT: configuration could be changed in down state only\n");
127 		return EINVAL;
128 	}
129 
130 	len = strlen(buf);
131 
132 	for (i = 0; i < ARRAY_SIZE(cfg_serv); i++) {
133 		if ((len > 0 && strncasecmp(cfg_serv[i], buf, len) == 0)) {
134 			strlcpy(dev_cfg_data->cfg_services,
135 				buf,
136 				ADF_CFG_MAX_VAL);
137 			break;
138 		}
139 	}
140 
141 	if (i == ARRAY_SIZE(cfg_serv)) {
142 		device_printf(GET_DEV(accel_dev),
143 			      "Unknown service configuration\n");
144 		ret = EINVAL;
145 	}
146 
147 	return ret;
148 }
149 
150 static int adf_cfg_sysctl_mode_handle(SYSCTL_HANDLER_ARGS)
151 {
152 	struct adf_cfg_device_data *dev_cfg_data;
153 	struct adf_accel_dev *accel_dev;
154 	char buf[ADF_CFG_SYSCTL_BUF_SZ];
155 	unsigned int len;
156 	int ret = 0;
157 	int i = 0;
158 
159 	accel_dev = arg1;
160 	if (!accel_dev)
161 		return ENXIO;
162 
163 	dev_cfg_data = accel_dev->cfg;
164 	if (!dev_cfg_data)
165 		return ENXIO;
166 
167 	strlcpy(buf, dev_cfg_data->cfg_mode, sizeof(buf));
168 
169 	ret = sysctl_handle_string(oidp, buf, sizeof(buf), req);
170 	if (ret != 0 || req->newptr == NULL)
171 		return ret;
172 
173 	/* Handle config change */
174 	if (adf_dev_started(accel_dev)) {
175 		device_printf(
176 		    GET_DEV(accel_dev),
177 		    "QAT: configuration could be changed in down state only\n");
178 		return EBUSY;
179 	}
180 
181 	len = strlen(buf);
182 
183 	for (i = 0; i < ARRAY_SIZE(cfg_mode); i++) {
184 		if ((len > 0 && strncasecmp(cfg_mode[i], buf, len) == 0)) {
185 			strlcpy(dev_cfg_data->cfg_mode, buf, ADF_CFG_MAX_VAL);
186 			break;
187 		}
188 	}
189 
190 	if (i == ARRAY_SIZE(cfg_mode)) {
191 		device_printf(GET_DEV(accel_dev),
192 			      "Unknown configuration mode\n");
193 		ret = EINVAL;
194 	}
195 
196 	return ret;
197 }
198 
199 static int adf_cfg_sysctl_handle(SYSCTL_HANDLER_ARGS)
200 {
201 	struct adf_cfg_device_data *dev_cfg_data;
202 	struct adf_accel_dev *accel_dev;
203 	char buf[ADF_CFG_SYSCTL_BUF_SZ] = { 0 };
204 	unsigned int len;
205 	int ret = 0;
206 
207 	accel_dev = arg1;
208 	if (!accel_dev)
209 		return ENXIO;
210 
211 	dev_cfg_data = accel_dev->cfg;
212 	if (!dev_cfg_data)
213 		return ENXIO;
214 
215 	if (adf_dev_started(accel_dev)) {
216 		strlcpy(buf, ADF_CFG_UP_STR, sizeof(buf));
217 	} else {
218 		strlcpy(buf, ADF_CFG_DOWN_STR, sizeof(buf));
219 	}
220 
221 	ret = sysctl_handle_string(oidp, buf, sizeof(buf), req);
222 	if (ret != 0 || req->newptr == NULL)
223 		return ret;
224 
225 	len = strlen(buf);
226 
227 	if ((len > 0 && strncasecmp(ADF_CFG_UP_STR, buf, len) == 0)) {
228 		ret = adf_cfg_up(accel_dev);
229 
230 	} else if (len > 0 && strncasecmp(ADF_CFG_DOWN_STR, buf, len) == 0) {
231 		ret = adf_cfg_down(accel_dev);
232 
233 	} else {
234 		device_printf(GET_DEV(accel_dev), "QAT: Invalid operation\n");
235 		ret = EINVAL;
236 	}
237 
238 	return ret;
239 }
240 
241 static int adf_cfg_sysctl_num_processes_handle(SYSCTL_HANDLER_ARGS)
242 {
243 	struct adf_cfg_device_data *dev_cfg_data;
244 	struct adf_accel_dev *accel_dev;
245 	uint32_t num_user_processes = 0;
246 	int ret = 0;
247 
248 	accel_dev = arg1;
249 	if (!accel_dev)
250 		return ENXIO;
251 
252 	dev_cfg_data = accel_dev->cfg;
253 	if (!dev_cfg_data)
254 		return ENXIO;
255 
256 	num_user_processes = dev_cfg_data->num_user_processes;
257 
258 	ret = sysctl_handle_int(oidp, &num_user_processes, 0, req);
259 	if (ret != 0 || req->newptr == NULL)
260 		return ret;
261 
262 	if (adf_dev_started(accel_dev)) {
263 		device_printf(
264 		    GET_DEV(accel_dev),
265 		    "QAT: configuration could be changed in down state only\n");
266 		return EBUSY;
267 	}
268 
269 	if (num_user_processes > ADF_CFG_MAX_USER_PROCESSES) {
270 		return EINVAL;
271 	}
272 
273 	dev_cfg_data->num_user_processes = num_user_processes;
274 
275 	return ret;
276 }
277 
278 int
279 adf_cfg_sysctl_add(struct adf_accel_dev *accel_dev)
280 {
281 	struct sysctl_ctx_list *qat_sysctl_ctx;
282 	struct sysctl_oid *qat_sysctl_tree;
283 
284 	if (!accel_dev)
285 		return EINVAL;
286 
287 	qat_sysctl_ctx =
288 	    device_get_sysctl_ctx(accel_dev->accel_pci_dev.pci_dev);
289 	qat_sysctl_tree =
290 	    device_get_sysctl_tree(accel_dev->accel_pci_dev.pci_dev);
291 
292 	SYSCTL_ADD_PROC(qat_sysctl_ctx,
293 			SYSCTL_CHILDREN(qat_sysctl_tree),
294 			OID_AUTO,
295 			"state",
296 			CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
297 			accel_dev,
298 			0,
299 			adf_cfg_sysctl_handle,
300 			"A",
301 			"QAT State");
302 
303 	SYSCTL_ADD_PROC(qat_sysctl_ctx,
304 			SYSCTL_CHILDREN(qat_sysctl_tree),
305 			OID_AUTO,
306 			"cfg_services",
307 			CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT,
308 			accel_dev,
309 			0,
310 			adf_cfg_sysctl_services_handle,
311 			"A",
312 			"QAT services confguration");
313 
314 	SYSCTL_ADD_PROC(qat_sysctl_ctx,
315 			SYSCTL_CHILDREN(qat_sysctl_tree),
316 			OID_AUTO,
317 			"cfg_mode",
318 			CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT,
319 			accel_dev,
320 			0,
321 			adf_cfg_sysctl_mode_handle,
322 			"A",
323 			"QAT mode configuration");
324 
325 	SYSCTL_ADD_PROC(qat_sysctl_ctx,
326 			SYSCTL_CHILDREN(qat_sysctl_tree),
327 			OID_AUTO,
328 			"num_user_processes",
329 			CTLTYPE_U32 | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT,
330 			accel_dev,
331 			0,
332 			adf_cfg_sysctl_num_processes_handle,
333 			"I",
334 			"QAT user processes number ");
335 
336 	return 0;
337 }
338 
339 void
340 adf_cfg_sysctl_remove(struct adf_accel_dev *accel_dev)
341 {
342 }
343