1/*
2  This file is provided under a dual BSD/GPLv2 license.  When using or
3  redistributing this file, you may do so under either license.
4
5  GPL LICENSE SUMMARY
6  Copyright(c) 2014 Intel Corporation.
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of version 2 of the GNU General Public License as
9  published by the Free Software Foundation.
10
11  This program is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  General Public License for more details.
15
16  Contact Information:
17  qat-linux@intel.com
18
19  BSD LICENSE
20  Copyright(c) 2014 Intel Corporation.
21  Redistribution and use in source and binary forms, with or without
22  modification, are permitted provided that the following conditions
23  are met:
24
25    * Redistributions of source code must retain the above copyright
26      notice, this list of conditions and the following disclaimer.
27    * Redistributions in binary form must reproduce the above copyright
28      notice, this list of conditions and the following disclaimer in
29      the documentation and/or other materials provided with the
30      distribution.
31    * Neither the name of Intel Corporation nor the names of its
32      contributors may be used to endorse or promote products derived
33      from this software without specific prior written permission.
34
35  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46*/
47#include <linux/mutex.h>
48#include <linux/slab.h>
49#include <linux/list.h>
50#include <linux/seq_file.h>
51#include "adf_accel_devices.h"
52#include "adf_cfg.h"
53#include "adf_common_drv.h"
54
55static DEFINE_MUTEX(qat_cfg_read_lock);
56
57static void *qat_dev_cfg_start(struct seq_file *sfile, loff_t *pos)
58{
59	struct adf_cfg_device_data *dev_cfg = sfile->private;
60
61	mutex_lock(&qat_cfg_read_lock);
62	return seq_list_start(&dev_cfg->sec_list, *pos);
63}
64
65static int qat_dev_cfg_show(struct seq_file *sfile, void *v)
66{
67	struct list_head *list;
68	struct adf_cfg_section *sec =
69				list_entry(v, struct adf_cfg_section, list);
70
71	seq_printf(sfile, "[%s]\n", sec->name);
72	list_for_each(list, &sec->param_head) {
73		struct adf_cfg_key_val *ptr =
74			list_entry(list, struct adf_cfg_key_val, list);
75		seq_printf(sfile, "%s = %s\n", ptr->key, ptr->val);
76	}
77	return 0;
78}
79
80static void *qat_dev_cfg_next(struct seq_file *sfile, void *v, loff_t *pos)
81{
82	struct adf_cfg_device_data *dev_cfg = sfile->private;
83
84	return seq_list_next(v, &dev_cfg->sec_list, pos);
85}
86
87static void qat_dev_cfg_stop(struct seq_file *sfile, void *v)
88{
89	mutex_unlock(&qat_cfg_read_lock);
90}
91
92static const struct seq_operations qat_dev_cfg_sops = {
93	.start = qat_dev_cfg_start,
94	.next = qat_dev_cfg_next,
95	.stop = qat_dev_cfg_stop,
96	.show = qat_dev_cfg_show
97};
98
99static int qat_dev_cfg_open(struct inode *inode, struct file *file)
100{
101	int ret = seq_open(file, &qat_dev_cfg_sops);
102
103	if (!ret) {
104		struct seq_file *seq_f = file->private_data;
105
106		seq_f->private = inode->i_private;
107	}
108	return ret;
109}
110
111static const struct file_operations qat_dev_cfg_fops = {
112	.open = qat_dev_cfg_open,
113	.read = seq_read,
114	.llseek = seq_lseek,
115	.release = seq_release
116};
117
118/**
119 * adf_cfg_dev_add() - Create an acceleration device configuration table.
120 * @accel_dev:  Pointer to acceleration device.
121 *
122 * Function creates a configuration table for the given acceleration device.
123 * The table stores device specific config values.
124 * To be used by QAT device specific drivers.
125 *
126 * Return: 0 on success, error code othewise.
127 */
128int adf_cfg_dev_add(struct adf_accel_dev *accel_dev)
129{
130	struct adf_cfg_device_data *dev_cfg_data;
131
132	dev_cfg_data = kzalloc(sizeof(*dev_cfg_data), GFP_KERNEL);
133	if (!dev_cfg_data)
134		return -ENOMEM;
135	INIT_LIST_HEAD(&dev_cfg_data->sec_list);
136	init_rwsem(&dev_cfg_data->lock);
137	accel_dev->cfg = dev_cfg_data;
138
139	/* accel_dev->debugfs_dir should always be non-NULL here */
140	dev_cfg_data->debug = debugfs_create_file("dev_cfg", S_IRUSR,
141						  accel_dev->debugfs_dir,
142						  dev_cfg_data,
143						  &qat_dev_cfg_fops);
144	if (!dev_cfg_data->debug) {
145		dev_err(&GET_DEV(accel_dev),
146			"Failed to create qat cfg debugfs entry.\n");
147		kfree(dev_cfg_data);
148		accel_dev->cfg = NULL;
149		return -EFAULT;
150	}
151	return 0;
152}
153EXPORT_SYMBOL_GPL(adf_cfg_dev_add);
154
155static void adf_cfg_section_del_all(struct list_head *head);
156
157void adf_cfg_del_all(struct adf_accel_dev *accel_dev)
158{
159	struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
160
161	down_write(&dev_cfg_data->lock);
162	adf_cfg_section_del_all(&dev_cfg_data->sec_list);
163	up_write(&dev_cfg_data->lock);
164	clear_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);
165}
166
167/**
168 * adf_cfg_dev_remove() - Clears acceleration device configuration table.
169 * @accel_dev:  Pointer to acceleration device.
170 *
171 * Function removes configuration table from the given acceleration device
172 * and frees all allocated memory.
173 * To be used by QAT device specific drivers.
174 *
175 * Return: void
176 */
177void adf_cfg_dev_remove(struct adf_accel_dev *accel_dev)
178{
179	struct adf_cfg_device_data *dev_cfg_data = accel_dev->cfg;
180
181	down_write(&dev_cfg_data->lock);
182	adf_cfg_section_del_all(&dev_cfg_data->sec_list);
183	up_write(&dev_cfg_data->lock);
184	debugfs_remove(dev_cfg_data->debug);
185	kfree(dev_cfg_data);
186	accel_dev->cfg = NULL;
187}
188EXPORT_SYMBOL_GPL(adf_cfg_dev_remove);
189
190static void adf_cfg_keyval_add(struct adf_cfg_key_val *new,
191			       struct adf_cfg_section *sec)
192{
193	list_add_tail(&new->list, &sec->param_head);
194}
195
196static void adf_cfg_keyval_del_all(struct list_head *head)
197{
198	struct list_head *list_ptr, *tmp;
199
200	list_for_each_prev_safe(list_ptr, tmp, head) {
201		struct adf_cfg_key_val *ptr =
202			list_entry(list_ptr, struct adf_cfg_key_val, list);
203		list_del(list_ptr);
204		kfree(ptr);
205	}
206}
207
208static void adf_cfg_section_del_all(struct list_head *head)
209{
210	struct adf_cfg_section *ptr;
211	struct list_head *list, *tmp;
212
213	list_for_each_prev_safe(list, tmp, head) {
214		ptr = list_entry(list, struct adf_cfg_section, list);
215		adf_cfg_keyval_del_all(&ptr->param_head);
216		list_del(list);
217		kfree(ptr);
218	}
219}
220
221static struct adf_cfg_key_val *adf_cfg_key_value_find(struct adf_cfg_section *s,
222						      const char *key)
223{
224	struct list_head *list;
225
226	list_for_each(list, &s->param_head) {
227		struct adf_cfg_key_val *ptr =
228			list_entry(list, struct adf_cfg_key_val, list);
229		if (!strcmp(ptr->key, key))
230			return ptr;
231	}
232	return NULL;
233}
234
235static struct adf_cfg_section *adf_cfg_sec_find(struct adf_accel_dev *accel_dev,
236						const char *sec_name)
237{
238	struct adf_cfg_device_data *cfg = accel_dev->cfg;
239	struct list_head *list;
240
241	list_for_each(list, &cfg->sec_list) {
242		struct adf_cfg_section *ptr =
243			list_entry(list, struct adf_cfg_section, list);
244		if (!strcmp(ptr->name, sec_name))
245			return ptr;
246	}
247	return NULL;
248}
249
250static int adf_cfg_key_val_get(struct adf_accel_dev *accel_dev,
251			       const char *sec_name,
252			       const char *key_name,
253			       char *val)
254{
255	struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, sec_name);
256	struct adf_cfg_key_val *keyval = NULL;
257
258	if (sec)
259		keyval = adf_cfg_key_value_find(sec, key_name);
260	if (keyval) {
261		memcpy(val, keyval->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES);
262		return 0;
263	}
264	return -1;
265}
266
267/**
268 * adf_cfg_add_key_value_param() - Add key-value config entry to config table.
269 * @accel_dev:  Pointer to acceleration device.
270 * @section_name: Name of the section where the param will be added
271 * @key: The key string
272 * @val: Value pain for the given @key
273 * @type: Type - string, int or address
274 *
275 * Function adds configuration key - value entry in the appropriate section
276 * in the given acceleration device
277 * To be used by QAT device specific drivers.
278 *
279 * Return: 0 on success, error code othewise.
280 */
281int adf_cfg_add_key_value_param(struct adf_accel_dev *accel_dev,
282				const char *section_name,
283				const char *key, const void *val,
284				enum adf_cfg_val_type type)
285{
286	struct adf_cfg_device_data *cfg = accel_dev->cfg;
287	struct adf_cfg_key_val *key_val;
288	struct adf_cfg_section *section = adf_cfg_sec_find(accel_dev,
289							   section_name);
290	if (!section)
291		return -EFAULT;
292
293	key_val = kzalloc(sizeof(*key_val), GFP_KERNEL);
294	if (!key_val)
295		return -ENOMEM;
296
297	INIT_LIST_HEAD(&key_val->list);
298	strlcpy(key_val->key, key, sizeof(key_val->key));
299
300	if (type == ADF_DEC) {
301		snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,
302			 "%ld", (*((long *)val)));
303	} else if (type == ADF_STR) {
304		strlcpy(key_val->val, (char *)val, sizeof(key_val->val));
305	} else if (type == ADF_HEX) {
306		snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,
307			 "0x%lx", (unsigned long)val);
308	} else {
309		dev_err(&GET_DEV(accel_dev), "Unknown type given.\n");
310		kfree(key_val);
311		return -1;
312	}
313	key_val->type = type;
314	down_write(&cfg->lock);
315	adf_cfg_keyval_add(key_val, section);
316	up_write(&cfg->lock);
317	return 0;
318}
319EXPORT_SYMBOL_GPL(adf_cfg_add_key_value_param);
320
321/**
322 * adf_cfg_section_add() - Add config section entry to config table.
323 * @accel_dev:  Pointer to acceleration device.
324 * @name: Name of the section
325 *
326 * Function adds configuration section where key - value entries
327 * will be stored.
328 * To be used by QAT device specific drivers.
329 *
330 * Return: 0 on success, error code othewise.
331 */
332int adf_cfg_section_add(struct adf_accel_dev *accel_dev, const char *name)
333{
334	struct adf_cfg_device_data *cfg = accel_dev->cfg;
335	struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, name);
336
337	if (sec)
338		return 0;
339
340	sec = kzalloc(sizeof(*sec), GFP_KERNEL);
341	if (!sec)
342		return -ENOMEM;
343
344	strlcpy(sec->name, name, sizeof(sec->name));
345	INIT_LIST_HEAD(&sec->param_head);
346	down_write(&cfg->lock);
347	list_add_tail(&sec->list, &cfg->sec_list);
348	up_write(&cfg->lock);
349	return 0;
350}
351EXPORT_SYMBOL_GPL(adf_cfg_section_add);
352
353int adf_cfg_get_param_value(struct adf_accel_dev *accel_dev,
354			    const char *section, const char *name,
355			    char *value)
356{
357	struct adf_cfg_device_data *cfg = accel_dev->cfg;
358	int ret;
359
360	down_read(&cfg->lock);
361	ret = adf_cfg_key_val_get(accel_dev, section, name, value);
362	up_read(&cfg->lock);
363	return ret;
364}
365