From ad4a4c1da574643eed696f1d86788e8a7a7982b5 Mon Sep 17 00:00:00 2001 From: Vikram Mulukutla <markivx@codeaurora.org> Date: Thu, 10 Apr 2014 20:23:30 -0700 Subject: [PATCH] firmware_class: Allow private data in [unmap|map]_fw_mem Some callers of request_firmware_direct may need additional context to be able to map firmware memory. Allow private data to be passed in with request_firmware_direct, and send this data along with the [unmap|map]_fw_mem callbacks. Change-Id: I05a15eb46cc663a4476b784e30e80182a28e10c3 Signed-off-by: Vikram Mulukutla <markivx@codeaurora.org> --- drivers/base/firmware_class.c | 45 +++++++++++++++++----------- drivers/soc/qcom/peripheral-loader.c | 6 ++-- drivers/soc/qcom/peripheral-loader.h | 4 +-- drivers/soc/qcom/pil-femto-modem.c | 4 +-- include/linux/firmware.h | 18 ++++++----- 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index f0493028fc75..5f61235439e0 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -128,8 +128,9 @@ struct firmware_buf { size_t size; phys_addr_t dest_addr; size_t dest_size; - void * (*map_fw_mem)(phys_addr_t phys, size_t size); - void (*unmap_fw_mem)(void *virt); + void * (*map_fw_mem)(phys_addr_t phys, size_t size, void *data); + void (*unmap_fw_mem)(void *virt, void *data); + void *map_data; #ifdef CONFIG_FW_LOADER_USER_HELPER bool is_paged_buf; struct page **pages; @@ -159,8 +160,9 @@ struct fw_desc { bool nocache; phys_addr_t dest_addr; size_t dest_size; - void * (*map_fw_mem)(phys_addr_t phys, size_t size); - void (*unmap_fw_mem)(void *virt); + void * (*map_fw_mem)(phys_addr_t phys, size_t size, void *data); + void (*unmap_fw_mem)(void *virt, void *data); + void *map_data; struct module *module; void *context; void (*cont)(const struct firmware *fw, void *context); @@ -327,14 +329,14 @@ static bool fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf if (fw_buf->dest_addr) buf = fw_buf->map_fw_mem(fw_buf->dest_addr, - fw_buf->dest_size); + fw_buf->dest_size, fw_buf->map_data); else buf = vmalloc(size); if (!buf) return false; if (kernel_read(file, 0, buf, size) != size) { if (fw_buf->dest_addr) - fw_buf->unmap_fw_mem(buf); + fw_buf->unmap_fw_mem(buf, fw_buf->map_data); else vfree(buf); return false; @@ -342,7 +344,7 @@ static bool fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf fw_buf->data = buf; fw_buf->size = size; if (fw_buf->dest_addr) - fw_buf->unmap_fw_mem(buf); + fw_buf->unmap_fw_mem(buf, fw_buf->map_data); return true; } @@ -693,7 +695,8 @@ static int __firmware_data_rw(struct firmware_priv *fw_priv, char *buffer, goto out; } - fw_buf = buf->map_fw_mem(buf->dest_addr + *offset, count); + fw_buf = buf->map_fw_mem(buf->dest_addr + *offset, count, + buf->map_data); if (!fw_buf) { pr_debug("%s: Failed ioremap.\n", __func__); retval = -ENOMEM; @@ -706,7 +709,7 @@ static int __firmware_data_rw(struct firmware_priv *fw_priv, char *buffer, memcpy(fw_buf, buffer, count); *offset += count; - buf->unmap_fw_mem(fw_buf); + buf->unmap_fw_mem(fw_buf, buf->map_data); out: return retval; @@ -1103,6 +1106,7 @@ _request_firmware_prepare(struct firmware **firmware_p, struct fw_desc *desc) buf->dest_size = desc->dest_size; buf->map_fw_mem = desc->map_fw_mem; buf->unmap_fw_mem = desc->unmap_fw_mem; + buf->map_data = desc->map_data; firmware->priv = buf; return 1; } @@ -1265,8 +1269,10 @@ request_firmware(const struct firmware **firmware_p, const char *name, int request_firmware_direct(const char *name, struct device *device, phys_addr_t dest_addr, size_t dest_size, - void * (*map_fw_mem)(phys_addr_t phys, size_t size), - void (*unmap_fw_mem)(void *virt)) + void * (*map_fw_mem)(phys_addr_t phys, size_t size, + void *data), + void (*unmap_fw_mem)(void *virt, void *data), + void *map_data) { struct fw_desc desc; const struct firmware *fp = NULL; @@ -1287,6 +1293,7 @@ request_firmware_direct(const char *name, struct device *device, desc.dest_size = dest_size; desc.map_fw_mem = map_fw_mem; desc.unmap_fw_mem = unmap_fw_mem; + desc.map_data = map_data; ret = _request_firmware(&desc); if (ret) @@ -1331,8 +1338,9 @@ _request_firmware_nowait( const char *name, struct device *device, gfp_t gfp, void *context, void (*cont)(const struct firmware *fw, void *context), bool nocache, phys_addr_t dest_addr, size_t dest_size, - void * (*map_fw_mem)(phys_addr_t phys, size_t size), - void (*unmap_fw_mem)(void *virt)) + void * (*map_fw_mem)(phys_addr_t phys, size_t size, void *data), + void (*unmap_fw_mem)(void *virt, void *data), + void *map_data) { struct fw_desc *desc; @@ -1356,6 +1364,7 @@ _request_firmware_nowait( desc->dest_size = dest_size; desc->map_fw_mem = map_fw_mem; desc->unmap_fw_mem = unmap_fw_mem; + desc->map_data = map_data; if (!try_module_get(module)) { kfree(desc); @@ -1400,7 +1409,7 @@ request_firmware_nowait( { return _request_firmware_nowait(module, uevent, name, device, gfp, - context, cont, false, 0, 0, NULL, NULL); + context, cont, false, 0, 0, NULL, NULL, NULL); } /** @@ -1419,12 +1428,14 @@ request_firmware_nowait_direct( const char *name, struct device *device, gfp_t gfp, void *context, void (*cont)(const struct firmware *fw, void *context), phys_addr_t dest_addr, size_t dest_size, - void * (*map_fw_mem)(phys_addr_t phys, size_t size), - void (*unmap_fw_mem)(void *virt)) + void * (*map_fw_mem)(phys_addr_t phys, size_t size, void *data), + void (*unmap_fw_mem)(void *virt, void *data), + void *map_data) { return _request_firmware_nowait(module, uevent, name, device, gfp, context, cont, true, dest_addr, - dest_size, map_fw_mem, unmap_fw_mem); + dest_size, map_fw_mem, unmap_fw_mem, + map_data); } /** diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c index 6e6f50cfc532..3590ffca6198 100644 --- a/drivers/soc/qcom/peripheral-loader.c +++ b/drivers/soc/qcom/peripheral-loader.c @@ -531,12 +531,12 @@ static void pil_release_mmap(struct pil_desc *desc) #define IOMAP_SIZE SZ_1M -static void *map_fw_mem(phys_addr_t paddr, size_t size) +static void *map_fw_mem(phys_addr_t paddr, size_t size, void *data) { return ioremap(paddr, size); } -static void unmap_fw_mem(void *vaddr) +static void unmap_fw_mem(void *vaddr, void *data) { iounmap(vaddr); } @@ -553,7 +553,7 @@ static int pil_load_seg(struct pil_desc *desc, struct pil_seg *seg) desc->name, num); ret = request_firmware_direct(fw_name, desc->dev, seg->paddr, seg->filesz, desc->map_fw_mem, - desc->unmap_fw_mem); + desc->unmap_fw_mem, NULL); if (ret < 0) { pil_err(desc, "Failed to locate blob %s or blob is too big.\n", fw_name); diff --git a/drivers/soc/qcom/peripheral-loader.h b/drivers/soc/qcom/peripheral-loader.h index 4dc198128bb4..0a50ef5aefc1 100644 --- a/drivers/soc/qcom/peripheral-loader.h +++ b/drivers/soc/qcom/peripheral-loader.h @@ -42,8 +42,8 @@ struct pil_desc { #define PIL_SKIP_ENTRY_CHECK BIT(0) struct pil_priv *priv; unsigned int proxy_unvote_irq; - void * (*map_fw_mem)(phys_addr_t phys, size_t size); - void (*unmap_fw_mem)(void *virt); + void * (*map_fw_mem)(phys_addr_t phys, size_t size, void *data); + void (*unmap_fw_mem)(void *virt, void *data); }; /** diff --git a/drivers/soc/qcom/pil-femto-modem.c b/drivers/soc/qcom/pil-femto-modem.c index e2bea490f168..579cc20eb6ac 100644 --- a/drivers/soc/qcom/pil-femto-modem.c +++ b/drivers/soc/qcom/pil-femto-modem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -122,7 +122,7 @@ struct femto_modem_data { #define POLL_INTERVAL_US 50 #define TIMEOUT_US 1000000 -static void *pil_femto_modem_map_fw_mem(phys_addr_t paddr, size_t size) +static void *pil_femto_modem_map_fw_mem(phys_addr_t paddr, size_t size, void *d) { /* Due to certain memory areas on the platform requiring 32-bit wide * accesses, we must cache the firmware to avoid bus errors. diff --git a/include/linux/firmware.h b/include/linux/firmware.h index ddca055c712a..89b23a831ce7 100644 --- a/include/linux/firmware.h +++ b/include/linux/firmware.h @@ -48,15 +48,16 @@ int request_firmware_nowait( int request_firmware_direct(const char *name, struct device *device, phys_addr_t dest_addr, size_t dest_size, void * (*map_fw_mem)(phys_addr_t phys, - size_t size), - void (*unmap_fw_mem)(void *virt)); + size_t size, void *data), + void (*unmap_fw_mem)(void *virt, void *data), + void *data); int request_firmware_nowait_direct( struct module *module, bool uevent, const char *name, struct device *device, gfp_t gfp, void *context, void (*cont)(const struct firmware *fw, void *context), phys_addr_t dest_addr, size_t dest_size, - void * (*map_fw_mem)(phys_addr_t phys, size_t size), - void (*unmap_fw_mem)(void *virt)); + void * (*map_fw_mem)(phys_addr_t phys, size_t size, void *data), + void (*unmap_fw_mem)(void *virt, void *data), void *data); void release_firmware(const struct firmware *fw); int cache_firmware(const char *name); int uncache_firmware(const char *name); @@ -72,8 +73,9 @@ static inline int request_firmware_direct(const char *name, phys_addr_t dest_addr, size_t dest_size, void * (*map_fw_mem)(phys_addr_t phys, - size_t size), - void (*unmap_fw_mem)(void *virt)) + size_t size, void *data), + void (*unmap_fw_mem)(void *virt), + void *data) { return -EINVAL; } @@ -89,8 +91,8 @@ static inline int request_firmware_nowait_direct( const char *name, struct device *device, gfp_t gfp, void *context, void (*cont)(const struct firmware *fw, void *context), phys_addr_t dest_addr, size_t dest_size, - void * (*map_fw_mem)(phys_addr_t phys, size_t size), - void (*unmap_fw_mem)(void *virt)) + void * (*map_fw_mem)(phys_addr_t phys, size_t size, void *data), + void (*unmap_fw_mem)(void *virt, void *data), void *data) { return -EINVAL; } -- GitLab