1// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
2/* Copyright(c) 2014 - 2020 Intel Corporation */
3#include <linux/mutex.h>
4#include <linux/slab.h>
5#include <linux/list.h>
6#include <linux/seq_file.h>
7#include "adf_accel_devices.h"
8#include "adf_cfg.h"
9#include "adf_common_drv.h"
10
11static DEFINE_MUTEX(qat_cfg_read_lock);
12
13static void *qat_dev_cfg_start(struct seq_file *sfile, loff_t *pos)
14{
15 struct adf_cfg_device_data *dev_cfg = sfile->private;
16
17 mutex_lock(&qat_cfg_read_lock);
18 return seq_list_start(head: &dev_cfg->sec_list, pos: *pos);
19}
20
21static int qat_dev_cfg_show(struct seq_file *sfile, void *v)
22{
23 struct list_head *list;
24 struct adf_cfg_section *sec =
25 list_entry(v, struct adf_cfg_section, list);
26
27 seq_printf(m: sfile, fmt: "[%s]\n", sec->name);
28 list_for_each(list, &sec->param_head) {
29 struct adf_cfg_key_val *ptr =
30 list_entry(list, struct adf_cfg_key_val, list);
31 seq_printf(m: sfile, fmt: "%s = %s\n", ptr->key, ptr->val);
32 }
33 return 0;
34}
35
36static void *qat_dev_cfg_next(struct seq_file *sfile, void *v, loff_t *pos)
37{
38 struct adf_cfg_device_data *dev_cfg = sfile->private;
39
40 return seq_list_next(v, head: &dev_cfg->sec_list, ppos: pos);
41}
42
43static void qat_dev_cfg_stop(struct seq_file *sfile, void *v)
44{
45 mutex_unlock(lock: &qat_cfg_read_lock);
46}
47
48static const struct seq_operations qat_dev_cfg_sops = {
49 .start = qat_dev_cfg_start,
50 .next = qat_dev_cfg_next,
51 .stop = qat_dev_cfg_stop,
52 .show = qat_dev_cfg_show
53};
54
55DEFINE_SEQ_ATTRIBUTE(qat_dev_cfg);
56
57/**
58 * adf_cfg_dev_add() - Create an acceleration device configuration table.
59 * @accel_dev: Pointer to acceleration device.
60 *
61 * Function creates a configuration table for the given acceleration device.
62 * The table stores device specific config values.
63 * To be used by QAT device specific drivers.
64 *
65 * Return: 0 on success, error code otherwise.
66 */
67int adf_cfg_dev_add(struct adf_accel_dev *accel_dev)
68{
69 struct adf_cfg_device_data *dev_cfg_data;
70
71 dev_cfg_data = kzalloc(sizeof(*dev_cfg_data), GFP_KERNEL);
72 if (!dev_cfg_data)
73 return -ENOMEM;
74 INIT_LIST_HEAD(list: &dev_cfg_data->sec_list);
75 init_rwsem(&dev_cfg_data->lock);
76 accel_dev->cfg = dev_cfg_data;
77 return 0;
78}
79EXPORT_SYMBOL_GPL(adf_cfg_dev_add);
80
81void adf_cfg_dev_dbgfs_add(struct adf_accel_dev *accel_dev)
82{
83 struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
84
85 dev_cfg_data->debug = debugfs_create_file("dev_cfg", 0400,
86 accel_dev->debugfs_dir,
87 dev_cfg_data,
88 &qat_dev_cfg_fops);
89}
90
91void adf_cfg_dev_dbgfs_rm(struct adf_accel_dev *accel_dev)
92{
93 struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
94
95 if (!dev_cfg_data)
96 return;
97
98 debugfs_remove(dentry: dev_cfg_data->debug);
99 dev_cfg_data->debug = NULL;
100}
101
102static void adf_cfg_section_del_all(struct list_head *head);
103static void adf_cfg_section_del_all_except(struct list_head *head,
104 const char *section_name);
105
106void adf_cfg_del_all(struct adf_accel_dev *accel_dev)
107{
108 struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
109
110 down_write(sem: &dev_cfg_data->lock);
111 adf_cfg_section_del_all(head: &dev_cfg_data->sec_list);
112 up_write(sem: &dev_cfg_data->lock);
113 clear_bit(ADF_STATUS_CONFIGURED, addr: &accel_dev->status);
114}
115
116void adf_cfg_del_all_except(struct adf_accel_dev *accel_dev,
117 const char *section_name)
118{
119 struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
120
121 down_write(sem: &dev_cfg_data->lock);
122 adf_cfg_section_del_all_except(head: &dev_cfg_data->sec_list, section_name);
123 up_write(sem: &dev_cfg_data->lock);
124 clear_bit(ADF_STATUS_CONFIGURED, addr: &accel_dev->status);
125}
126
127/**
128 * adf_cfg_dev_remove() - Clears acceleration device configuration table.
129 * @accel_dev: Pointer to acceleration device.
130 *
131 * Function removes configuration table from the given acceleration device
132 * and frees all allocated memory.
133 * To be used by QAT device specific drivers.
134 *
135 * Return: void
136 */
137void adf_cfg_dev_remove(struct adf_accel_dev *accel_dev)
138{
139 struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
140
141 if (!dev_cfg_data)
142 return;
143
144 down_write(sem: &dev_cfg_data->lock);
145 adf_cfg_section_del_all(head: &dev_cfg_data->sec_list);
146 up_write(sem: &dev_cfg_data->lock);
147 kfree(objp: dev_cfg_data);
148 accel_dev->cfg = NULL;
149}
150EXPORT_SYMBOL_GPL(adf_cfg_dev_remove);
151
152static void adf_cfg_keyval_add(struct adf_cfg_key_val *new,
153 struct adf_cfg_section *sec)
154{
155 list_add_tail(new: &new->list, head: &sec->param_head);
156}
157
158static void adf_cfg_keyval_remove(const char *key, struct adf_cfg_section *sec)
159{
160 struct list_head *head = &sec->param_head;
161 struct list_head *list_ptr, *tmp;
162
163 list_for_each_prev_safe(list_ptr, tmp, head) {
164 struct adf_cfg_key_val *ptr =
165 list_entry(list_ptr, struct adf_cfg_key_val, list);
166
167 if (strncmp(ptr->key, key, sizeof(ptr->key)))
168 continue;
169
170 list_del(entry: list_ptr);
171 kfree(objp: ptr);
172 break;
173 }
174}
175
176static void adf_cfg_keyval_del_all(struct list_head *head)
177{
178 struct list_head *list_ptr, *tmp;
179
180 list_for_each_prev_safe(list_ptr, tmp, head) {
181 struct adf_cfg_key_val *ptr =
182 list_entry(list_ptr, struct adf_cfg_key_val, list);
183 list_del(entry: list_ptr);
184 kfree(objp: ptr);
185 }
186}
187
188static void adf_cfg_section_del_all(struct list_head *head)
189{
190 struct adf_cfg_section *ptr;
191 struct list_head *list, *tmp;
192
193 list_for_each_prev_safe(list, tmp, head) {
194 ptr = list_entry(list, struct adf_cfg_section, list);
195 adf_cfg_keyval_del_all(head: &ptr->param_head);
196 list_del(entry: list);
197 kfree(objp: ptr);
198 }
199}
200
201static void adf_cfg_section_del_all_except(struct list_head *head,
202 const char *section_name)
203{
204 struct list_head *list, *tmp;
205 struct adf_cfg_section *ptr;
206
207 list_for_each_prev_safe(list, tmp, head) {
208 ptr = list_entry(list, struct adf_cfg_section, list);
209 if (!strcmp(ptr->name, section_name))
210 continue;
211 adf_cfg_keyval_del_all(head: &ptr->param_head);
212 list_del(entry: list);
213 kfree(objp: ptr);
214 }
215}
216
217static struct adf_cfg_key_val *adf_cfg_key_value_find(struct adf_cfg_section *s,
218 const char *key)
219{
220 struct list_head *list;
221
222 list_for_each(list, &s->param_head) {
223 struct adf_cfg_key_val *ptr =
224 list_entry(list, struct adf_cfg_key_val, list);
225 if (!strcmp(ptr->key, key))
226 return ptr;
227 }
228 return NULL;
229}
230
231static struct adf_cfg_section *adf_cfg_sec_find(struct adf_accel_dev *accel_dev,
232 const char *sec_name)
233{
234 struct adf_cfg_device_data *cfg = accel_dev->cfg;
235 struct list_head *list;
236
237 list_for_each(list, &cfg->sec_list) {
238 struct adf_cfg_section *ptr =
239 list_entry(list, struct adf_cfg_section, list);
240 if (!strcmp(ptr->name, sec_name))
241 return ptr;
242 }
243 return NULL;
244}
245
246static int adf_cfg_key_val_get(struct adf_accel_dev *accel_dev,
247 const char *sec_name,
248 const char *key_name,
249 char *val)
250{
251 struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, sec_name);
252 struct adf_cfg_key_val *keyval = NULL;
253
254 if (sec)
255 keyval = adf_cfg_key_value_find(s: sec, key: key_name);
256 if (keyval) {
257 memcpy(val, keyval->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES);
258 return 0;
259 }
260 return -ENODATA;
261}
262
263/**
264 * adf_cfg_add_key_value_param() - Add key-value config entry to config table.
265 * @accel_dev: Pointer to acceleration device.
266 * @section_name: Name of the section where the param will be added
267 * @key: The key string
268 * @val: Value pain for the given @key
269 * @type: Type - string, int or address
270 *
271 * Function adds configuration key - value entry in the appropriate section
272 * in the given acceleration device. If the key exists already, the value
273 * is updated.
274 * To be used by QAT device specific drivers.
275 *
276 * Return: 0 on success, error code otherwise.
277 */
278int adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev,
279 const char *section_name,
280 const char *key, const void *val,
281 enum adf_cfg_val_type type)
282{
283 struct adf_cfg_device_data *cfg = accel_dev->cfg;
284 struct adf_cfg_key_val *key_val;
285 struct adf_cfg_section *section = adf_cfg_sec_find(accel_dev,
286 sec_name: section_name);
287 char temp_val[ADF_CFG_MAX_VAL_LEN_IN_BYTES];
288
289 if (!section)
290 return -EFAULT;
291
292 key_val = kzalloc(sizeof(*key_val), GFP_KERNEL);
293 if (!key_val)
294 return -ENOMEM;
295
296 INIT_LIST_HEAD(list: &key_val->list);
297 strscpy(key_val->key, key, sizeof(key_val->key));
298
299 if (type == ADF_DEC) {
300 snprintf(buf: key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,
301 fmt: "%ld", (*((long *)val)));
302 } else if (type == ADF_STR) {
303 strscpy(key_val->val, (char *)val, sizeof(key_val->val));
304 } else if (type == ADF_HEX) {
305 snprintf(buf: key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,
306 fmt: "0x%lx", (unsigned long)val);
307 } else {
308 dev_err(&GET_DEV(accel_dev), "Unknown type given.\n");
309 kfree(objp: key_val);
310 return -EINVAL;
311 }
312 key_val->type = type;
313
314 /* Add the key-value pair as below policy:
315 * 1. if the key doesn't exist, add it;
316 * 2. if the key already exists with a different value then update it
317 * to the new value (the key is deleted and the newly created
318 * key_val containing the new value is added to the database);
319 * 3. if the key exists with the same value, then return without doing
320 * anything (the newly created key_val is freed).
321 */
322 down_write(sem: &cfg->lock);
323 if (!adf_cfg_key_val_get(accel_dev, sec_name: section_name, key_name: key, val: temp_val)) {
324 if (strncmp(temp_val, key_val->val, sizeof(temp_val))) {
325 adf_cfg_keyval_remove(key, sec: section);
326 } else {
327 kfree(objp: key_val);
328 goto out;
329 }
330 }
331
332 adf_cfg_keyval_add(new: key_val, sec: section);
333
334out:
335 up_write(sem: &cfg->lock);
336 return 0;
337}
338EXPORT_SYMBOL_GPL(adf_cfg_add_key_value_param);
339
340/**
341 * adf_cfg_section_add() - Add config section entry to config table.
342 * @accel_dev: Pointer to acceleration device.
343 * @name: Name of the section
344 *
345 * Function adds configuration section where key - value entries
346 * will be stored.
347 * To be used by QAT device specific drivers.
348 *
349 * Return: 0 on success, error code otherwise.
350 */
351int adf_cfg_section_add(struct adf_accel_dev *accel_dev, const char *name)
352{
353 struct adf_cfg_device_data *cfg = accel_dev->cfg;
354 struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, sec_name: name);
355
356 if (sec)
357 return 0;
358
359 sec = kzalloc(sizeof(*sec), GFP_KERNEL);
360 if (!sec)
361 return -ENOMEM;
362
363 strscpy(sec->name, name, sizeof(sec->name));
364 INIT_LIST_HEAD(list: &sec->param_head);
365 down_write(sem: &cfg->lock);
366 list_add_tail(new: &sec->list, head: &cfg->sec_list);
367 up_write(sem: &cfg->lock);
368 return 0;
369}
370EXPORT_SYMBOL_GPL(adf_cfg_section_add);
371
372int adf_cfg_get_param_value(struct adf_accel_dev *accel_dev,
373 const char *section, const char *name,
374 char *value)
375{
376 struct adf_cfg_device_data *cfg = accel_dev->cfg;
377 int ret;
378
379 down_read(sem: &cfg->lock);
380 ret = adf_cfg_key_val_get(accel_dev, sec_name: section, key_name: name, val: value);
381 up_read(sem: &cfg->lock);
382 return ret;
383}
384EXPORT_SYMBOL_GPL(adf_cfg_get_param_value);
385

source code of linux/drivers/crypto/intel/qat/qat_common/adf_cfg.c