日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux CMA使用机制分析--基于SigmaStar SSD202

發布時間:2024/10/12 linux 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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相關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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。