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