使用dma_alloc_writecombine申请内存空间大小的限制
来源:互联网 发布:我的校园软件 编辑:程序博客网 时间:2024/05/21 15:03
最近在调TFT分辨率,当使用1024x768 16bpp时正常,而当调整为1024x768 24bpp时报"Failed to allocate video memory"的错误.
出错的地方是在分配显示缓冲区.代码如下:
static __inline int allocate_video_memory_map(struct fb_info *fbinfo)
{
...
fbinfo->screen_base = dma_alloc_writecombine(fbi->dev, map_size, (dma_addr_t *)&fbinfo->fix.smem_start, GFP_KERNEL);
if (!fbinfo->screen_base) {
return -ENOMEM;
}
return 0;
}
...
{
ret = allocate_video_memory_map(fbinfo);
if (ret) {
dev_err(fbi->dev, "Failed to allocate video memory ma (%d)\n", ret);
return -ENOMEM;
}
}
dma_alloc_writecombine函数
/*
* Allocate DMA-coherent memory space and return both the kernel remapped
* virtual and bus address for that space.
*/
void *
dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
{
void *memory;
if (dma_alloc_from_coherent(dev, size, handle, &memory))
return memory;
if (arch_is_coherent()) {
void *virt;
virt = kmalloc(size, gfp);
if (!virt)
return NULL;
*handle = virt_to_dma(dev, virt);
return virt;
}
return __dma_alloc(dev, size, handle, gfp,
pgprot_noncached(pgprot_kernel));
}
EXPORT_SYMBOL(dma_alloc_coherent);
/*
* Allocate a writecombining region, in much the same way as
* dma_alloc_coherent above.
*/
void *
dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
{
return __dma_alloc(dev, size, handle, gfp,
pgprot_writecombine(pgprot_kernel));
}
EXPORT_SYMBOL(dma_alloc_writecombine);
由上方代码可以看出,两个函数都调用了__dma_alloc函数,差别只在于最后一个参数。
dma_alloc_coherent 在 arm 平台上会禁止页表项中的 C (Cacheable) 域以及 B (Bufferable)域。而 dma_alloc_writecombine 只禁止 C (Cacheable) 域.
C 代表是否应用高速缓冲存储器, 而 B 代表是否应用写缓冲区。
如许,dma_alloc_writecombine 分派出来的内存不应用缓存,然则会应用写缓冲区。而 dma_alloc_coherent 则二者都不应用。
C B 位的具体含义
0 0 无cache,无写缓冲;任何对memory的读写都反应到总线上。对 memory 的操纵过程中CPU须要守候。
0 1 无cache,有写缓冲;读操纵直接反应到总线上;写操纵,CPU将数据写入到写缓冲后持续运行,由写缓冲进行写回操纵。
1 0 有cache,写通模式;读操纵起首推敲cache hit;写操纵时直接将数据写入写缓冲,若是同时呈现cache hit,那么也更新cache。
1 1 有cache,写回模式;读操纵起首推敲cache hit;写操纵也起首推敲cache hit。
如许,两者的差别就很清楚了。
static void *
__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
pgprot_t prot)
{
struct page *page;
struct arm_vm_region *c;
unsigned long order;
u64 mask = ISA_DMA_THRESHOLD, limit;
if (!consistent_pte[0]) {
printk(KERN_ERR "%s: not initialised\n", __func__);
dump_stack();
return NULL;
}
if (dev) {
mask = dev->coherent_dma_mask;
/*
* Sanity check the DMA mask - it must be non-zero, and
* must be able to be satisfied by a DMA allocation.
*/
if (mask == 0) {
dev_warn(dev, "coherent DMA mask is unset\n");
goto no_page;
}
if ((~mask) & ISA_DMA_THRESHOLD) {
dev_warn(dev, "coherent DMA mask %#llx is smaller "
"than system GFP_DMA mask %#llx\n",
mask, (unsigned long long)ISA_DMA_THRESHOLD);
goto no_page;
}
}
/*
* Sanity check the allocation size.
*/
size = PAGE_ALIGN(size);
limit = (mask + 1) & ~mask;
if ((limit && size >= limit) ||
size >= (CONSISTENT_END - CONSISTENT_BASE)) {
printk(KERN_WARNING "coherent allocation too big "
"(requested %#x mask %#llx)\n", size, mask);
goto no_page;
}
order = get_order(size);
if (mask != 0xffffffff)
gfp |= GFP_DMA;
page = alloc_pages(gfp, order);
if (!page)
goto no_page;
/*
* Invalidate any data that might be lurking in the
* kernel direct-mapped region for device DMA.
*/
{
void *ptr = page_address(page);
memset(ptr, 0, size);
dmac_flush_range(ptr, ptr + size);
outer_flush_range(__pa(ptr), __pa(ptr) + size);
}
/*
* Allocate a virtual address in the consistent mapping region.
*/
c = arm_vm_region_alloc(&consistent_head, size,
gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
if (c) {
pte_t *pte;
struct page *end = page + (1 << order);
int idx = CONSISTENT_PTE_INDEX(c->vm_start);
u32 off = CONSISTENT_OFFSET(c->vm_start) & (PTRS_PER_PTE-1);
pte = consistent_pte[idx] + off;
c->vm_pages = page;
split_page(page, order);
/*
* Set the "dma handle"
*/
*handle = page_to_dma(dev, page);
do {
BUG_ON(!pte_none(*pte));
/*
* x86 does not mark the pages reserved...
*/
SetPageReserved(page);
set_pte_ext(pte, mk_pte(page, prot), 0);
page++;
pte++;
off++;
if (off >= PTRS_PER_PTE) {
off = 0;
pte = consistent_pte[++idx];
}
} while (size -= PAGE_SIZE);
/*
* Free the otherwise unused pages.
*/
while (page < end) {
__free_page(page);
page++;
}
return (void *)c->vm_start;
}
if (page)
__free_pages(page, order);
no_page:
*handle = ~0;
return NULL;
}
在文件arch/arm/include/asm/memory.h中找到有关CONSISTENT_DMA_SIZE的定义:
/* * Size of DMA-consistent memory region. Must be multiple of 2M, * between 2MB and 14MB inclusive. */#ifndef CONSISTENT_DMA_SIZE#define CONSISTENT_DMA_SIZE SZ_2M#endif
而文件arch/arm/include/asm/memory.h定义的是Linux下整个ARM体系的公共参数,如果直接修改会引起别的平台的一些不可预料的结果.
幸运的是在memory.h文件开头有一个include文件
#include <mach/memory.h>
找到<mach/memory.h>文件arch/arm/mach-xxx/include/mach/memory.h,在其中添加CONSISTENT_DMA_SIZE的定义即可,如:
#define CONSISTENT_DMA_SIZE SZ_4M
- 使用dma_alloc_writecombine申请内存空间大小的限制
- 类的内存空间大小
- 完全释放申请的内存空间
- 【内存空间】01. 指针占用的内存空间大小
- 测试系统可供malloc()使用的内存空间大小
- 使用malloc函数申请内存空间注意事项
- 指针占用的内存空间大小
- 文件的大小与内存空间
- PostgreSQL 聚合函数共享申请的内存空间
- C++测试程序申请多大的内存空间
- C#申请大内存空间的二维数组
- 简单的介绍一下C中申请的内存空间,free的使用
- 申请内存空间和释放内存空间
- 内核使用硬件ip的dma,dma_alloc_coherent 与 dma_alloc_writecombine
- 内核使用硬件ip的dma,dma_alloc_coherent 与 dma_alloc_writecombine
- 内核使用硬件ip的dma,dma_alloc_coherent 与 dma_alloc_writecombine
- 限制PGA使用内存的大小
- dma_alloc_writecombine
- cocoa ios iphone xcode 播放GIF动画
- phpcms头条图片
- ColorMatrix
- Android Intent Flag的介绍
- 基础要点总结
- 使用dma_alloc_writecombine申请内存空间大小的限制
- linux softirq和tasklet的关系
- Android APK签名流程
- [转]成都一网络公司放末日假期 称最后时间陪最亲的人
- 最快浮点数取绝对值
- Android Library Project 使用问题总结
- 什么是write-allocate policy?
- C++面试 1
- 基于官方UIImagePicker的图片多选(类似美图秀秀)