Commit | Line | Data |
---|---|---|
d8cba25d TS |
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" | |
d8cba25d | 52 | #include "adf_cfg.h" |
22e4dda0 | 53 | #include "adf_common_drv.h" |
d8cba25d TS |
54 | |
55 | static DEFINE_MUTEX(qat_cfg_read_lock); | |
56 | ||
57 | static void *qat_dev_cfg_start(struct seq_file *sfile, loff_t *pos) | |
58 | { | |
59 | struct adf_cfg_device_data *dev_cfg = sfile->private; | |
d65071ec | 60 | |
d8cba25d TS |
61 | mutex_lock(&qat_cfg_read_lock); |
62 | return seq_list_start(&dev_cfg->sec_list, *pos); | |
63 | } | |
64 | ||
65 | static 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 | ||
80 | static 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; | |
d65071ec | 83 | |
d8cba25d TS |
84 | return seq_list_next(v, &dev_cfg->sec_list, pos); |
85 | } | |
86 | ||
87 | static void qat_dev_cfg_stop(struct seq_file *sfile, void *v) | |
88 | { | |
89 | mutex_unlock(&qat_cfg_read_lock); | |
90 | } | |
91 | ||
92 | static 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 | ||
99 | static 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; | |
d65071ec | 105 | |
d8cba25d TS |
106 | seq_f->private = inode->i_private; |
107 | } | |
108 | return ret; | |
109 | } | |
110 | ||
111 | static 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 | * | |
ec0d6fa3 | 126 | * Return: 0 on success, error code otherwise. |
d8cba25d TS |
127 | */ |
128 | int 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) { | |
66550304 AB |
145 | dev_err(&GET_DEV(accel_dev), |
146 | "Failed to create qat cfg debugfs entry.\n"); | |
d8cba25d TS |
147 | kfree(dev_cfg_data); |
148 | accel_dev->cfg = NULL; | |
149 | return -EFAULT; | |
150 | } | |
151 | return 0; | |
152 | } | |
153 | EXPORT_SYMBOL_GPL(adf_cfg_dev_add); | |
154 | ||
155 | static void adf_cfg_section_del_all(struct list_head *head); | |
156 | ||
157 | void 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); | |
22e4dda0 | 164 | clear_bit(ADF_STATUS_CONFIGURED, &accel_dev->status); |
d8cba25d TS |
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 | */ | |
177 | void 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 | } | |
188 | EXPORT_SYMBOL_GPL(adf_cfg_dev_remove); | |
189 | ||
190 | static 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 | ||
196 | static 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 | ||
208 | static 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 | ||
221 | static 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 | ||
235 | static 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 | ||
250 | static 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 | * | |
ec0d6fa3 | 279 | * Return: 0 on success, error code otherwise. |
d8cba25d TS |
280 | */ |
281 | int 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 { | |
66550304 | 309 | dev_err(&GET_DEV(accel_dev), "Unknown type given.\n"); |
d8cba25d TS |
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 | } | |
319 | EXPORT_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 | * | |
ec0d6fa3 | 330 | * Return: 0 on success, error code otherwise. |
d8cba25d TS |
331 | */ |
332 | int 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 | } | |
351 | EXPORT_SYMBOL_GPL(adf_cfg_section_add); | |
352 | ||
353 | int 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 | } |