= array(); } $post['classname'] = 'post'; } function comment_format(&$post) { global $conf, $uid, $gid, $forumlist; if (empty($post)) return; $forum = $post['fid'] ? forum_read($post['fid']) : ''; $thread = well_thread_read_cache($post['tid']); if ($thread) { //$post['fid'] = $thread['fid']; $post['closed'] = $thread['closed']; $post['subject'] = $thread['subject']; $post['url'] = $thread['url']; } else { $post['closed'] = 0; $post['subject'] = lang('thread_not_exists'); $post['url'] = ''; } $post['create_date_fmt'] = humandate($post['create_date']); //$post['message'] = stripslashes(htmlspecialchars_decode($post['message'])); $user = user_read_cache($post['uid']); $post['username'] = array_value($user, 'username'); $post['user_avatar_url'] = array_value($user, 'avatar_url'); $post['user'] = $user ? user_safe_info($user) : user_guest(); isset($post['floor']) || $post['floor'] = 0; // 权限判断 $post['allowupdate'] = 2 == array_value($forum, 'comment', 0) && ($uid == $post['uid'] || forum_access_mod($post['fid'], $gid, 'allowupdate')); $post['allowdelete'] = group_access($gid, 'allowuserdelete') && $uid == $post['uid'] || forum_access_mod($post['fid'], $gid, 'allowdelete'); $post['user_url'] = url('user-' . $post['uid'] . ($post['uid'] ? '' : '-' . $post['pid'])); if ($post['files'] > 0) { list($attachlist, $imagelist, $filelist) = well_attach_find_by_pid($post['pid']); // 使用图床 评论使用图床,mysql会过多,写死链接到内容是减轻mysql的过多的方法 if (2 == $conf['attach_on']) { foreach ($imagelist as $key => $attach) { $url = $conf['upload_url'] . 'website_attach/' . $attach['filename']; // 替换成图床 $post['message'] = FALSE !== strpos($post['message'], $url) && $attach['image_url'] ? str_replace($url, $attach['image_url'], $post['message']) : $post['message']; } } $post['filelist'] = $filelist; } else { $post['filelist'] = array(); } $post['classname'] = 'post'; } function comment_format_message(&$val) { global $conf; if (empty($val)) return; // 使用云储存 if (1 == $conf['attach_on'] && 1 == $val['attach_on']) { $val['message'] = str_replace('="upload/', '="' . file_path($val['attach_on']), $val['message']); } elseif (2 == $conf['attach_on'] && 2 == $val['attach_on']) { // 使用图床 list($attachlist, $imagelist, $filelist) = well_attach_find_by_tid($val['tid']); foreach ($imagelist as $key => $attach) { $url = $conf['upload_url'] . 'website_attach/' . $attach['filename']; // 替换成图床 $val['message'] = FALSE !== strpos($val['message'], $url) && $attach['image_url'] ? str_replace($url, $attach['image_url'], $val['message']) : $val['message']; } } else { $val['message'] = str_replace('="upload/', '="' . file_path($val['attach_on']), $val['message']); } //$val['message'] = stripslashes(htmlspecialchars_decode($val['message'])); } // 把内容中使用了云储存的附件链接替换掉 function comment_message_replace_url($pid, $message) { global $conf; if (0 == $conf['attach_on']) { $message = FALSE !== strpos($message, '="../upload/') ? str_replace('="../upload/', '="upload/', $message) : $message; $message = FALSE !== strpos($message, '="/upload/') ? str_replace('="/upload/', '="upload/', $message) : $message; } elseif (1 == $conf['attach_on']) { // 使用云储存 $message = str_replace('="' . $conf['cloud_url'] . 'upload/', '="upload/', $message); } elseif (2 == $conf['attach_on']) { // 使用图床 评论使用图床,mysql会过多,写死链接到内容是减轻mysql的过多的方法 list($attachlist, $imagelist, $filelist) = well_attach_find_by_pid($pid); foreach ($imagelist as $key => $attach) { $url = $conf['upload_url'] . 'website_attach/' . $attach['filename']; // 替换回相对链接 $message = $attach['image_url'] && FALSE !== strpos($message, $attach['image_url']) ? str_replace($attach['image_url'], $url, $message) : $message; } } return $message; } function comment_filter($val) { unset($val['userip']); return $val; } function comment_highlight_keyword($str, $k) { $r = str_ireplace($k, '' . $k . '', $str); return $r; } // //
function comment_message_format(&$s) { if (xn_strlen($s) < 100) return; $s = preg_replace('#.*?
#is', '', $s); $s = str_ireplace(array('
', '
', '
', '

', '', '', '', '' . ''), "\r\n", $s); $s = str_ireplace(array(' '), " ", $s); $s = strip_tags($s); $s = preg_replace('#[\r\n]+#', "\n", $s); $s = xn_substr(trim($s), 0, 100); $s = str_replace("\n", '
', $s); } // 对内容进行引用 function comment_quote($quotepid) { $quotepost = comment_read($quotepid); if (empty($quotepost)) return ''; $uid = $quotepost['uid']; $s = $quotepost['message']; $s = comment_brief($s, 100); $userhref = url('user-' . $uid); $user = user_read_cache($uid); $r = '
' . $user['username'] . ' ' . $s . '
'; return $r; } // 获取内容的简介 0: html, 1: txt; 2: markdown; 3: ubb function comment_brief($s, $len = 100) { $s = strip_tags($s); $s = htmlspecialchars($s); $more = xn_strlen($s) > $len ? ' ... ' : ''; $s = xn_substr($s, 0, $len) . $more; return $s; } ?>dma
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

dma

旗下网站admin117浏览0评论

dma

dma

说明

dma_alloc_coherent 相关的知识网络上有很多,将相关的知识收集汇总以便于后续遇到问题方便查找。这一次对dma_alloc_coherent进行学习的原因是在使用rapidio驱动时申请大于64M的DMA内存时,遇到多次申请无法申请到内存的情况(加大预留DMA内存不能解决)。进而学习一下相关知识看是否有方法能解决相关问题。

怎样让DMA申请大内存

遇到的问题DMA无法申请大于32M的内存,MAX_ORDER 这个宏设置的太小,这个宏限制了一次请求所能分配的最大物理页数。如果申请5MB内存,MAX_ORDER 需要不小于12。决方法是修改menuconfig的CONFIG_FORCE_MAX_ZONEORDER定义。 内存物理内存分配alloc_pages 内存管理 能够申请多大的DMA内存,和对应内存个数可以看/proc/buddyinfo。 buddyinfo说明

Linux 内核内存管理 Linux CMA内存使用

深入理解Linux高端内存

mmzone.h中

/* Free memory management - zoned buddy allocator. */#ifndef CONFIG_FORCE_MAX_ZONEORDER#define MAX_ORDER 11#else#define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER#endif#define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1)) 注意开启内核的DMA支持CMA

DMA使用CMA的设置,不开启设置DMA将不能使用CMA内存。在dma_alloc_coherent 调用时使用或上__GFP_HIGHMEM参数可以避免使用Normal 空间。

实际超大内存的使用不建议通过上面的方式处理

对于dma framwork来说,当我们使能并且配置了CMA区域时会使用CMA进行内存分配,但是内核依然对于旧的实现方式进行了兼容,可以通过 CONFIG_HAVE_GENERIC_DMA_COHERENT 来进行配置。

对于generic dma coherent的实现方式,依然借用了dts中的reserved memory节点,只不过在其中会定义 no-map 属性,进而这块内存就从系统中剥离出来了,无法被伙伴系统所使用,但是可以在dma核心层通过remap的形式创建页表映射来使用它。

链接中的重点知识理解 空闲页和buddyinfo对应关系

在“内存管理”的连接上有内存分配的原理如下说明: 分配器维护空闲页面所组成的块, 这里每一块都是2的方幂个页面, 方幂的指数称为阶. 阶是伙伴系统中一个非常重要的术语. 它描述了内存分配的数量单位. 内存块的长度是2^0,order , 其中order的范围从0到MAX_ORDER zone->free_area[MAX_ORDER]数组中阶作为各个元素的索引, 用于指定对应链表中的连续内存区包含多少个页帧.

数组中第0个元素的阶为0, 它的free_list链表域指向具有包含区为单页(2^0 = 1)的内存页面链表数组中第1个元素的free_list域管理的内存区为两页(2^1 = 2) 第3个管理的内存区为4页, 依次类推. 直到2^MAXORDER-1个页面大小的块

buddyinfo说明中有如下图: ZONE的空间配置,但是对于ARM 可能没有ZONE DMA部分。ZONE_DMA,对于32位系统和64位系统表达的意义是不同的,ZONE_DMA32则只对64位系统有意义,对32位系统就等同于ZONE_DMA,没有单独存在的意义。

从上面介绍可以看出Buddy info对着应空闲页的状态。

有一个有意思的现象

在使用dma_alloc_coherent申请一致性内存的时候,有时候如果DTS有大量预留内存被分频。第一次会申请64M大内存失败。如果再次运行程序申请又能正常申请,申请失败时报下面的错误。

vmap allocation for size XXXX failed: use vmalloc=XXX to increase size

查看ZONE区域发现有足够的内存空间,怀疑是系统的vmalloc 虚拟地址连续大小资源不足。该资源在系统启动的时候就存在了,在UBOOT阶段可以进行设置。

问题的原因

查看虚拟内存大小( cat /proc/meminfo)

$ cat /proc/meminfo.....MemTotal: 1061096 kBMemFree: 987244 kBMemAvailable: 969068 kBBuffers: 0 kBCached: 45716 kBSwapCached: 0 kBActive: 1840 kBInactive: 24 kBActive(anon): 1840 kBInactive(anon): 24 kBActive(file): 0 kBInactive(file): 0 kBUnevictable: 45644 kBMlocked: 0 kBHighTotal: 828928 kBHighFree: 779192 kBLowTotal: 232168 kBLowFree: 208052 kBSwapTotal: 0 kBSwapFree: 0 kBDirty: 0 kBWriteback: 0 kBAnonPages: 1800 kBMapped: 2752 kBShmem: 72 kBSlab: 16740 kBSReclaimable: 9436 kBSUnreclaim: 7304 kBKernelStack: 624 kBPageTables: 144 kBNFS_Unstable: 0 kBBounce: 0 kBWritebackTmp: 0 kBCommitLimit: 530548 kBCommitted_AS: 3984 kBVmallocTotal: 245760 kB VmallocUsed: 0 kBVmallocChunk: 0 kBPercpu: 320 kBCmaTotal: 262144 kBCmaFree: 260280 kB......

查看虚拟内存使用情况( cat /proc/meminfo)

$ cat /proc/vmallocinfo .....0x(ptrval)-0x(ptrval) 8298496 simplefb_probe+0x210/0x678 phys=0x70000000 ioremap //DTS 中的显示保留内存 dc_reserved0x(ptrval)-0x(ptrval) 266240 __devm_ioremap+0x4c/0x98 phys=0xfd500000 ioremap0x(ptrval)-0x(ptrval) 4198400 __devm_ioremap+0x4c/0x98 phys=0xf9000000 ioremap0x(ptrval)-0x(ptrval) 274432 deflate_comp_init+0x20/0x9c pages=66 vmalloc0x(ptrval)-0x(ptrval) 1052672 __devm_ioremap+0x4c/0x98 phys=0xf0300000 ioremap0x(ptrval)-0x(ptrval) 1052672 __devm_ioremap+0x4c/0x98 phys=0xf0400000 ioremap0x(ptrval)-0x(ptrval) 1052672 __devm_ioremap+0x4c/0x98 phys=0xf0000000 ioremap......

在测试中发现使用的图像接口的接收缓存添加了no-map参数,有这个参数在会导致该段内存在启动的时候被系统使用ioremap将对应地址段占用,用ioremap会消耗虚拟地址范围导致没有虚拟地址分配给其他映射。

.....mipi_buffer: mipi_buffer@0x3EE00000 {compatible = "shared-dma-pool";reg = <0x3EE00000 0x08000000>;no-map;};camera_link_buffer: camera_link_buffer@0x46E00000 {compatible = "shared-dma-pool";reg = <0x46E00000 0x08000000>;no-map;};dc_reserved: dc_mem@0x70000000 {compatible = "shared-dma-pool";reg = <0x70000000 0x2000000>;no-map;};........ 解决办法

一点相关的说明

vmalloc.h:201:#define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START)

1.查看/proc/meminfo的vmalloc大小,在uboot启动参数中调大点。

setenv bootargs ‘mem=1G console=ttyAMA0,115200 mtdparts=hi_sfc:1M(boot),8M(kernel),20M(app),2M(nand),1M(param) slave_bhisilicon # 64M console=ttyAMA0,115200 vmalloc=500M’

2.或者修改KENERL 内部的,需要修改KENERL 的内容。

/kernel/arch/arm$ grep -nr "VMALLOC_END"include/asm/pgtable.h:47:#define VMALLOC_END0xff800000ULinclude/asm/pgtable-nommu.h:87:#defineVMALLOC_END0xffffffffULkernel/module.c:55:return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,mm/mmu.c:971: (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {mm/mmu.c:1132:(void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);mm/mmu.c:1149:if (vmalloc_reserve > VMALLOC_END - (PAGE_OFFSET + SZ_32M)) {mm/mmu.c:1150:vmalloc_reserve = VMALLOC_END - (PAGE_OFFSET + SZ_32M);mm/mmu.c:1155:vmalloc_min = (void *)(VMALLOC_END - vmalloc_reserve);mm/init.c:552:MLM(VMALLOC_START, VMALLOC_END),mm/dump.c:30:{ VMALLOC_END,"vmalloc() End" },mm/iomap.c:39: (unsigned long)addr < VMALLOC_END)mm/pageattr.c:60: !in_range(start, size, VMALLOC_START, VMALLOC_END))mm/ioremap.c:123: sizeof(pgd_t) * (pgd_index(VMALLOC_END) -

修改mmu.c的240 值为其他值能修改虚拟地址的大小,一般建议是1G->240,内存较大可以对应修改。

static void * __initdata vmalloc_min =(void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);/* * vmalloc=size forces the vmalloc area to be exactly 'size' * bytes. This can be used to increase (or decrease) the vmalloc * area - the default is 240m.

3.将DTS中预留内存中没有必要no-map的去掉no_map参数。

dma_alloc_coherent DMA内存申请学习笔记

发布评论

评论列表(0)

  1. 暂无评论