summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaavard Skinnemoen <hskinnemoen@atmel.com>2007-03-21 15:16:50 (GMT)
committerHaavard Skinnemoen <hskinnemoen@atmel.com>2007-04-27 11:44:14 (GMT)
commitf9692b9501c339ec90647d8cd6ee5c106f072f9f (patch)
tree3a11d55a0383d10cb712b31bc18e57585cdeed4c
parentd8011768e6bdd0d9de5cc7bdbd3077b4b4fab8c7 (diff)
downloadlinux-f9692b9501c339ec90647d8cd6ee5c106f072f9f.tar.xz
[AVR32] Reserve framebuffer memory in early_parse_fbmem()
With the current strategy of using the bootmem allocator to allocate or reserve framebuffer memory, there's a slight chance that the requested area has been taken by the boot allocator bitmap before we get around to reserving it. By inserting the framebuffer region as a reserved region as early as possible, we improve our chances for success and we make the region visible as a reserved region in dmesg and /proc/iomem without any extra work. Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
-rw-r--r--arch/avr32/kernel/setup.c68
1 files changed, 61 insertions, 7 deletions
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index d0a35a1..1682e2d 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -191,21 +191,45 @@ find_free_region(const struct resource *mem, resource_size_t size,
return target;
}
+static int __init
+alloc_reserved_region(resource_size_t *start, resource_size_t size,
+ resource_size_t align, const char *name)
+{
+ struct resource *mem;
+ resource_size_t target;
+ int ret;
+
+ for (mem = system_ram; mem; mem = mem->sibling) {
+ target = find_free_region(mem, size, align);
+ if (target <= mem->end) {
+ ret = add_reserved_region(target, target + size - 1,
+ name);
+ if (!ret)
+ *start = target;
+ return ret;
+ }
+ }
+
+ return -ENOMEM;
+}
+
/*
* Early framebuffer allocation. Works as follows:
* - If fbmem_size is zero, nothing will be allocated or reserved.
* - If fbmem_start is zero when setup_bootmem() is called,
- * fbmem_size bytes will be allocated from the bootmem allocator.
+ * a block of fbmem_size bytes will be reserved before bootmem
+ * initialization. It will be aligned to the largest page size
+ * that fbmem_size is a multiple of.
* - If fbmem_start is nonzero, an area of size fbmem_size will be
- * reserved at the physical address fbmem_start if necessary. If
- * the area isn't in a memory region known to the kernel, it will
- * be left alone.
+ * reserved at the physical address fbmem_start if possible. If
+ * it collides with other reserved memory, a different block of
+ * same size will be allocated, just as if fbmem_start was zero.
*
* Board-specific code may use these variables to set up platform data
* for the framebuffer driver if fbmem_size is nonzero.
*/
-static unsigned long __initdata fbmem_start;
-static unsigned long __initdata fbmem_size;
+static resource_size_t __initdata fbmem_start;
+static resource_size_t __initdata fbmem_size;
/*
* "fbmem=xxx[kKmM]" allocates the specified amount of boot memory for
@@ -219,9 +243,39 @@ static unsigned long __initdata fbmem_size;
*/
static int __init early_parse_fbmem(char *p)
{
+ int ret;
+ unsigned long align;
+
fbmem_size = memparse(p, &p);
- if (*p == '@')
+ if (*p == '@') {
fbmem_start = memparse(p, &p);
+ ret = add_reserved_region(fbmem_start,
+ fbmem_start + fbmem_size - 1,
+ "Framebuffer");
+ if (ret) {
+ printk(KERN_WARNING
+ "Failed to reserve framebuffer memory\n");
+ fbmem_start = 0;
+ }
+ }
+
+ if (!fbmem_start) {
+ if ((fbmem_size & 0x000fffffUL) == 0)
+ align = 0x100000; /* 1 MiB */
+ else if ((fbmem_size & 0x0000ffffUL) == 0)
+ align = 0x10000; /* 64 KiB */
+ else
+ align = 0x1000; /* 4 KiB */
+
+ ret = alloc_reserved_region(&fbmem_start, fbmem_size,
+ align, "Framebuffer");
+ if (ret) {
+ printk(KERN_WARNING
+ "Failed to allocate framebuffer memory\n");
+ fbmem_size = 0;
+ }
+ }
+
return 0;
}
early_param("fbmem", early_parse_fbmem);