brintos

brintos / linux-shallow public Read only

0
0
Text · 10.2 KiB · b0fc453 Raw
385 lines · c
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_show53};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);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(&dev_cfg_data->lock);111	adf_cfg_section_del_all(&dev_cfg_data->sec_list);112	up_write(&dev_cfg_data->lock);113	clear_bit(ADF_STATUS_CONFIGURED, &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(&dev_cfg_data->lock);122	adf_cfg_section_del_all_except(&dev_cfg_data->sec_list, section_name);123	up_write(&dev_cfg_data->lock);124	clear_bit(ADF_STATUS_CONFIGURED, &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 device132 * and frees all allocated memory.133 * To be used by QAT device specific drivers.134 *135 * Return: void136 */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(&dev_cfg_data->lock);145	adf_cfg_section_del_all(&dev_cfg_data->sec_list);146	up_write(&dev_cfg_data->lock);147	kfree(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->list, &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(list_ptr);171		kfree(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(list_ptr);184		kfree(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(&ptr->param_head);196		list_del(list);197		kfree(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(&ptr->param_head);212		list_del(list);213		kfree(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(sec, 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 added267 * @key: The key string268 * @val: Value pain for the given @key269 * @type: Type - string, int or address270 *271 * Function adds configuration key - value entry in the appropriate section272 * in the given acceleration device. If the key exists already, the value273 * 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							   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(&key_val->list);297	strscpy(key_val->key, key, sizeof(key_val->key));298 299	if (type == ADF_DEC) {300		snprintf(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,301			 "%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(key_val->val, ADF_CFG_MAX_VAL_LEN_IN_BYTES,306			 "0x%lx", (unsigned long)val);307	} else {308		dev_err(&GET_DEV(accel_dev), "Unknown type given.\n");309		kfree(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 it317	 *    to the new value (the key is deleted and the newly created318	 *    key_val containing the new value is added to the database);319	 * 3. if the key exists with the same value, then return without doing320	 *    anything (the newly created key_val is freed).321	 */322	down_write(&cfg->lock);323	if (!adf_cfg_key_val_get(accel_dev, section_name, key, temp_val)) {324		if (strncmp(temp_val, key_val->val, sizeof(temp_val))) {325			adf_cfg_keyval_remove(key, section);326		} else {327			kfree(key_val);328			goto out;329		}330	}331 332	adf_cfg_keyval_add(key_val, section);333 334out:335	up_write(&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 section344 *345 * Function adds configuration section where key - value entries346 * 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, 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(&sec->param_head);365	down_write(&cfg->lock);366	list_add_tail(&sec->list, &cfg->sec_list);367	up_write(&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(&cfg->lock);380	ret = adf_cfg_key_val_get(accel_dev, section, name, value);381	up_read(&cfg->lock);382	return ret;383}384EXPORT_SYMBOL_GPL(adf_cfg_get_param_value);385