DMA及cache一致性的学习心得

这里提到的DMA设备是非PCI设备
在framebuffer的prob函数中,用到了这样一个函数,下面分析下它的作用
/*
*    s3c_fb_map_video_memory():
*   分配DRAM的缓存区给frame buffer。
*   这个缓存区是一个non-cached,non-buffered的。
*   这片内存区域允许调色板和像素在写入时不刷新cache缓存。
*   一旦这片区域重新映射,那么所有用来访问video memory的虚拟内存将会
*   对应另外一片新的区域,即另外一片物理地址
*/
int __init s3c_fb_map_video_memory(struct s3c_fb_info *fbi)
{
......
fbi->map_size_f1 = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
fbi->map_cpu_f1 = dma_alloc_writecombine(fbi->dev, fbi->map_size_f1,
&fbi->map_dma_f1, GFP_KERNEL);
......
}


首先说说6410的DMA虚拟地址和物理地址的映射。2.6.29中,比2.6.24有一些出入

2.6.29内核中,在arch/arm/mm/dma-mapping.c 中实现了DMA映射的函数。其中
 
#define CONSISTENT_END    (0xffe00000)
#define CONSISTENT_BASE    (CONSISTENT_END - CONSISTENT_DMA_SIZE)


CONSISTENT_ENT 是DMA虚拟地址的结束地址
CONSISTENT_ENT 是DMA虚拟地址的起始地址

而CONSISTENT_DMA_SIZE定义在/arch/arm/include/asm/memory.h
 
/*
* 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_8M + SZ_4M) //+ chachi - SZ_2M        
#endif


DMA的大小必须是2M的整数倍。且在2M和14M之间
原来定义的大小是2M,网上看到有些blog说不够用,会报错。考虑到将来如果移植摄像头和音频的话,将会占用不少DMA缓存,因此这里改到12M

由于在编写驱动的时候,出了很多错误,所以走了不少弯路,也学到不少东西。因此在研究
 dma_writecombine函数的时,有必要先了解一下cache的一致性问题。

参考书:《Linux设备驱动开发详解》、《Linux设备驱动程序》第三版
 

cache的一致性
先理解cache的作用
CPU在访问内存时,首先判断所要访问的内容是否在Cache中,如果在,就称为“命中(hit)”,此时CPU直接从Cache中调用该内容;否则,就 称为“ 不命中”,CPU只好去内存中调用所需的子程序或指令了。CPU不但可以直接从Cache中读出内容,也可以直接往其中写入内容。由于Cache的存取速 率相当快,使得CPU的利用率大大提高,进而使整个系统的性能得以提升。

Cache的一致性就是直Cache中的数据,与对应的内存中的数据是一致的。

DMA是直接操作总线地址的,这里先当作物理地址来看待吧(系统总线地址和物理地址只是观察内存的角度不同)。如果cache缓存的内存区域不包括DMA分配到的区域,那么就没有一致性的问题。但是如果cache缓存包括了DMA目的地址的话,会出现什么什么问题呢?

问题出在,经过DMA操作,cache缓存对应的内存数据已经被修改了,而CPU本身不知道(DMA传输是不通过CPU的),它仍然认为cache中的数 据就是内存中的数据,以后访问Cache映射的内存时,它仍然使用旧的Cache数据。这样就发生Cache与内存的数据“不一致性”错误。

题外话:好像2.6.29内核中,6410的总线地址和物理地址是一样的,因为我在查看vir_to_bus函数的时候,发现在/arch/arm/linux/asm/memory.h中这样定义:
 
#ifndef __virt_to_bus
#define __virt_to_bus    __virt_to_phys
#define __bus_to_virt    __phys_to_virt
#endif

而且用source Insight搜索了一遍,没有发现6410相关的代码中,重新定义__vit_to_bus,因此擅自认为2.6内核中,6410的总线地址就是物理地址。希望高手指点。

顺便提一下,总线地址是从设备角度上看到的内存,物理地址是CPU的角度看到的未经过转换的内存(经过转换的是虚拟地址)

由上面可以看出,DMA如果使用cache,那么一定要考虑cache的一致性。解决DMA导致的一致性的方法最简单的就是禁止DMA目标地址范围内的cache功能。但是这样就会牺牲性能。

因此在DMA是否使用cache的问题上,可以根据DMA缓冲区期望保留的的时间长短来决策。DAM的映射就分为:一致性DMA映射和流式DMA映射。

一致性DMA映射申请的缓存区能够使用cache,并且保持cache一致性。一致性映射具有很长的生命周期,在这段时间内占用的映射寄存器,即使不使用也不会释放。生命周期为该驱动的生命周期

流式DMA映射实现比较复杂,因为没具体了解,就不说明了。只知道种方式的生命周期比较短,而且禁用cache。一些硬件对流式映射有优化。建立流式DMA映射,需要告诉内核数据的流动方向。


因为LCD随时都在使用,因此在Frame buffer驱动中,使用一致性DMA映射
上面的代码中用到
 dma_alloc_writecombine函数,另外还有一个一致性DMA映射函数dma_alloc_coherent

两者的区别在于:
查看两者的源代码
 
/*
* 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));
}


/*
* 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));
}

#define pgprot_noncached(prot)  __pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE))
#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~L_PTE_CACHEABLE)

再结合网上的资料(不过我感觉那文章写的有些问题,我修改了一下),由上面代码可以看出,两个函数都调用了__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。

这样,两者的区别就很清楚了。
 

A = dma_alloc_writecombine(struct device *dev, size_t size ,dma_addr_t *handle, gfp_t gfp);

含义:
A          : 内存的虚拟起始地址,在内核要用此地址来操作所分配的内存
dev      : 可以平台初始化里指定,主要是用到dma_mask之类参数,可参考framebuffer
size      : 实际分配大小,传入dma_map_size即可
handle: 返回的内存物理地址,dma就可以用。

A和hanle是一一对应的,A是虚拟地址,而handle是总线地址。对任意一个操作都将改变写缓冲区内容。


1、页对齐内存大小:dma_map_size = PAGE_ALIGN(MY_DATA_SIZE + PAGE_SIZE);

MY_DATA_SIZE是你想分配的大小.

2、调用

A = dma_alloc_writecombine(B,C,D,GFP_KERNEL);

含义:

A: 内存的虚拟起始地址,在内核要用此地址来操作所分配的内存

B: struct device指针,可以平台初始化里指定,主要是dma_mask之类,可参考framebuffer

C: 实际分配大小,传入dma_map_size即可

D: 返回的内存物理地址,dma就可以用。

所以,A和D是一一对应的,只不过,A是虚拟地址,而D是物理地址。对任意一个操作都将改变缓冲区内容。当然要注意操作环境。

参见S3C2410 LCD驱动中的函数s3c2410fb_map_video_memory():
unsigned map_size = PAGE_ALIGN(info->fix.smem_len);
info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,&map_dma, GFP_KERNEL);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/434677.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET使用Memcached高缓存实例(初级教程)

http://www.itruanjian.com/a/itruanjian/datebase/nosql/2011/0927/5706.htmlMemcached是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提供动态、数据库驱动网站的M…

C# 线程手册 第三章 使用线程 Monitor.TryEnter()

Monitor 类的TryEnter() 方法在尝试获取一个对象上的显式锁方面和 Enter() 方法类似。然而,它不像Enter()方法那样会阻塞执行。如果线程成功进入关键区域那么TryEnter()方法会返回true. TryEnter()方法的三个重载方法中的两个以一个timeout类型值作为参数&#xff0…

socketpair理解

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://liulixiaoyao.blog.51cto.com/1361095/533469 今天跟人谈到socketpair的问题,晚上回来写了个程序验证下自己的猜测&#xff0…

小数点化分数的过程_分数和小数的互化

《分数和小数的互化》由会员分享,可在线阅读,更多相关《分数和小数的互化(3页珍藏版)》请在人人文库网上搜索。1、_五__年级__数学____备课组教案教师备课时间课时课题分数和小数的互化课型新授课前准备:教材剖析(考点、易错点、关联考点)。1…

pycharm不同py文件共享参数_PyCharm安装笔记

1. 介绍1.1 介绍今天福哥带着大家学习如何安装非常好用的Python编辑器,也就是jetbrains全家桶的PyCharm编辑器。PyCharm是jetbrans开发的一款专门用来编写Python程序的编辑器,它的自动补全、代码联想、框架支持、插件支持以及高效的反应速度成为了编写Py…

WPF - 自定义标记扩展

在使用WPF进行编程的过程中,我们常常需要使用XAML的标记扩展:{Binding},{x:Null}等等。那么为什么WPF提供了XAML标记扩展这一功能,我们又如何创建自定义的标记扩展呢。这就是本文将要讨论的内容。 一.从标记扩展的分析…

mysql c api 函数 linux下 mysql_query_Linux C 调用MYSQL API 函数mysql_escape_string()转义插入数据...

标签:Title:Linux C 调用MYSQL API 函数mysql_escape_string()转义插入数据 --2013-10-11 11:57#include #include #include #include "mysql.h"int main(int argc, char *argv[]){MYSQL my_connection;int res;mysql_init(&my_connection);char UNAM…

使用LVM

一些比较常用的命令: vgdisplay 展示创建的volume group lvdisplay 展示创建的logic volume 在我们的项目中,vg把磁盘阵列的所有空间分给它,pv为每个盘,lv分配为每个虚拟机。 这样需要修改的地方:转载于:https://www.c…

mysql客户端保存数据乱码_mysql客户端数据乱码问题

往mysql插入中文数据时出现乱码,如下:mysql> select * from test;-----------------| id | name |-----------------| 1 | 鐜嬪煿鍧?|| 2 | 鐜嬫檽宄?|| 3 | 寮犲皬闆?|| 4 | 鐜嬮洩宄?|| 5 | 闄嗕簯 || 6 | 妗冭姳濂…

基于半同步/半反应堆线程池实现的HTTP解析服务端程序

简介: 半同步/半反应堆线程池是通过一个线程往工作队列添加任务T,然后工作线程竞争工作队列获得任务T。HTTP请求解析服务端程序:逐行解析客户端发送来的HTTP请求然后作出HTTP回答。采用线程池就是:服务端创建一个线程池&#xff0…

GridView中实现CheckBox的全选

用服务器端的方法&#xff1a; 在页面上放一个gridview控件&#xff0c;配置好数据源&#xff0c;编辑列&#xff0c;添加一个模版列&#xff0c;再编辑模版&#xff0c;放入一个checkbox控件。代码如下&#xff1a; <asp:GridView ID"GridView1" runat"serv…

mysql replace first_Java replaceFirst()方法

Java replaceFirst()方法replaceFirst() 方法使用给定的参数 replacement 替换字符串第一个匹配给定的正则表达式的子字符串。语法publicStringreplaceFirst(Stringregex,Stringreplacement)参数 regex -- 匹配此字符串的正则表达式。replacement -- 用来替换第一个匹配项的字符…

Windows与linux双系统安装

[源] [http://xiaomaimai.blog.51cto.com/1182965/294256] Windows与linux双系统 Linux的安装方式有硬盘安装、网络安装、光驱安装。 双系统的安装最后先安装windows&#xff0c;再安装linux&#xff0c;因为windows每次安装时都会重新修改系统引导文件&#xff0c;如果安装…

第一步:Axure 使用svn多人协作产品开发(提交文件)

注册登陆http://www.svnxiezuo.com站点 注册登陆http://www.svnxiezuo.com站点 从注册http://www.svnxiezuo.com站点获取svn项目地址 编辑axure文件 开始创建axure共享文件 创建axure共享文件 axure提交文件到svn版本库当中 登陆http://www.svnxiezuo.com站点svn版本库 axure创…

python文件函数_python文件和文件夹复制函数

本文实例为大家分享了python文件和文件夹复制函数&#xff0c;供大家参考&#xff0c;具体内容如下文件复制函数代码和注释如下&#xff1a;# 文件复制函数def copy_file(file1,file2):将文件一复制到文件二:param file1::param file2::return:# 首先打开源文件file1和目标文件…

\r,\n,\r\n

\r 是回车&#xff0c;return(光标到达最左侧) \n 是换行&#xff0c;newline(移到下一行) 如果只换行&#xff0c;打印的东西会在下一行的先一个位置继续&#xff0c;比如 #### 如果只回车&#xff0c;打印的东西会覆盖原有的东西 test\r123-->123t atest\r…

sql server2005索引

create index myindex on Student(StudentID) ---创建一个索引&#xff0c;括号内为要为那一列添加索引drop index Student.myindex ---删除索引&#xff0c;需指定“表名.索引列” 详细参考于&#xff1a;http://www.2cto.com/database/201201/117131.html转载于:https://www.…

python socketio async client_electron/socket.io client-python socketio/aiohttp server//连接失败

此websocket连接失败。有趣的是这几天前还在起作用。我把电子从6降到了5.0.6,但这没用。服务器from aiohttp import webimport socketioapp web.Application()sio socketio.AsyncServer()# or sio socketio.AsyncServer(cors_allowed_origins*)sio.attach(app)sio.on(connec…

2012.2.18-silverlight设计器崩溃

先把所有与siverlight有关的silverlight,silverlightsdk,silverlight_too ,silverlight toolkit,全部卸掉&#xff0c;然后重装&#xff0c;然后启动2010&#xff0c;打开原来的silverlight的项目OK&#xff0c;新疆项目也OK 总结&#xff1a;通过以上解决方法&#xff0c;可以…

领导者/追随者(Leader/Followers)模型和半同步/半异步(half-sync/half-async)模型

领导者/追随者&#xff08;Leader/Followers&#xff09;模型和半同步/半异步&#xff08;half-sync/half-async&#xff09;模型都是常用的客户-服务器编程模型。这几天翻了些文章&#xff0c;发现对领导者/追随者模型说的比较少&#xff0c;下面就这个模型打个比方&#xff1…