diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 5f61235439e054d9155418a3dc236922a53eac69..584e9a2bfdecd89cc86aa2898d099abeee1e4fd9 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -129,7 +129,7 @@ struct firmware_buf {
phys_addr_t dest_addr;
size_t dest_size;
void * (*map_fw_mem)(phys_addr_t phys, size_t size, void *data);
- void (*unmap_fw_mem)(void *virt, void *data);
+ void (*unmap_fw_mem)(void *virt, size_t size, void *data);
void *map_data;
#ifdef CONFIG_FW_LOADER_USER_HELPER
bool is_paged_buf;
@@ -161,7 +161,7 @@ struct fw_desc {
phys_addr_t dest_addr;
size_t dest_size;
void * (*map_fw_mem)(phys_addr_t phys, size_t size, void *data);
- void (*unmap_fw_mem)(void *virt, void *data);
+ void (*unmap_fw_mem)(void *virt, size_t size, void *data);
void *map_data;
struct module *module;
void *context;
@@ -336,7 +336,8 @@ static bool fw_read_file_contents(struct file *file, struct firmware_buf *fw_buf
return false;
if (kernel_read(file, 0, buf, size) != size) {
if (fw_buf->dest_addr)
- fw_buf->unmap_fw_mem(buf, fw_buf->map_data);
+ fw_buf->unmap_fw_mem(buf, fw_buf->dest_size,
+ fw_buf->map_data);
else
vfree(buf);
return false;
@@ -344,7 +345,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->map_data);
+ fw_buf->unmap_fw_mem(buf, fw_buf->size, fw_buf->map_data);
return true;
}
@@ -709,7 +710,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->map_data);
+ buf->unmap_fw_mem(fw_buf, count, buf->map_data);
out:
return retval;
@@ -1271,7 +1272,8 @@ 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 *data),
- void (*unmap_fw_mem)(void *virt, void *data),
+ void (*unmap_fw_mem)(void *virt, size_t size,
+ void *data),
void *map_data)
{
struct fw_desc desc;
@@ -1339,7 +1341,7 @@ _request_firmware_nowait(
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 *data),
- void (*unmap_fw_mem)(void *virt, void *data),
+ void (*unmap_fw_mem)(void *virt, size_t size, void *data),
void *map_data)
{
struct fw_desc *desc;
@@ -1429,7 +1431,7 @@ request_firmware_nowait_direct(
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 *data),
- void (*unmap_fw_mem)(void *virt, void *data),
+ void (*unmap_fw_mem)(void *virt, size_t size, void *data),
void *map_data)
{
return _request_firmware_nowait(module, uevent, name, device, gfp,
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index b9853300cb472a67c5ff2df4cea4cbeb20f054e8..06fcccfdd3c159b471f47800afa512be5713a4ed 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -363,7 +363,6 @@ static int pil_alloc_region(struct pil_priv *priv, phys_addr_t min_addr,
void *region;
size_t size = max_addr - min_addr;
size_t aligned_size;
- DEFINE_DMA_ATTRS(attrs);
/* Don't reallocate due to fragmentation concerns, just sanity check */
if (priv->region) {
@@ -378,9 +377,12 @@ static int pil_alloc_region(struct pil_priv *priv, phys_addr_t min_addr,
else
aligned_size = ALIGN(size, SZ_1M);
- dma_set_attr(DMA_ATTR_SKIP_ZEROING, &attrs);
+ dma_set_attr(DMA_ATTR_SKIP_ZEROING, &priv->desc->attrs);
+ dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &priv->desc->attrs);
+
region = dma_alloc_attrs(priv->desc->dev, aligned_size,
- &priv->region_start, GFP_KERNEL, &attrs);
+ &priv->region_start, GFP_KERNEL,
+ &priv->desc->attrs);
if (region == NULL) {
pil_err(priv->desc, "Failed to allocate relocatable region of size %zx\n",
@@ -523,29 +525,25 @@ static void pil_release_mmap(struct pil_desc *desc)
#define IOMAP_SIZE SZ_1M
struct pil_map_fw_info {
- int relocated;
void *region;
+ struct dma_attrs attrs;
phys_addr_t base_addr;
+ struct device *dev;
};
static void *map_fw_mem(phys_addr_t paddr, size_t size, void *data)
{
struct pil_map_fw_info *info = data;
- if (info && info->relocated && info->region)
- return info->region + (paddr - info->base_addr);
-
- return ioremap(paddr, size);
+ return dma_remap(info->dev, info->region, paddr, size,
+ &info->attrs);
}
-static void unmap_fw_mem(void *vaddr, void *data)
+static void unmap_fw_mem(void *vaddr, size_t size, void *data)
{
struct pil_map_fw_info *info = data;
- if (info && info->relocated && info->region)
- return;
-
- iounmap(vaddr);
+ dma_unremap(info->dev, vaddr, size);
}
static int pil_load_seg(struct pil_desc *desc, struct pil_seg *seg)
@@ -555,9 +553,10 @@ static int pil_load_seg(struct pil_desc *desc, struct pil_seg *seg)
char fw_name[30];
int num = seg->num;
struct pil_map_fw_info map_fw_info = {
- .relocated = seg->relocated,
+ .attrs = desc->attrs,
.region = desc->priv->region,
.base_addr = desc->priv->region_start,
+ .dev = desc->dev,
};
void *map_data = desc->map_data ? desc->map_data : &map_fw_info;
@@ -612,7 +611,7 @@ static int pil_load_seg(struct pil_desc *desc, struct pil_seg *seg)
memset(buf, 0, size);
- desc->unmap_fw_mem(buf, map_data);
+ desc->unmap_fw_mem(buf, size, map_data);
count -= orig_size;
paddr += orig_size;
@@ -714,6 +713,8 @@ int pil_boot(struct pil_desc *desc)
goto release_fw;
}
+ init_dma_attrs(&desc->attrs);
+
ret = pil_init_mmap(desc, mdt);
if (ret)
goto release_fw;
@@ -765,8 +766,9 @@ out:
up_read(&pil_pm_rwsem);
if (ret) {
if (priv->region) {
- dma_free_coherent(desc->dev, priv->region_size,
- priv->region, priv->region_start);
+ dma_free_attrs(desc->dev, priv->region_size,
+ priv->region, priv->region_start,
+ &desc->attrs);
priv->region = NULL;
}
pil_release_mmap(desc);
@@ -796,8 +798,8 @@ void pil_shutdown(struct pil_desc *desc)
flush_delayed_work(&priv->proxy);
if (priv->region) {
- dma_free_coherent(desc->dev, priv->region_size,
- priv->region, priv->region_start);
+ dma_free_attrs(desc->dev, priv->region_size,
+ priv->region, priv->region_start, &desc->attrs);
priv->region = NULL;
}
}
diff --git a/drivers/soc/qcom/peripheral-loader.h b/drivers/soc/qcom/peripheral-loader.h
index 68b3659e14b3f750aa5cb63087fadac8f9e8993f..9cb791fc32ef1de1a4d96d674083706405650059 100644
--- a/drivers/soc/qcom/peripheral-loader.h
+++ b/drivers/soc/qcom/peripheral-loader.h
@@ -12,6 +12,8 @@
#ifndef __MSM_PERIPHERAL_LOADER_H
#define __MSM_PERIPHERAL_LOADER_H
+#include <linux/dma-attrs.h>
+
struct device;
struct module;
struct pil_priv;
@@ -25,6 +27,7 @@ struct pil_priv;
* @proxy_timeout: delay in ms until proxy vote is removed
* @flags: bitfield for image flags
* @priv: DON'T USE - internal only
+ * @attrs: DMA attributes to be used during dma allocation.
* @proxy_unvote_irq: IRQ to trigger a proxy unvote. proxy_timeout
* is ignored if this is set.
* @map_fw_mem: Custom function used to map physical address space to virtual.
@@ -41,9 +44,10 @@ struct pil_desc {
unsigned long flags;
#define PIL_SKIP_ENTRY_CHECK BIT(0)
struct pil_priv *priv;
+ struct dma_attrs attrs;
unsigned int proxy_unvote_irq;
void * (*map_fw_mem)(phys_addr_t phys, size_t size, void *data);
- void (*unmap_fw_mem)(void *virt, void *data);
+ void (*unmap_fw_mem)(void *virt, size_t size, void *data);
void *map_data;
};
diff --git a/include/linux/firmware.h b/include/linux/firmware.h
index 89b23a831ce70518445aad9c1331ba557c6b84e6..56672339c6cf4af2a6c13b7a5161fe619bac35b7 100644
--- a/include/linux/firmware.h
+++ b/include/linux/firmware.h
@@ -49,7 +49,8 @@ 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 *data),
- void (*unmap_fw_mem)(void *virt, void *data),
+ void (*unmap_fw_mem)(void *virt, size_t size,
+ void *data),
void *data);
int request_firmware_nowait_direct(
struct module *module, bool uevent,
@@ -57,7 +58,7 @@ int request_firmware_nowait_direct(
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 *data),
- void (*unmap_fw_mem)(void *virt, void *data), void *data);
+ void (*unmap_fw_mem)(void *virt, size_t size, void *data), void *data);
void release_firmware(const struct firmware *fw);
int cache_firmware(const char *name);
int uncache_firmware(const char *name);