在實際應用中,需要保留一段專用內存,給驅動程序或者應用程序,比如給PL 訪問的一段內存,用於查表,等等。
本文介紹如何在petalinlux 裏實現保留一段內存。在這裏我引用原文有3種方式預留內存:普通的,DMA,CMA。我的應用中打算使用普通的,32位方式。但這裏3種方式都介紹。
其中重要的參考來自:https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841683/Linux+Reserved+Memory
預留內存
要從系統地址空間保留內存範圍,可以在設備樹配置中使用保留的內存節點。 每個子節點定義一個特定的內存空間,並且可以根據內核文檔中所述可用於保留內存節點的不同參數進行配置。 然後可以通過memory-region參數將保留的存儲空間分配給特定的設備驅動程序。
用於64位Cortex-A53 MPSoC的system-top.dts文件中的設備樹節點:
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
reserved: buffer@0 {
no-map;
reg = <0x0 0x70000000 0x0 0x10000000>;
};
};
reserved-driver@0 {
compatible = "xlnx,reserved-memory";
memory-region = <&reserved>;
};
或者在基於Yocto的Petalinux project-spec / meta-user / recipes-bsp / device-tree / files / system-user.dtsi 中針對32位Cortex-A9 Zynq進行定製的類似設備樹節點:
/include/ "system-conf.dtsi"
/ {
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
reserved: buffer@0x38000000 {
no-map;
reg = <0x38000000 0x08000000>;
};
};
reserved-driver@0 {
compatible = "xlnx,reserved-memory";
memory-region = <&reserved>;
};
};
在設備驅動程序中,可以通過解析設備樹節點來處理內存區域的屬性,並且一旦知道了物理地址和大小,就可以使用memremap / ioremap調用來映射內存區域。 下面的代碼引用了保留的內存分配:
/* Get reserved memory region from Device-tree */
np = of_parse_phandle(dev->of_node, "memory-region", 0);
if (!np) {
dev_err(dev, "No %s specified\n", "memory-region");
goto error1;
}
rc = of_address_to_resource(np, 0, &r);
if (rc) {
dev_err(dev, "No memory address assigned to the region\n");
goto error1;
}
lp->paddr = r.start;
lp->vaddr = memremap(r.start, resource_size(&r), MEMREMAP_WB);
dev_info(dev, "Allocated reserved memory, vaddr: 0x%0llX, paddr: 0x%0llX\n", (u64)lp->vaddr, lp->paddr);
由於保留的內存區域已被內核排除以用於通用,並標記爲無映射,因此iomem信息(/ proc / iomem)顯示系統RAM小於板上的內存量。
root@plnx_aarch64:~# cat /proc/iomem
00000000-6fffffff : System RAM
00080000-00b37fff : Kernel code
011c9000-012b8fff : Kernel data
Once the device is loaded, the allocation can be confirmed:
[ 126.191774] reserved-memory reserved-driver@0: Device Tree Probing
[ 126.198595] reserved-memory reserved-driver@0: Allocated reserved memory, vaddr: 0xFFFFFF8020000000, paddr: 0x70000000
通過DMA API保留的內存
通常,保留內存空間與DMA引擎一起使用,因此從設備驅動程序的角度來看,集成這兩個框架可能很有用。 對於該特定目的,可以將兼容屬性設置爲shared-dma-pool,從而生成爲特定設備驅動程序保留的DMA內存池。
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
reserved: buffer@0 {
compatible = "shared-dma-pool";
no-map;
reg = <0x0 0x70000000 0x0 0x10000000>;
};
};
reserved-driver@0 {
compatible = "xlnx,reserved-memory";
memory-region = <&reserved>;
};
這樣,設備驅動程序僅需要以常規方式使用DMA API,但無需使用默認的CMA內存池,而是將爲此特定設備使用保留的內存區域。
/* Initialize reserved memory resources */
rc = of_reserved_mem_device_init(dev);
if(rc) {
dev_err(dev, "Could not get reserved memory\n");
goto error1;
}
/* Allocate memory */
dma_set_coherent_mask(dev, 0xFFFFFFFF);
lp->vaddr = dma_alloc_coherent(dev, ALLOC_SIZE, &lp->paddr, GFP_KERNEL);
dev_info(dev, "Allocated coherent memory, vaddr: 0x%0llX, paddr: 0x%0llX\n", (u64)lp->vaddr, lp->paddr);
內核日誌是這樣的:
[ 0.000000] Reserved memory: created DMA memory pool at 0x0000000070000000, size 256 MiB
[ 0.000000] Reserved memory: initialized node buffer@0, compatible id shared-dma-pool
[ 0.000000] cma: Reserved 128 MiB at 0x0000000068000000
在啓動驅動程序後,內核日誌是這樣的:
root@plnx_aarch64:~# insmod /lib/modules/4.6.0-xilinx/extra/reserved-memory.ko
[ 80.745166] reserved-memory reserved-driver@0: Device Tree Probing
[ 80.750183] reserved-memory reserved-driver@0: assigned reserved memory node buffer@0
[ 81.220878] reserved-memory reserved-driver@0: Allocated coherent memory, vaddr: 0xFFFFFF8020000000, paddr: 0x70000000
爲CMA保留的內存
有時,不需要將保留的內存區域分配給特定的設備驅動程序,而只打算擁有比默認的更大的CMA內存池。 對於該特定用例,可以使用一個額外的屬性來指向內核,以將保留的內存區域用作默認的CMA內存池。
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
reserved: buffer@0 {
compatible = "shared-dma-pool";
reusable;
reg = <0x0 0x70000000 0x0 0x10000000>;
linux,cma-default;
};
};
內核日誌是這樣的:
[ 0.000000] Reserved memory: created CMA memory pool at 0x0000000070000000, size 256 MiB
[ 0.000000] Reserved memory: initialized node buffer@0, compatible id shared-dma-pool