最近被一个问题困扰了很久,就是TI的dvsdk 编译出来的可加载模块cmemk.ko,这个模块是TI 专门针对DSP和ARM 之间共享内存,数据交互而设计的,在dvsdk编译完成后会被放在,system/ti-dsp/下面。
那我遇到什么问题了 呢,原来是整个android系统可以在SD卡中启动并正确的完成cmemk.ko模块的加载,加载主要是通过文件系统中内核运行的第一个脚本init.rc文件,里面有着详细的安装insmod。如下:
# load DSP modules
insmod /system/ti-dsp/cmemk.ko "phys_start=0x84f00000 phys_end=0x85900000 allowOverlap=1 useHeapIfPoolUnavailable=1"
insmod /system/ti-dsp/dsplinkk.ko
insmod /system/ti-dsp/lpm_omap3530.ko
insmod /system/ti-dsp/sdmak.ko
我们可以清楚的看到相应的加载过程以及为加载传入的参数。
好了,然后我就想着配置成文件系统从nfs启动,问题就出现了,无论如何都不能正确的加载cmemk,ko正确,主要是地址冲突。在过去的几天里面一直对这个问题困扰着,因为既然sd卡可以正常启动,那为何nfs不能正确加载,错误如下
11.085815] File /home/rowboat/rowboat_android1/external/ti-dsp/ti-dvsdk_dm3730-evm_04_03_00_06/linuxutils_2_26_02_05/packages/ti/sdo/linuxutils/cmem/src/module/cmec
[ 11.102386] CMEM Range Overlaps Kernel Physical - allowing overlap
[ 11.108856] CMEM phys_start (0x84f00000) overlaps kernel (0x80000000 -> 0x8f800000)
[ 11.116821] CMEMK Error: Failed to request_mem_region(0x84f00000, 10485760)
然后初步怀疑的就是uboot的传递给内核的参数错误。。有了这个想法,就根据nfs的bootargs配置,修改了
insmod /system/ti-dsp/cmemk.ko "phys_start=0x84f00000 phys_end=0x85900000 allowOverlap=1 useHeapIfPoolUnavailable=1"这后面的参数,但是都没能成功,就这样琢磨了好久。后来查找网上的论坛,ti官网,发现可能是内存初始化配置不正确,好下面给出sd启动默认的环境变量:
In: serial
Out: serial
Err: serial
Read back SMSC id 0x92200000
Die ID #08ee00229ff80000015f26ad0f01e009
Net: smc911x-0
Hit any key to stop autoboot: 0
DM3730# pri
bootcmd=if mmc init; then if run loadbootscript; then run bootscript; else if run loaduimage; then run mmcboot; else run nandboot; fi; fi; else run nandboot; fi
bootdelay=6
baudrate=115200
ipaddr=169.254.7.210
serverip=169.254.7.218
gatewayip=169.254.255.255
netmask=255.255.0.0
bootfile=uImage
loadaddr=0x82000000
usbtty=cdc_acm
console=ttyO0,115200n8
mmcargs=setenv bootargs console=${console} root=/dev/mmcblk0p2 rw rootfstype=ext3 rootwait
nandargs=setenv bootargs console=${console} root=/dev/mtdblock4 rw rootfstype=jffs2
loadbootscript=fatload mmc 0 ${loadaddr} boot.scr
bootscript=echo Running bootscript from mmc ...; source ${loadaddr}
loaduimage=fatload mmc 0 ${loadaddr} uImage
mmcboot=echo Booting from mmc ...; run mmcargs; bootm ${loadaddr}
nandboot=echo Booting from nand ...; run nandargs; onenand read ${loadaddr} 280000 400000; bootm ${loadaddr}
stdin=serial
stdout=serial
stderr=serial
dieid#=08ee00229ff80000015f26ad0f01e009
ethact=smc911x-0
下面我就简单分析一下这个启动选择的过程:
uboot启动后首先运行的命令是bootcmd ,在这里我们可以发现,有好几个选择:
1.sd存在就是mmc存在,那么会去加载loadbootscript脚本,如果加载成功那就then 运行bootscript,这样我们发现他运行的是boot.src而这个文件是TI 的软件包里面附带的,是sd卡启动的一个必须文件。当然如果没有这个脚本文件,那么直接运行loaduimage判断是否uImage存在,如果存在那么运行脚本mmcboot,设置bootargs,运行内核。当然如果在sd卡里面找不到uImage,那么就从nand去查找,。
2.sd卡直接不存在,那么就启动nandboot,这个最直接。
好,简单的做了分析,那这里最关键的就是boot.src的内容,下面我们来看一下:
then
echo ***** Kernel: /dev/mmcblk0p1/uImage *****
fi
echo ***** RootFS: /dev/mmcblk0p2 *****
setenv bootargs 'mem=68M@0x80000000 mem=128M@0x88000000 console=tty0 console=ttyO0,115200n8 androidboot.console=ttyO0 root=/dev/mmcblk0p2 rw rootfstype=ext3 init=/init rootwait ip=off mpurate=1000 vram=32M omapfb.vram=0:16M'
我们可以看到原来这个文件也就是完成了bootargs的设置,原来如此,像我这也是第一次打开这个文件,要不是遇到这个问题。好下面我们仔细看一下这个设置的参数。
关键就在于这个mem的设置,才使得cmemk.ko可以加载成功
mem=68M@0x80000000 mem=128M@0x88000000 意思就是从0x80000000 到0x84f00000开辟68M内存,从0x88000000 到0x90000000 开辟128M内存专门给arm端的linux使用,那为什么要设置成这样呢,下面我们再来看一个boot.src:
then
echo ***** Kernel: /dev/mmcblk0p1/uImage *****
fi
echo ***** RootFS: /dev/mmcblk0p2 *****
setenv bootargs 'console=ttyO0,115200n8 androidboot.console=ttyO0 mem=256M root=/dev/mmcblk0p2 rw rootfstype=ext3 rootdelay=1 init=/init ip=off omap_vout.vid1_static_vrfb_alloc=y vram=8M omapfb.vram=0:8M'
通过比较我们可发现最大区别就在与mem的设置,出现这个情况就是,前者要使用codec enginer 让arm和dsp通信,完成硬件加速,在两者之间需要专门开辟一块连续的内存
给dsp使用,而这个内存也是可以和arm共享的,主要原因我的理解是linux使用的是虚拟内存的概念,而dsp上的bios没有这种机制,因此如果有一个数据块,在linux放在一个虚拟地址上,那么也许这个虚拟地址刚好是处于动态映射区那么这个所对应的实际物理地址很可能就是不连续的,那样dsp就不能调用这段数据。为了防止这个的出现,cmem就是开辟连续共享内存的一个机制,他使得在arm和dsp通信时,arm端的虚拟地址就会通过cmem制定出连续的物理地址供给dsp调用,而这个连续的内存块的大小就是在insmod时传入的参数,phys_start=0x84f00000 phys_end=0x85900000 大概是10M的大小,其实最大可以到60M(0x87ffffff),但是够用就不用浪费.
因此我们看到第二组的mem=256M,一看就知道是不使用dvsdk,或者可以理解不是dsp,不起dsp端的服务,只是把dsp做为个硬件模块来使用。
因此,整个问题最终就是归结在mem的设置,这个mem的大小是传递给linux内核,告知其linux占用256M,不会有独立内存分配给dsp等等。针对davnic平台来说,mem=256M的设置基本是不支持codec enginer的,而他只是运行linux,不运行dsp 的bios。
最终整个问题都得到解决,一个星期也没有白费,学到很多,特别感谢一位网友师兄,哈哈,大家一起加油