前一篇文档提到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相关API

dma_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相关推荐

  1. iostat IO统计原理linux内核源码分析----基于单通道SATA盘

    iostat IO统计原理linux内核源码分析----基于单通道SATA盘 先上一个IO发送submit_bio流程图,本文基本就是围绕该流程讲解. 内核版本 3.10.96 详细的源码注释:htt ...

  2. openVswitch(OVS)源代码之linux RCU锁机制分析

    前言 本来想继续顺着数据包的处理流程分析upcall调用的,但是发现在分析upcall调用时必须先了解linux中内核和用户空间通信接口Netlink机制,所以就一直耽搁了对upcall的分析.如果对 ...

  3. [转载]Linux 线程实现机制分析

    自从多线程编程的概念出现在 Linux 中以来,Linux 多线应用的发展总是与两个问题脱不开干系:兼容性.效率.本文从线程模型入手,通过分析目前 Linux 平台上最流行的 LinuxThreads ...

  4. Linux 线程实现机制分析

    本文转自:http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/ 一.基础知识:线程和进程 按照教科书上的定义,进程是资源管理的最小单位 ...

  5. Linux 线程实现机制分析--转

    http://www.ibm.com/developerworks/cn/linux/kernel/l-thread/ 一.基础知识:线程和进程 按照教科书上的定义,进程是资源管理的最小单位,线程是程 ...

  6. Linux内核NAPI机制分析

    转自:http://blog.chinaunix.net/uid-17150-id-2824051.html 简介: NAPI 是 Linux 上采用的一种提高网络处理效率的技术,它的核心概念就是不采 ...

  7. Linux睡眠唤醒机制分析--以IMX6UL为例

    鉴于当前做的项目中有低功耗的需求,因此查探了一番Linux的睡眠及唤醒的机制. 当前网络上已经有很多关于睡眠唤醒的分析文章,有的分析也非常透彻,因此本文只从寄存器以及汇编处理和CPU架构方面来补充一下 ...

  8. linux内核机制是什么,linux内核slab机制分析

    1.内部碎片和外部碎片 外部碎片 什么是外部碎片呢?我们通过一个图来解释: image.png 假设这是一段连续的页框,阴影部分表示已经被使用的页框,现在需要申请一个连续的5个页框.这个时候,在这段内 ...

  9. Linux内核poll机制分析

    1. poll 机制 本篇主要是进行 poll 内核实现,调用流程的分析. 1.1 sys_poll 分析 应用程序调用 poll() 后,经过 SWI 的处理后,最终会进入内核的 sys_poll( ...

最新文章

  1. python pymysql实例_python笔记-mysql命令使用示例(使用pymysql执行)
  2. python培训班深圳-深圳哪里有Python培训班?
  3. 2!=5 or 0在python中是否正确-python中的or,and运算符
  4. libgdx 1.4.1公布
  5. UNIX 高手的 20 个习惯
  6. oracle远程物化视图
  7. java学习(21):移位运算符
  8. Python中利用for循环的求和运算
  9. bios 微星click_msi微星主板bios设置方法
  10. 集合论—关系的自反、对称和传递闭包
  11. mybatis-基本架构
  12. idea 全局搜索快捷键冲突_intellij idea 的全局搜索快捷键方法
  13. [工具类] 系列二 Lettuce 访问Redis 工具类 RedisUtil
  14. 金融行业开源软件研究评测报告——JSON组件
  15. (一)Jedis远程访问阿里云服务器Redis服务出错
  16. IDEA通过插件安装Gitee并clone项目
  17. 使用RestFul风格操作ElasticSearch 看这篇够了
  18. CreateEventA 函数理解
  19. 一个优秀的大数据开发工程师的日常是怎么样的?
  20. dreamweaver作业静态HTML网页设计——我的家乡海南旅游网站

热门文章

  1. linux cut 命令(转)
  2. windows 2008 R2下安装Exchange 2010(单域环境下)
  3. Silverlight3实现按路径运动[原创]
  4. Colaboratory下载Kaggle数据
  5. 前端JS通过Ajax下载后端返回的Excel文档
  6. C 语言判断大端小端
  7. 【代码】python paramiko模块代码示例:远程执行命令及上传和下载
  8. ubuntu安装rar win解压缩工具
  9. win cmd rmdir /s递归删除目录
  10. centos7.x 64位 rpm安装JDK8