linux CMA使用机制分析--基于SigmaStar SSD202
前一篇文档提到CMA相关的内容Linux虚拟内存映射分析以及CMA测试 - 以SSD202为例,其主要使用标准内核CMA API进行,并直接经由CMA进行管理,通过进一步查探,SSD202内核有独立的模块msys位于CMA之上,另外多做了一层管理
模块位置:drivers/sstar/msys/ms_msys.c
此模块属于综合性模块,包含多个类型,主要是与cpu特性相关的,也就是独立属于SSD202平台的。
首先看一下初始化,大概就能看出其功能
static int __init msys_init(void)
{int ret;//ret = misc_register(&sys_dev);ret = register_chrdev(MAJOR_SYS_NUM, "msys", &msys_fops);if (ret != 0) {MSYS_ERROR("cannot register msys (err=%d)\n", ret);}sys_dev.this_device = device_create(msys_get_sysfs_class(), NULL,MKDEV(MAJOR_SYS_NUM, MINOR_SYS_NUM), NULL, "msys");sys_dev.this_device->dma_mask=&sys_dma_mask;sys_dev.this_device->coherent_dma_mask=sys_dma_mask;mutex_init(&dmem_mutex);INIT_LIST_HEAD(&kept_mem_head);INIT_LIST_HEAD(&fixed_mem_head);device_create_file(sys_dev.this_device, &dev_attr_dmem);device_create_file(sys_dev.this_device, &dev_attr_dmem_alloc);device_create_file(sys_dev.this_device, &dev_attr_release_dmem);
#ifdef CONFIG_MSYS_DMEM_SYSFS_ALLdevice_create_file(sys_dev.this_device, &dev_attr_fixed_dmem);device_create_file(sys_dev.this_device, &dev_attr_unfix_dmem);device_create_file(sys_dev.this_device, &dev_attr_dmem_retry_count);device_create_file(sys_dev.this_device, &dev_attr_dmem_realloc);
#endif#ifdef CONFIG_MS_PIU_TICK_APIdevice_create_file(sys_dev.this_device, &dev_attr_PIU_T);
#endif#ifdef CONFIG_MS_CPU_FREQdevice_create_file(sys_dev.this_device, &dev_attr_TEMP_R);
#endifdevice_create_file(sys_dev.this_device, &dev_attr_CHIP_VERSION);#ifdef CONFIG_MS_US_TICK_APIdevice_create_file(sys_dev.this_device, &dev_attr_us_ticks);
#endif#ifdef CONFIG_SS_PROFILING_TIMEdevice_create_file(sys_dev.this_device, &dev_attr_booting_time);
#endif
#if defined(CONFIG_ARCH_INFINITY2)
#if defined(CONFIG_MS_MOVE_DMA)device_create_file(sys_dev.this_device, &dev_attr_movedma);
#endifdevice_create_file(sys_dev.this_device, &dev_attr_bytedma);device_create_file(sys_dev.this_device, &dev_attr_bytedmacp);
#endif
#if defined(CONFIG_PROC_FS) && defined(CONFIG_MSYS_REQUEST_PROC)mutex_init(&proc_info_mutex);INIT_LIST_HEAD(&proc_info_head);proc_class=proc_mkdir("mstar",NULL);proc_zen_kernel=proc_mkdir("kernel",proc_class);
#endifreturn 0;
}
其主要功能有:
1. 创建msys设备文件,支持ioctl相关设置
2. cma memory的属性控制
3. Frequency以及Temperature相关
分析CMA使用,可以从cma memory的属性控制入手,也就是
device_create_file(sys_dev.this_device, &dev_attr_dmem);
device_create_file(sys_dev.this_device, &dev_attr_dmem_alloc);
device_create_file(sys_dev.this_device, &dev_attr_release_dmem);
管理核心结构为
typedef struct
{
unsigned int VerChk_Version;
char name[16];
unsigned int length; //32 bit
unsigned long long phys; //64 bit
unsigned long long kvirt; //Kernel Virtual Address 64 bit
unsigned int option; //reserved
unsigned int VerChk_Size;
} __attribute__ ((__packed__)) MSYS_DMEM_INFO;
基本上可以理解为将cma区域通过name和length来描述和管理
核心的API有2个msys_request_dmem 和 msys_release_dmem
有了属性文件,方便在userspace进行使用
查阅已创建的cam区
cat /sys/class/mstar/msys/dmem
root@wireless-tag:~# cat /sys/class/mstar/msys/dmem
序号:大小 物理地址 名称
0000 : 0x00001000@2644C000 [AESDMA_ENG1]
0001 : 0x00001000@2644B000 [AESDMA_ENG]
0002 : 0x000FA000@264C0000 [test3]
0003 : 0x00060812@26450000 [emac1_buff]
0004 : 0x00000812@26449000 [emac0_buff]
0005 : 0x00000840@26448000 [BDMA]TOTAL: 0x0015D864 总大小
释放cam区
指定名称即可,比如释放test3,echo test3 > /sys/class/mstar/msys/release_dmem
[ 4385.943383] cma: cma_release(page c63be800)
[ 4385.947603] [MSYS] DMEM [test3]@0x264C0000 successfully released
再次查看已分配区域确认一下:
root@wireless-tag:~# cat /sys/class/mstar/msys/dmem
0000 : 0x00001000@2644C000 [AESDMA_ENG1]
0001 : 0x00001000@2644B000 [AESDMA_ENG]
0002 : 0x00060812@26450000 [emac1_buff]
0003 : 0x00000812@26449000 [emac0_buff]
0004 : 0x00000840@26448000 [BDMA]TOTAL: 0x00063864
分配新的区域
指定name和length即可,echo new1k 1024 > /sys/class/mstar/msys/dmem_alloc
[ 4509.950954] MSYS: DMEM request: [new1k]:0x00000400 Bytes
[ 4509.956153] cma: cma_alloc(cma c0435ef0, count 1, align 0)
[ 4509.961723] cma: cma_alloc(): returned c63bd9a0
[ 4509.966504] MSYS: DMEM request: [new1k]:0x00000400 success, CPU phy:@0x2644D000, virt:@0xC644D000
确认结果
root@wireless-tag:~# cat /sys/class/mstar/msys/dmem
0000 : 0x00000400@2644D000 [new1k]
0001 : 0x00001000@2644C000 [AESDMA_ENG1]
0002 : 0x00001000@2644B000 [AESDMA_ENG]
0003 : 0x00060812@26450000 [emac1_buff]
0004 : 0x00000812@26449000 [emac0_buff]
0005 : 0x00000840@26448000 [BDMA]TOTAL: 0x00063C64
分配API msys_request_dmem实现
int msys_request_dmem(MSYS_DMEM_INFO *mem_info)
{
dma_addr_t phys_addr;
int err=0;
int retry=0;
if(mem_info->name[0]==0||strlen(mem_info->name)>15)
{
MSYS_ERROR( "Invalid DMEM name!! Either garbage or empty name!!\n");
return -EINVAL;
}
/*if(mem_info->length<=0)
{
MSYS_ERROR( "Invalid DMEM length!! [%s]:0x%08X\n",mem_info->name,(unsigned int)mem_info->length);
return -EFAULT;
}*/
MSYS_ERROR("DMEM request: [%s]:0x%08X Bytes\n",mem_info->name,(unsigned int)mem_info->length);
mutex_lock(&dmem_mutex);
// if(mem_info->name[0]!=0)
{
struct list_head *ptr;
struct DMEM_INFO_LIST *entry;
---所有cam块通过全局list管理kept_mem_head
list_for_each(ptr, &kept_mem_head)
{
entry = list_entry(ptr, struct DMEM_INFO_LIST, list);
---已存在重新分配if (0==strncmp(entry->dmem_info.name, mem_info->name,strnlen(mem_info->name,15)))
{
if(dmem_realloc_enabled && (entry->dmem_info.length != mem_info->length))
{
MSYS_ERROR("dmem realloc %s", entry->dmem_info.name);
----先释放旧的空间,直接调用cma相关APIdma_free_coherent(sys_dev.this_device, PAGE_ALIGN(entry->dmem_info.length),(void *)(uintptr_t)entry->dmem_info.kvirt,entry->dmem_info.phys);
MSYS_ERROR("DMEM [%s]@0x%08X successfully released\n",entry->dmem_info.name,(unsigned int)entry->dmem_info.phys);
list_del_init(&entry->list);
break;
}
else
{
memcpy(mem_info,&entry->dmem_info,sizeof(MSYS_DMEM_INFO));
MSYS_ERROR("DMEM kept entry found: name=%s, phys=0x%08X, length=0x%08X\n",mem_info->name,(unsigned int)mem_info->phys,(unsigned int)mem_info->length);
goto BEACH_ENTRY_FOUND;
}
}
}
//MSYS_PRINT(KERN_WARNING"can not found kept direct requested memory entry name=%s\n",mem_info.name);
}
// else
// {
// MSYS_PRINT(" !!ERROR!! Anonymous DMEM request is forbidden !!\n");
// return -EFAULT;
// }
-----分配新空间
while( !(mem_info->kvirt = (u64)(uintptr_t)dma_alloc_coherent(sys_dev.this_device, PAGE_ALIGN(mem_info->length), &phys_addr, GFP_KERNEL)) ){
if(retry >= dmem_retry_count)
{
MSYS_ERROR( "unable to allocate direct memory\n");
err = -ENOMEM;
goto BEACH_ALLOCATE_FAILED;
}
MSYS_ERROR( "retry ALLOC_DMEM %d [%s]:0x%08X\n", retry, mem_info->name, (unsigned int)mem_info->length);
sysctl_compaction_handler(NULL, 1, NULL, NULL, NULL);
msleep(1000);
retry++;
}
mem_info->phys=(u64)phys_addr;
{
----创建list管理节点
struct DMEM_INFO_LIST *new=(struct DMEM_INFO_LIST *)kmalloc(sizeof(struct DMEM_INFO_LIST),GFP_KERNEL);if(new==NULL)
{
MSYS_ERROR("allocate memory for mem_list entry error\n" ) ;
err = -ENOMEM;
goto BEACH;
}
memset(new->dmem_info.name,0,16);
/*
new->dmem_info.kvirt=mem_info->kvirt;
new->dmem_info.phys=mem_info->phys;
new->dmem_info.length=mem_info->length;
if(mem_info->name!=NULL){
memcpy(new->dmem_info.name,mem_info->name,strnlen(mem_info->name,15));
}
*/
memcpy(&new->dmem_info,mem_info,sizeof(MSYS_DMEM_INFO));
list_add(&new->list, &kept_mem_head);
}
if(retry)
MSYS_ERROR("DMEM request: [%s]:0x%08X success, @0x%08X (retry=%d)\n",mem_info->name,(unsigned int)mem_info->length, (unsigned int)mem_info->phys, retry);
else
MSYS_ERROR("DMEM request: [%s]:0x%08X success, CPU phy:@0x%08X, virt:@0x%08X\n",mem_info->name,(unsigned int)mem_info->length, (unsigned int)mem_info->phys, (unsigned int)mem_info->kvirt);
BEACH:
if(err==-ENOMEM)
{
msys_release_dmem(mem_info);
}
BEACH_ALLOCATE_FAILED:
BEACH_ENTRY_FOUND:
if(err)
{
MSYS_ERROR("DMEM request: [%s]:0x%08X FAILED!! (retry=%d)\n",mem_info->name,(unsigned int)mem_info->length, retry);
}
#if 0
if(0==err){
memset((void *)((unsigned int)mem_info->kvirt),0,mem_info->length);
Chip_Flush_CacheAll();
MSYS_PRINT("DMEM CLEAR!!\n");
}
#endif
mutex_unlock(&dmem_mutex);
return err;
}
EXPORT_SYMBOL(msys_request_dmem);
释放空间 msys_release_dmem
int msys_release_dmem(MSYS_DMEM_INFO *mem_info)
{//MSYS_DMEM_INFO mem_info;
struct list_head *ptr;
struct DMEM_INFO_LIST *entry,*match_entry;int dmem_fixed=0;
mutex_lock(&dmem_mutex);
match_entry=NULL;// MSYS_PRINT("\nFREEING DMEM [%s]\n\n",mem_info->name);
if(mem_info->name[0]!=0)
{
----遍历全局list查找name块
list_for_each(ptr, &kept_mem_head)
{
int res=0;
entry = list_entry(ptr, struct DMEM_INFO_LIST, list);
res=strncmp(entry->dmem_info.name, mem_info->name,strnlen(mem_info->name,15));
// MSYS_PRINT("DMEM0 [%s],%s %d\n",entry->dmem_info.name,match_entry->dmem_info.name,res);
if (0==res)
{
match_entry=entry;
break;
}
}
}---通过name找不到,再检索物理地址
if(match_entry==NULL && (0!=mem_info->phys))
{
MSYS_ERROR("WARNING!! DMEM [%s]@0x%08X can not be found by name, try to find by phys address\n",mem_info->name, (unsigned int)mem_info->phys);
list_for_each(ptr, &kept_mem_head)
{
entry = list_entry(ptr, struct DMEM_INFO_LIST, list);
if (entry->dmem_info.phys==mem_info->phys)
{
match_entry=entry;
break;
}
}}
---name和phys都找不到即退出
if(match_entry==NULL)
{
MSYS_ERROR("DMEM [%s]@0x%08X not found, skipping release...\n",mem_info->name, (unsigned int)mem_info->phys);
goto BEACH;
}if(fixed_dmem_enabled)
{
//check if entry is fixed----从管理上,支持固定区域,不需要释放,用单独的list管理 fixed_mem_head
list_for_each(ptr, &fixed_mem_head)
{
int res=0;
entry = list_entry(ptr, struct DMEM_INFO_LIST, list);
res=strcmp(entry->dmem_info.name, match_entry->dmem_info.name);
if (0==res)
{
dmem_fixed=1;
MSYS_PRINT("DMEM [%s]@0x%08X is fixed, skipping release...\n",match_entry->dmem_info.name,(unsigned int)match_entry->dmem_info.phys);
goto BEACH;
}
}
}---调用CMA释放接口
dma_free_coherent(sys_dev.this_device, PAGE_ALIGN(match_entry->dmem_info.length),(void *)(uintptr_t)match_entry->dmem_info.kvirt,match_entry->dmem_info.phys);MSYS_PRINT("DMEM [%s]@0x%08X successfully released\n",match_entry->dmem_info.name,(unsigned int)match_entry->dmem_info.phys);
---从全局列表删除
list_del_init(&match_entry->list);
---释放list管理节点
kfree(match_entry);BEACH:
mutex_unlock(&dmem_mutex);
return 0;}
EXPORT_SYMBOL(msys_release_dmem);
其他模块使用,以AES模块中的封装为例
static void* alloc_dmem(const char* name, unsigned int size, dma_addr_t *addr)
{MSYS_DMEM_INFO dmem;memcpy(dmem.name,name,strlen(name)+1);dmem.length=size;if(0!=msys_request_dmem(&dmem)){return NULL;}*addr=dmem.phys;return (void *)((uintptr_t)dmem.kvirt);
}
void free_dmem(const char* name, unsigned int size, void *virt, dma_addr_t addr )
{MSYS_DMEM_INFO dmem;memcpy(dmem.name,name,strlen(name)+1);dmem.length=size;dmem.kvirt=(unsigned long long)((uintptr_t)virt);dmem.phys=(unsigned long long)((uintptr_t)addr);msys_release_dmem(&dmem);
}
分配指定name和大小即可,返回虚拟地址直接使用
释放指定name或者物理地址即可
linux CMA使用机制分析--基于SigmaStar SSD202相关推荐
- iostat IO统计原理linux内核源码分析----基于单通道SATA盘
iostat IO统计原理linux内核源码分析----基于单通道SATA盘 先上一个IO发送submit_bio流程图,本文基本就是围绕该流程讲解. 内核版本 3.10.96 详细的源码注释:htt ...
- openVswitch(OVS)源代码之linux RCU锁机制分析
前言 本来想继续顺着数据包的处理流程分析upcall调用的,但是发现在分析upcall调用时必须先了解linux中内核和用户空间通信接口Netlink机制,所以就一直耽搁了对upcall的分析.如果对 ...
- [转载]Linux 线程实现机制分析
自从多线程编程的概念出现在 Linux 中以来,Linux 多线应用的发展总是与两个问题脱不开干系:兼容性.效率.本文从线程模型入手,通过分析目前 Linux 平台上最流行的 LinuxThreads ...
- Linux 线程实现机制分析
本文转自:http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/ 一.基础知识:线程和进程 按照教科书上的定义,进程是资源管理的最小单位 ...
- Linux 线程实现机制分析--转
http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/ 一.基础知识:线程和进程 按照教科书上的定义,进程是资源管理的最小单位,线程是程 ...
- Linux内核NAPI机制分析
转自:http://blog.chinaunix.net/uid-17150-id-2824051.html 简介: NAPI 是 Linux 上采用的一种提高网络处理效率的技术,它的核心概念就是不采 ...
- Linux睡眠唤醒机制分析--以IMX6UL为例
鉴于当前做的项目中有低功耗的需求,因此查探了一番Linux的睡眠及唤醒的机制. 当前网络上已经有很多关于睡眠唤醒的分析文章,有的分析也非常透彻,因此本文只从寄存器以及汇编处理和CPU架构方面来补充一下 ...
- linux内核机制是什么,linux内核slab机制分析
1.内部碎片和外部碎片 外部碎片 什么是外部碎片呢?我们通过一个图来解释: image.png 假设这是一段连续的页框,阴影部分表示已经被使用的页框,现在需要申请一个连续的5个页框.这个时候,在这段内 ...
- Linux内核poll机制分析
1. poll 机制 本篇主要是进行 poll 内核实现,调用流程的分析. 1.1 sys_poll 分析 应用程序调用 poll() 后,经过 SWI 的处理后,最终会进入内核的 sys_poll( ...
最新文章
- python pymysql实例_python笔记-mysql命令使用示例(使用pymysql执行)
- python培训班深圳-深圳哪里有Python培训班?
- 2!=5 or 0在python中是否正确-python中的or,and运算符
- libgdx 1.4.1公布
- UNIX 高手的 20 个习惯
- oracle远程物化视图
- java学习(21):移位运算符
- Python中利用for循环的求和运算
- bios 微星click_msi微星主板bios设置方法
- 集合论—关系的自反、对称和传递闭包
- mybatis-基本架构
- idea 全局搜索快捷键冲突_intellij idea 的全局搜索快捷键方法
- [工具类] 系列二 Lettuce 访问Redis 工具类 RedisUtil
- 金融行业开源软件研究评测报告——JSON组件
- (一)Jedis远程访问阿里云服务器Redis服务出错
- IDEA通过插件安装Gitee并clone项目
- 使用RestFul风格操作ElasticSearch 看这篇够了
- CreateEventA 函数理解
- 一个优秀的大数据开发工程师的日常是怎么样的?
- dreamweaver作业静态HTML网页设计——我的家乡海南旅游网站