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(&dev_cfg->sec_list, *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(sfile, "[%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(sfile, "%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, &dev_cfg->sec_list, pos);
41}
42
43static void qat_dev_cfg_stop(struct seq_file *sfile, void *v)
44{
45	mutex_unlock(&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(&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(dev_cfg_data->debug);
99	dev_cfg_data->debug = NULL;
100}
101
102static void adf_cfg_section_del_all(struct list_head *head);
103
104void adf_cfg_del_all(struct adf_accel_dev *accel_dev)
105{
106	struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
107
108	down_write(&dev_cfg_data->lock);
109	adf_cfg_section_del_all(&dev_cfg_data->sec_list);
110	up_write(&dev_cfg_data->lock);
111	clear_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);
112}
113
114/**
115 * adf_cfg_dev_remove() - Clears acceleration device configuration table.
116 * @accel_dev:  Pointer to acceleration device.
117 *
118 * Function removes configuration table from the given acceleration device
119 * and frees all allocated memory.
120 * To be used by QAT device specific drivers.
121 *
122 * Return: void
123 */
124void adf_cfg_dev_remove(struct adf_accel_dev *accel_dev)
125{
126	struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
127
128	if (!dev_cfg_data)
129		return;
130
131	down_write(&dev_cfg_data->lock);
132	adf_cfg_section_del_all(&dev_cfg_data->sec_list);
133	up_write(&dev_cfg_data->lock);
134	kfree(dev_cfg_data);
135	accel_dev->cfg = NULL;
136}
137EXPORT_SYMBOL_GPL(adf_cfg_dev_remove);
138
139static void adf_cfg_keyval_add(struct adf_cfg_key_val *new,
140			       struct adf_cfg_section *sec)
141{
142	list_add_tail(&new->list, &sec->param_head);
143}
144
145static void adf_cfg_keyval_remove(const char *key, struct adf_cfg_section *sec)
146{
147	struct list_head *head = &sec->param_head;
148	struct list_head *list_ptr, *tmp;
149
150	list_for_each_prev_safe(list_ptr, tmp, head) {
151		struct adf_cfg_key_val *ptr =
152			list_entry(list_ptr, struct adf_cfg_key_val, list);
153
154		if (strncmp(ptr->key, key, sizeof(ptr->key)))
155			continue;
156
157		list_del(list_ptr);
158		kfree(ptr);
159		break;
160	}
161}
162
163static void adf_cfg_keyval_del_all(struct list_head *head)
164{
165	struct list_head *list_ptr, *tmp;
166
167	list_for_each_prev_safe(list_ptr, tmp, head) {
168		struct adf_cfg_key_val *ptr =
169			list_entry(list_ptr, struct adf_cfg_key_val, list);
170		list_del(list_ptr);
171		kfree(ptr);
172	}
173}
174
175static void adf_cfg_section_del_all(struct list_head *head)
176{
177	struct adf_cfg_section *ptr;
178	struct list_head *list, *tmp;
179
180	list_for_each_prev_safe(list, tmp, head) {
181		ptr = list_entry(list, struct adf_cfg_section, list);
182		adf_cfg_keyval_del_all(&ptr->param_head);
183		list_del(list);
184		kfree(ptr);
185	}
186}
187
188static struct adf_cfg_key_val *adf_cfg_key_value_find(struct adf_cfg_section *s,
189						      const char *key)
190{
191	struct list_head *list;
192
193	list_for_each(list, &s->param_head) {
194		struct adf_cfg_key_val *ptr =
195			list_entry(list, struct adf_cfg_key_val, list);
196		if (!strcmp(ptr->key, key))
197			return ptr;
198	}
199	return NULL;
200}
201
202static struct adf_cfg_section *adf_cfg_sec_find(struct adf_accel_dev *accel_dev,
203						const char *sec_name)
204{
205	struct adf_cfg_device_data *cfg = accel_dev->cfg;
206	struct list_head *list;
207
208	list_for_each(list, &cfg->sec_list) {
209		struct adf_cfg_section *ptr =
210			list_entry(list, struct adf_cfg_section, list);
211		if (!strcmp(ptr->name, sec_name))
212			return ptr;
213	}
214	return NULL;
215}
216
217static int adf_cfg_key_val_get(struct adf_accel_dev *accel_dev,
218			       const char *sec_name,
219			       const char *key_name,
220			       char *val)
221{
222	struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, sec_name);
223	struct adf_cfg_key_val *keyval = NULL;
224
225	if (sec)
226		keyval = adf_cfg_key_value_find(sec, key_name);
227	if (keyval) {
228		memcpy(val, keyval->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES);
229		return 0;
230	}
231	return -ENODATA;
232}
233
234/**
235 * adf_cfg_add_key_value_param() - Add key-value config entry to config table.
236 * @accel_dev:  Pointer to acceleration device.
237 * @section_name: Name of the section where the param will be added
238 * @key: The key string
239 * @val: Value pain for the given @key
240 * @type: Type - string, int or address
241 *
242 * Function adds configuration key - value entry in the appropriate section
243 * in the given acceleration device. If the key exists already, the value
244 * is updated.
245 * To be used by QAT device specific drivers.
246 *
247 * Return: 0 on success, error code otherwise.
248 */
249int adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev,
250				const char *section_name,
251				const char *key, const void *val,
252				enum adf_cfg_val_type type)
253{
254	struct adf_cfg_device_data *cfg = accel_dev->cfg;
255	struct adf_cfg_key_val *key_val;
256	struct adf_cfg_section *section = adf_cfg_sec_find(accel_dev,
257							   section_name);
258	char temp_val[ADF_CFG_MAX_VAL_LEN_IN_BYTES];
259
260	if (!section)
261		return -EFAULT;
262
263	key_val = kzalloc(sizeof(*key_val), GFP_KERNEL);
264	if (!key_val)
265		return -ENOMEM;
266
267	INIT_LIST_HEAD(&key_val->list);
268	strscpy(key_val->key, key, sizeof(key_val->key));
269
270	if (type == ADF_DEC) {
271		snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,
272			 "%ld", (*((long *)val)));
273	} else if (type == ADF_STR) {
274		strscpy(key_val->val, (char *)val, sizeof(key_val->val));
275	} else if (type == ADF_HEX) {
276		snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,
277			 "0x%lx", (unsigned long)val);
278	} else {
279		dev_err(&GET_DEV(accel_dev), "Unknown type given.\n");
280		kfree(key_val);
281		return -EINVAL;
282	}
283	key_val->type = type;
284
285	/* Add the key-value pair as below policy:
286	 * 1. if the key doesn't exist, add it;
287	 * 2. if the key already exists with a different value then update it
288	 *    to the new value (the key is deleted and the newly created
289	 *    key_val containing the new value is added to the database);
290	 * 3. if the key exists with the same value, then return without doing
291	 *    anything (the newly created key_val is freed).
292	 */
293	if (!adf_cfg_key_val_get(accel_dev, section_name, key, temp_val)) {
294		if (strncmp(temp_val, key_val->val, sizeof(temp_val))) {
295			adf_cfg_keyval_remove(key, section);
296		} else {
297			kfree(key_val);
298			return 0;
299		}
300	}
301
302	down_write(&cfg->lock);
303	adf_cfg_keyval_add(key_val, section);
304	up_write(&cfg->lock);
305	return 0;
306}
307EXPORT_SYMBOL_GPL(adf_cfg_add_key_value_param);
308
309/**
310 * adf_cfg_section_add() - Add config section entry to config table.
311 * @accel_dev:  Pointer to acceleration device.
312 * @name: Name of the section
313 *
314 * Function adds configuration section where key - value entries
315 * will be stored.
316 * To be used by QAT device specific drivers.
317 *
318 * Return: 0 on success, error code otherwise.
319 */
320int adf_cfg_section_add(struct adf_accel_dev *accel_dev, const char *name)
321{
322	struct adf_cfg_device_data *cfg = accel_dev->cfg;
323	struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, name);
324
325	if (sec)
326		return 0;
327
328	sec = kzalloc(sizeof(*sec), GFP_KERNEL);
329	if (!sec)
330		return -ENOMEM;
331
332	strscpy(sec->name, name, sizeof(sec->name));
333	INIT_LIST_HEAD(&sec->param_head);
334	down_write(&cfg->lock);
335	list_add_tail(&sec->list, &cfg->sec_list);
336	up_write(&cfg->lock);
337	return 0;
338}
339EXPORT_SYMBOL_GPL(adf_cfg_section_add);
340
341int adf_cfg_get_param_value(struct adf_accel_dev *accel_dev,
342			    const char *section, const char *name,
343			    char *value)
344{
345	struct adf_cfg_device_data *cfg = accel_dev->cfg;
346	int ret;
347
348	down_read(&cfg->lock);
349	ret = adf_cfg_key_val_get(accel_dev, section, name, value);
350	up_read(&cfg->lock);
351	return ret;
352}
353EXPORT_SYMBOL_GPL(adf_cfg_get_param_value);
354