702 lines · 17.4 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0 #include <linux/types.h>#include <linux/kconfig.h>#include <linux/list.h>#include <linux/slab.h>#include <linux/security.h>#include <linux/highmem.h>#include <linux/umh.h>#include <linux/sysctl.h>#include <linux/vmalloc.h> #include "fallback.h"#include "firmware.h" /* * firmware fallback mechanism */ extern struct firmware_fallback_config fw_fallback_config; /* These getters are vetted to use int properly */static inline int __firmware_loading_timeout(void){	return fw_fallback_config.loading_timeout;} /* These setters are vetted to use int properly */static void __fw_fallback_set_timeout(int timeout){	fw_fallback_config.loading_timeout = timeout;} /* * use small loading timeout for caching devices' firmware because all these * firmware images have been loaded successfully at lease once, also system is * ready for completing firmware loading now. The maximum size of firmware in * current distributions is about 2M bytes, so 10 secs should be enough. */void fw_fallback_set_cache_timeout(void){	fw_fallback_config.old_timeout = __firmware_loading_timeout();	__fw_fallback_set_timeout(10);} /* Restores the timeout to the value last configured during normal operation */void fw_fallback_set_default_timeout(void){	__fw_fallback_set_timeout(fw_fallback_config.old_timeout);} static long firmware_loading_timeout(void){	return __firmware_loading_timeout() > 0 ?		__firmware_loading_timeout() * HZ : MAX_JIFFY_OFFSET;} static inline bool fw_sysfs_done(struct fw_priv *fw_priv){	return __fw_state_check(fw_priv, FW_STATUS_DONE);} static inline bool fw_sysfs_loading(struct fw_priv *fw_priv){	return __fw_state_check(fw_priv, FW_STATUS_LOADING);} static inline int fw_sysfs_wait_timeout(struct fw_priv *fw_priv,  long timeout){	return __fw_state_wait_common(fw_priv, timeout);} struct fw_sysfs {	bool nowait;	struct device dev;	struct fw_priv *fw_priv;	struct firmware *fw;}; static struct fw_sysfs *to_fw_sysfs(struct device *dev){	return container_of(dev, struct fw_sysfs, dev);} static void __fw_load_abort(struct fw_priv *fw_priv){	/*	 * There is a small window in which user can write to 'loading'	 * between loading done and disappearance of 'loading'	 */	if (fw_sysfs_done(fw_priv))		return; 	list_del_init(&fw_priv->pending_list);	fw_state_aborted(fw_priv);} static void fw_load_abort(struct fw_sysfs *fw_sysfs){	struct fw_priv *fw_priv = fw_sysfs->fw_priv; 	__fw_load_abort(fw_priv);} static LIST_HEAD(pending_fw_head); void kill_pending_fw_fallback_reqs(bool only_kill_custom){	struct fw_priv *fw_priv;	struct fw_priv *next; 	mutex_lock(&fw_lock);	list_for_each_entry_safe(fw_priv, next, &pending_fw_head,				 pending_list) {		if (!fw_priv->need_uevent || !only_kill_custom)			 __fw_load_abort(fw_priv);	}	mutex_unlock(&fw_lock);} static ssize_t timeout_show(struct class *class, struct class_attribute *attr,			    char *buf){	return sprintf(buf, "%d\n", __firmware_loading_timeout());} /** * firmware_timeout_store() - set number of seconds to wait for firmware * @class: device class pointer * @attr: device attribute pointer * @buf: buffer to scan for timeout value * @count: number of bytes in @buf * *	Sets the number of seconds to wait for the firmware.  Once *	this expires an error will be returned to the driver and no *	firmware will be provided. * *	Note: zero means 'wait forever'. **/static ssize_t timeout_store(struct class *class, struct class_attribute *attr,			     const char *buf, size_t count){	int tmp_loading_timeout = simple_strtol(buf, NULL, 10); 	if (tmp_loading_timeout < 0)		tmp_loading_timeout = 0; 	__fw_fallback_set_timeout(tmp_loading_timeout); 	return count;}static CLASS_ATTR_RW(timeout); static struct attribute *firmware_class_attrs[] = {	&class_attr_timeout.attr,	NULL,};ATTRIBUTE_GROUPS(firmware_class); static void fw_dev_release(struct device *dev){	struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev); 	kfree(fw_sysfs);} static int do_firmware_uevent(struct fw_sysfs *fw_sysfs, struct kobj_uevent_env *env){	if (add_uevent_var(env, "FIRMWARE=%s", fw_sysfs->fw_priv->fw_name))		return -ENOMEM;	if (add_uevent_var(env, "TIMEOUT=%i", __firmware_loading_timeout()))		return -ENOMEM;	if (add_uevent_var(env, "ASYNC=%d", fw_sysfs->nowait))		return -ENOMEM; 	return 0;} static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env){	struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);	int err = 0; 	mutex_lock(&fw_lock);	if (fw_sysfs->fw_priv)		err = do_firmware_uevent(fw_sysfs, env);	mutex_unlock(&fw_lock);	return err;} static struct class firmware_class = {	.name		= "firmware",	.class_groups	= firmware_class_groups,	.dev_uevent	= firmware_uevent,	.dev_release	= fw_dev_release,}; int register_sysfs_loader(void){	return class_register(&firmware_class);} void unregister_sysfs_loader(void){	class_unregister(&firmware_class);} static ssize_t firmware_loading_show(struct device *dev,				     struct device_attribute *attr, char *buf){	struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);	int loading = 0; 	mutex_lock(&fw_lock);	if (fw_sysfs->fw_priv)		loading = fw_sysfs_loading(fw_sysfs->fw_priv);	mutex_unlock(&fw_lock); 	return sprintf(buf, "%d\n", loading);} /* one pages buffer should be mapped/unmapped only once */static int map_fw_priv_pages(struct fw_priv *fw_priv){	if (!fw_priv->is_paged_buf)		return 0; 	vunmap(fw_priv->data);	fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0,			     PAGE_KERNEL_RO);	if (!fw_priv->data)		return -ENOMEM;	return 0;} /** * firmware_loading_store() - set value in the 'loading' control file * @dev: device pointer * @attr: device attribute pointer * @buf: buffer to scan for loading control value * @count: number of bytes in @buf * *	The relevant values are: * *	 1: Start a load, discarding any previous partial load. *	 0: Conclude the load and hand the data to the driver code. *	-1: Conclude the load with an error and discard any written data. **/static ssize_t firmware_loading_store(struct device *dev,				      struct device_attribute *attr,				      const char *buf, size_t count){	struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);	struct fw_priv *fw_priv;	ssize_t written = count;	int loading = simple_strtol(buf, NULL, 10);	int i; 	mutex_lock(&fw_lock);	fw_priv = fw_sysfs->fw_priv;	if (fw_state_is_aborted(fw_priv))		goto out; 	switch (loading) {	case 1:		/* discarding any previous partial load */		if (!fw_sysfs_done(fw_priv)) {			for (i = 0; i < fw_priv->nr_pages; i++)				__free_page(fw_priv->pages[i]);			vfree(fw_priv->pages);			fw_priv->pages = NULL;			fw_priv->page_array_size = 0;			fw_priv->nr_pages = 0;			fw_state_start(fw_priv);		}		break;	case 0:		if (fw_sysfs_loading(fw_priv)) {			int rc; 			/*			 * Several loading requests may be pending on			 * one same firmware buf, so let all requests			 * see the mapped 'buf->data' once the loading			 * is completed.			 * */			rc = map_fw_priv_pages(fw_priv);			if (rc)				dev_err(dev, "%s: map pages failed\n",					__func__);			else				rc = security_kernel_post_read_file(NULL,						fw_priv->data, fw_priv->size,						READING_FIRMWARE); 			/*			 * Same logic as fw_load_abort, only the DONE bit			 * is ignored and we set ABORT only on failure.			 */			list_del_init(&fw_priv->pending_list);			if (rc) {				fw_state_aborted(fw_priv);				written = rc;			} else {				fw_state_done(fw_priv);			}			break;		}		/* fallthrough */	default:		dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);		/* fallthrough */	case -1:		fw_load_abort(fw_sysfs);		break;	}out:	mutex_unlock(&fw_lock);	return written;} static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store); static void firmware_rw_data(struct fw_priv *fw_priv, char *buffer,			   loff_t offset, size_t count, bool read){	if (read)		memcpy(buffer, fw_priv->data + offset, count);	else		memcpy(fw_priv->data + offset, buffer, count);} static void firmware_rw(struct fw_priv *fw_priv, char *buffer,			loff_t offset, size_t count, bool read){	while (count) {		void *page_data;		int page_nr = offset >> PAGE_SHIFT;		int page_ofs = offset & (PAGE_SIZE-1);		int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count); 		page_data = kmap(fw_priv->pages[page_nr]); 		if (read)			memcpy(buffer, page_data + page_ofs, page_cnt);		else			memcpy(page_data + page_ofs, buffer, page_cnt); 		kunmap(fw_priv->pages[page_nr]);		buffer += page_cnt;		offset += page_cnt;		count -= page_cnt;	}} static ssize_t firmware_data_read(struct file *filp, struct kobject *kobj,				  struct bin_attribute *bin_attr,				  char *buffer, loff_t offset, size_t count){	struct device *dev = kobj_to_dev(kobj);	struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);	struct fw_priv *fw_priv;	ssize_t ret_count; 	mutex_lock(&fw_lock);	fw_priv = fw_sysfs->fw_priv;	if (!fw_priv || fw_sysfs_done(fw_priv)) {		ret_count = -ENODEV;		goto out;	}	if (offset > fw_priv->size) {		ret_count = 0;		goto out;	}	if (count > fw_priv->size - offset)		count = fw_priv->size - offset; 	ret_count = count; 	if (fw_priv->data)		firmware_rw_data(fw_priv, buffer, offset, count, true);	else		firmware_rw(fw_priv, buffer, offset, count, true); out:	mutex_unlock(&fw_lock);	return ret_count;} static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size){	struct fw_priv *fw_priv= fw_sysfs->fw_priv;	int pages_needed = PAGE_ALIGN(min_size) >> PAGE_SHIFT; 	/* If the array of pages is too small, grow it... */	if (fw_priv->page_array_size < pages_needed) {		int new_array_size = max(pages_needed,					 fw_priv->page_array_size * 2);		struct page **new_pages; 		new_pages = vmalloc(array_size(new_array_size, sizeof(void *)));		if (!new_pages) {			fw_load_abort(fw_sysfs);			return -ENOMEM;		}		memcpy(new_pages, fw_priv->pages,		       fw_priv->page_array_size * sizeof(void *));		memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *		       (new_array_size - fw_priv->page_array_size));		vfree(fw_priv->pages);		fw_priv->pages = new_pages;		fw_priv->page_array_size = new_array_size;	} 	while (fw_priv->nr_pages < pages_needed) {		fw_priv->pages[fw_priv->nr_pages] =			alloc_page(GFP_KERNEL | __GFP_HIGHMEM); 		if (!fw_priv->pages[fw_priv->nr_pages]) {			fw_load_abort(fw_sysfs);			return -ENOMEM;		}		fw_priv->nr_pages++;	}	return 0;} /** * firmware_data_write() - write method for firmware * @filp: open sysfs file * @kobj: kobject for the device * @bin_attr: bin_attr structure * @buffer: buffer being written * @offset: buffer offset for write in total data store area * @count: buffer size * *	Data written to the 'data' attribute will be later handed to *	the driver as a firmware image. **/static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj,				   struct bin_attribute *bin_attr,				   char *buffer, loff_t offset, size_t count){	struct device *dev = kobj_to_dev(kobj);	struct fw_sysfs *fw_sysfs = to_fw_sysfs(dev);	struct fw_priv *fw_priv;	ssize_t retval; 	if (!capable(CAP_SYS_RAWIO))		return -EPERM; 	mutex_lock(&fw_lock);	fw_priv = fw_sysfs->fw_priv;	if (!fw_priv || fw_sysfs_done(fw_priv)) {		retval = -ENODEV;		goto out;	} 	if (fw_priv->data) {		if (offset + count > fw_priv->allocated_size) {			retval = -ENOMEM;			goto out;		}		firmware_rw_data(fw_priv, buffer, offset, count, false);		retval = count;	} else {		retval = fw_realloc_pages(fw_sysfs, offset + count);		if (retval)			goto out; 		retval = count;		firmware_rw(fw_priv, buffer, offset, count, false);	} 	fw_priv->size = max_t(size_t, offset + count, fw_priv->size);out:	mutex_unlock(&fw_lock);	return retval;} static struct bin_attribute firmware_attr_data = {	.attr = { .name = "data", .mode = 0644 },	.size = 0,	.read = firmware_data_read,	.write = firmware_data_write,}; static struct attribute *fw_dev_attrs[] = {	&dev_attr_loading.attr,	NULL}; static struct bin_attribute *fw_dev_bin_attrs[] = {	&firmware_attr_data,	NULL}; static const struct attribute_group fw_dev_attr_group = {	.attrs = fw_dev_attrs,	.bin_attrs = fw_dev_bin_attrs,

Lines 1–500 of 702.