Discussion:
is remap_pfn_range should align to 2(n) * (page size) ?
zhuzhenhua
2008-05-09 06:54:29 UTC
Permalink
hello all
i have a sensor driver want to malloc 2.xM SDRAM to capture
data(using DMA), so i used remap_pfn_range to malloc 3M.
But in /proc/meminfo, it showes free memory reduce 4M. i also check the
/proc/buddyinfo, it seemes too.
(i am looking inside kernel code, but not get clear at now).

is remap_pfn_range should align to 2(n) * (page size) ?

thanks for any hints

zzh
Ralf Baechle
2008-05-09 09:56:05 UTC
Permalink
Post by zhuzhenhua
i have a sensor driver want to malloc 2.xM SDRAM to capture
data(using DMA), so i used remap_pfn_range to malloc 3M.
But in /proc/meminfo, it showes free memory reduce 4M. i also check the
/proc/buddyinfo, it seemes too.
(i am looking inside kernel code, but not get clear at now).
is remap_pfn_range should align to 2(n) * (page size) ?
This has nothing to do with remap_pfn_range but with the power of two
sized buckets used by the global free page pool. Any allocation with
get_free_pages will be rounded up to the next power of two. If that's a
real concern for you you could allocate a 4MB page then split the page
into a 2MB and two 1MB pages and free the 1MB page again.

Ralf
zhuzhenhua
2008-05-12 02:18:27 UTC
Permalink
Post by Ralf Baechle
Post by zhuzhenhua
i have a sensor driver want to malloc 2.xM SDRAM to capture
data(using DMA), so i used remap_pfn_range to malloc 3M.
But in /proc/meminfo, it showes free memory reduce 4M. i also check the
/proc/buddyinfo, it seemes too.
(i am looking inside kernel code, but not get clear at now).
is remap_pfn_range should align to 2(n) * (page size) ?
This has nothing to do with remap_pfn_range but with the power of two
sized buckets used by the global free page pool. Any allocation with
get_free_pages will be rounded up to the next power of two. If that's a
real concern for you you could allocate a 4MB page then split the page
into a 2MB and two 1MB pages and free the 1MB page again.
Ralf
thanks for your reply , i see in get_frree_pages and free_pages there is a
get_order(size).
but i don't understand " allocate a 4MB page then split the page
into a 2MB and two 1MB pages and free the 1MB page again."
is there any function to split it?

thanks for any hints

Best Regards


zzh
Ralf Baechle
2008-05-12 11:22:33 UTC
Permalink
Post by zhuzhenhua
Post by Ralf Baechle
This has nothing to do with remap_pfn_range but with the power of two
sized buckets used by the global free page pool. Any allocation with
get_free_pages will be rounded up to the next power of two. If that's a
real concern for you you could allocate a 4MB page then split the page
into a 2MB and two 1MB pages and free the 1MB page again.
thanks for your reply , i see in get_frree_pages and free_pages there is a
get_order(size).
but i don't understand " allocate a 4MB page then split the page
into a 2MB and two 1MB pages and free the 1MB page again."
is there any function to split it?
No, you'd have to code that yourself. Take a look at split_page() which
splits an order n page into order 0 pages. You'd want something similar
but splitting for some non-zero order.

Ralf
zhuzhenhua
2008-05-13 11:44:06 UTC
Permalink
Post by Ralf Baechle
Post by zhuzhenhua
Post by Ralf Baechle
This has nothing to do with remap_pfn_range but with the power of two
sized buckets used by the global free page pool. Any allocation with
get_free_pages will be rounded up to the next power of two. If that's
a
Post by zhuzhenhua
Post by Ralf Baechle
real concern for you you could allocate a 4MB page then split the page
into a 2MB and two 1MB pages and free the 1MB page again.
thanks for your reply , i see in get_frree_pages and free_pages there is
a
Post by zhuzhenhua
get_order(size).
but i don't understand " allocate a 4MB page then split the page
into a 2MB and two 1MB pages and free the 1MB page again."
is there any function to split it?
No, you'd have to code that yourself. Take a look at split_page() which
splits an order n page into order 0 pages. You'd want something similar
but splitting for some non-zero order.
Ralf
thanks for your advice, i found in newest kernel version, in some arch , the
dma_alloc_coherent will call split_page.
because my kernel version is 2.6.14, so i first patch a split_page patch as
follow:
http://www.kernel.org/pub/linux/kernel/people/npiggin/patches/lockless/2.6.16-rc5/broken-out/mm-split-highorder.patch

but it seemes that there is still no split_page in
dma_alloc_coherent/dma_alloc_noncoherent
so i copy from other arch code to arch/mips/mm/dma-noncoherent.c (attach at
the end of mail)
and now my driver just use dma_alloc_coherent malloc 3M directly, and it
seemes ok.
i just wonder why mips arch dma_alloc_coherent/dma_alloc_nocoherent do not
call split_page while other arch calling.

thanks for any hints.

Best Regards

zzh






modify on dma-noncoherent.c
--- dma-noncoherent.c 2008-05-13 19:31:58.131375500 +0800
+++ dma-noncoherent-split.c 2008-05-13 19:31:51.039745500 +0800
@@ -16,27 +16,59 @@

#include <asm/cache.h>
#include <asm/io.h>
+
+static struct page *__dma_alloc(struct device *dev, size_t size,
+ dma_addr_t *handle, gfp_t gfp)
+{
+ struct page *page, *free, *end;
+ int order;
+
+ size = PAGE_ALIGN(size);
+ order = get_order(size);
+ page = alloc_pages(gfp, order);
+ if (!page)
+ return NULL;
+ split_page(page, order);
+
+ *handle = page_to_phys(page);
+ free = page + (size >> PAGE_SHIFT);
+ end = page + (1 << order);

-/*
- * Warning on the terminology - Linux calls an uncached area coherent;
- * MIPS terminology calls memory areas with hardware maintained coherency
- * coherent.
- */
+ /*
+ * Free any unused pages
+ */
+ while (free < end) {
+ __free_page(free);
+ free++;
+ }
+
+ return page;
+}
+
+static void __dma_free(struct device *dev, size_t size,
+ struct page *page, dma_addr_t handle)
+{
+ struct page *end = page + (PAGE_ALIGN(size) >> PAGE_SHIFT);

+ while (page < end)
+ __free_page(page++);
+}
void *dma_alloc_noncoherent(struct device *dev, size_t size,
dma_addr_t * dma_handle, unsigned int __nocast gfp)
{
+ struct page *page;
void *ret;
/* ignore region specifiers */
gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);

if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
gfp |= GFP_DMA;
- ret = (void *) __get_free_pages(gfp, get_order(size));
-
+ page = __dma_alloc(dev, size, dma_handle, gfp);
+ if (page)
+ ret = KSEG1ADDR(page_to_phys(page));
+ printk("ret in dma_alloc_noncoherent = 0x%x\n",ret);
if (ret != NULL) {
memset(ret, 0, size);
- *dma_handle = virt_to_phys(ret);
}

return ret;
@@ -63,19 +95,17 @@
void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
dma_addr_t dma_handle)
{
- free_pages((unsigned long) vaddr, get_order(size));
+ void *addr = KSEG0ADDR(vaddr);
+ struct page *page;
+ BUG_ON(!virt_addr_valid(addr));
+ page = virt_to_page(addr);
+ __dma_free(dev, size, page, dma_handle);
}

EXPORT_SYMBOL(dma_free_noncoherent);

void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
- dma_addr_t dma_handle)
-{
- unsigned long addr = (unsigned long) vaddr;
-
- addr = CAC_ADDR(addr);
- free_pages(addr, get_order(size));
-}
+ dma_addr_t dma_handle) __attribute__((alias("dma_free_noncoherent")));

EXPORT_SYMBOL(dma_free_coherent);
Ralf Baechle
2008-05-13 17:23:01 UTC
Permalink
Post by zhuzhenhua
thanks for your advice, i found in newest kernel version, in some arch , the
dma_alloc_coherent will call split_page.
because my kernel version is 2.6.14, so i first patch a split_page patch as
http://www.kernel.org/pub/linux/kernel/people/npiggin/patches/lockless/2.6.16-rc5/broken-out/mm-split-highorder.patch
but it seemes that there is still no split_page in
dma_alloc_coherent/dma_alloc_noncoherent
so i copy from other arch code to arch/mips/mm/dma-noncoherent.c (attach at
the end of mail)
and now my driver just use dma_alloc_coherent malloc 3M directly, and it
seemes ok.
i just wonder why mips arch dma_alloc_coherent/dma_alloc_nocoherent do not
call split_page while other arch calling.
I have not identified the waste of memory as a big problem for typical
MIPS systems yet.

The 3MB requirement of your device is sort of odd because it's not a power
of two. Have you considered splitting the allocation into a 2MB and a 1MB
allocation or would that be undersirable?

Ralf
zhuzhenhua
2008-05-14 01:19:10 UTC
Permalink
Post by zhuzhenhua
Post by zhuzhenhua
thanks for your advice, i found in newest kernel version, in some arch ,
the
Post by zhuzhenhua
dma_alloc_coherent will call split_page.
because my kernel version is 2.6.14, so i first patch a split_page patch
as
http://www.kernel.org/pub/linux/kernel/people/npiggin/patches/lockless/2.6.16-rc5/broken-out/mm-split-highorder.patch
Post by zhuzhenhua
but it seemes that there is still no split_page in
dma_alloc_coherent/dma_alloc_noncoherent
so i copy from other arch code to arch/mips/mm/dma-noncoherent.c (attach
at
Post by zhuzhenhua
the end of mail)
and now my driver just use dma_alloc_coherent malloc 3M directly, and it
seemes ok.
i just wonder why mips arch dma_alloc_coherent/dma_alloc_nocoherent do
not
Post by zhuzhenhua
call split_page while other arch calling.
I have not identified the waste of memory as a big problem for typical
MIPS systems yet.
The 3MB requirement of your device is sort of odd because it's not a power
of two. Have you considered splitting the allocation into a 2MB and a 1MB
allocation or would that be undersirable?
Ralf
Thanks for your reply.
Our board is for embedded system , It only have 32M sdram and we don't want
to
waste 1M sdram. My sensor driver need about 2.5xM memory to capture a
picture
by DMA (our DMA controller do not support scatter/gather).

I also can use bootargs "mem=29M" to keep 3M sdram. but it's not flexible
as
passing a param to driver module(calling dma_alloc_coherent). maybe my
situation
is not common for MIPS arch. so that's is no split_page in
dma_alloc_coherent.
and now after patch,it seemes ok for me.

Best Regards

zzh
Geert Uytterhoeven
2008-05-14 07:33:58 UTC
Permalink
Post by zhuzhenhua
Post by zhuzhenhua
Post by zhuzhenhua
thanks for your advice, i found in newest kernel version, in some arch ,
the
Post by zhuzhenhua
dma_alloc_coherent will call split_page.
because my kernel version is 2.6.14, so i first patch a split_page patch
as
http://www.kernel.org/pub/linux/kernel/people/npiggin/patches/lockless/2.6.16-rc5/broken-out/mm-split-highorder.patch
Post by zhuzhenhua
but it seemes that there is still no split_page in
dma_alloc_coherent/dma_alloc_noncoherent
so i copy from other arch code to arch/mips/mm/dma-noncoherent.c (attach
at
Post by zhuzhenhua
the end of mail)
and now my driver just use dma_alloc_coherent malloc 3M directly, and it
seemes ok.
i just wonder why mips arch dma_alloc_coherent/dma_alloc_nocoherent do
not
Post by zhuzhenhua
call split_page while other arch calling.
I have not identified the waste of memory as a big problem for typical
MIPS systems yet.
The 3MB requirement of your device is sort of odd because it's not a power
of two. Have you considered splitting the allocation into a 2MB and a 1MB
allocation or would that be undersirable?
Thanks for your reply.
Our board is for embedded system , It only have 32M sdram and we don't want
to
waste 1M sdram. My sensor driver need about 2.5xM memory to capture a
picture
by DMA (our DMA controller do not support scatter/gather).
I also can use bootargs "mem=29M" to keep 3M sdram. but it's not flexible
as
passing a param to driver module(calling dma_alloc_coherent). maybe my
situation
is not common for MIPS arch. so that's is no split_page in
dma_alloc_coherent.
and now after patch,it seemes ok for me.
One other issue is that bootargs "mem=29M" is guaranteed to give you 3
MiB for your device, while dma_alloc_coherent() may fail if memory is
too fragmented.

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- ***@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

Loading...