summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Mossberg <johan.xx.mossberg@stericsson.com>2011-03-31 17:19:22 +0200
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:03:42 +0200
commit230963b2e963ec9fe9b3302b654bb932ac259345 (patch)
tree4f3f0c854fb4c351fa93dea1f1b6d5beea7a0972
parentedb315559d342cb71a18d1f5a40713f139292df8 (diff)
HWMEM: Alloc kernel vaddrs on boot
By allocating all the kernel virtual addresses on boot fragmentation of the vmalloc area can not cause HWMEM allocs to fail. ST-Ericsson ID: 333457 ST-Ericsson FOSS-OUT ID: STETL-FOSS-OUT-10068 Change-Id: I04a8b4a2804df9a9bbad24e4874107f86a1efdb9 Signed-off-by: Johan Mossberg <johan.xx.mossberg@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/19682 Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
-rw-r--r--drivers/misc/hwmem/hwmem-main.c81
1 files changed, 48 insertions, 33 deletions
diff --git a/drivers/misc/hwmem/hwmem-main.c b/drivers/misc/hwmem/hwmem-main.c
index 9223bdd013b..96cca3735dd 100644
--- a/drivers/misc/hwmem/hwmem-main.c
+++ b/drivers/misc/hwmem/hwmem-main.c
@@ -59,6 +59,7 @@ struct hwmem_alloc {
static struct platform_device *hwdev;
static u32 hwmem_paddr;
+static void *hwmem_kaddr;
static u32 hwmem_size;
static LIST_HEAD(alloc_list);
@@ -307,60 +308,67 @@ static void clean_alloc_list(void)
}
}
-static int kmap_alloc(struct hwmem_alloc *alloc)
+static int alloc_kaddrs(void)
{
- int ret;
- pgprot_t pgprot;
-
- struct vm_struct *area = get_vm_area(alloc->size, VM_IOREMAP);
+ struct vm_struct *area = get_vm_area(hwmem_size, VM_IOREMAP);
if (area == NULL) {
- dev_info(&hwdev->dev, "Failed to allocate %u bytes virtual"
- " memory", alloc->size);
+ dev_info(&hwdev->dev, "Failed to allocate %u bytes kernel"
+ " virtual memory", hwmem_size);
return -ENOMSG;
}
- pgprot = PAGE_KERNEL;
- cach_set_pgprot_cache_options(&alloc->cach_buf, &pgprot);
+ hwmem_kaddr = area->addr;
- ret = ioremap_page_range((unsigned long)area->addr,
- (unsigned long)area->addr + alloc->size, alloc->paddr, pgprot);
- if (ret < 0) {
- dev_info(&hwdev->dev, "Failed to map %#x - %#x", alloc->paddr,
- alloc->paddr + alloc->size);
- goto failed_to_map;
- }
+ return 0;
+}
- alloc->kaddr = area->addr;
+static void free_kaddrs(void)
+{
+ struct vm_struct *area;
- return 0;
+ if (hwmem_kaddr == NULL)
+ return;
-failed_to_map:
- area = remove_vm_area(area->addr);
+ area = remove_vm_area(hwmem_kaddr);
if (area == NULL)
dev_err(&hwdev->dev,
- "Failed to unmap alloc, resource leak!\n");
+ "Failed to free kernel virtual memory,"
+ " resource leak!\n");
kfree(area);
- return ret;
+ hwmem_kaddr = NULL;
}
-static void kunmap_alloc(struct hwmem_alloc *alloc)
+static int kmap_alloc(struct hwmem_alloc *alloc)
{
- struct vm_struct *area;
+ int ret;
+ pgprot_t pgprot;
+ void *alloc_kaddr = hwmem_kaddr + get_alloc_offset(alloc);
- if (alloc->kaddr == NULL)
- return;
+ pgprot = PAGE_KERNEL;
+ cach_set_pgprot_cache_options(&alloc->cach_buf, &pgprot);
- area = remove_vm_area(alloc->kaddr);
- if (area == NULL) {
- dev_err(&hwdev->dev,
- "Failed to unmap alloc, resource leak!\n");
- return;
+ ret = ioremap_page_range((unsigned long)alloc_kaddr,
+ (unsigned long)alloc_kaddr + alloc->size, alloc->paddr,
+ pgprot);
+ if (ret < 0) {
+ dev_info(&hwdev->dev, "Failed to map %#x - %#x", alloc->paddr,
+ alloc->paddr + alloc->size);
+ return ret;
}
- kfree(area);
+ alloc->kaddr = alloc_kaddr;
+ return 0;
+}
+
+static void kunmap_alloc(struct hwmem_alloc *alloc)
+{
+ if (alloc->kaddr == NULL)
+ return;
+
+ unmap_kernel_range((unsigned long)alloc->kaddr, alloc->size);
alloc->kaddr = NULL;
}
@@ -386,7 +394,8 @@ struct hwmem_alloc *hwmem_alloc(u32 size, enum hwmem_alloc_flags flags,
alloc = find_free_alloc_bestfit(size);
if (IS_ERR(alloc)) {
- dev_info(&hwdev->dev, "Allocation failed, no free slot\n");
+ dev_info(&hwdev->dev, "Could not find slot for %u bytes"
+ " allocation\n", size);
goto no_slot;
}
@@ -800,6 +809,10 @@ static int __devinit hwmem_probe(struct platform_device *pdev)
hwmem_paddr = platform_data->start;
hwmem_size = platform_data->size;
+ ret = alloc_kaddrs();
+ if (ret < 0)
+ goto alloc_kaddrs_failed;
+
/*
* No need to flush the caches here. If we can keep track of the cache
* content then none of our memory will be in the caches, if we can't
@@ -827,6 +840,8 @@ static int __devinit hwmem_probe(struct platform_device *pdev)
ioctl_init_failed:
clean_alloc_list();
init_alloc_list_failed:
+ free_kaddrs();
+alloc_kaddrs_failed:
hwdev = NULL;
out: