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