Linux Reserved Memory 預留內存


原文地址:
Linux Reserved Memory
https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18841683/Linux+Reserved+Memory

前言

基於Xilinx Zynq SoC / MPSoC的系統的常見要求之一是爲特殊用途預留內存。預留的內存區域需要從linux內核的使用區域中分離出來,僅給特點的驅動程序使用。
reserved-memory 架構包含了預留內存的功能。預留內存的功能又與內核中的DMA-API和CMA框架密切相關。

本文旨在展示和解釋一些可用的用例,並且已經使用Petalinux構建工具進行了測試。由於本文中的修改僅涉及DTS文件定製和設備驅動程序中分配內存位置的改動,還是可以將其導出到Yocto或OSL工作流程中的。

預留內存給設備驅動

爲了從系統地址空間預留內存,設備樹須配置預留內存的節點。
每個節點定義一個特定的內存空間,並且可以根據內核文檔中關於可用於預留內存節點的說明配置不同的參數。
然後就可以通過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>;
   };

或32位Cortex-A9 Zynq上,最新的基於Yocto的Petalinux的自定義的類似的設備樹節點:

/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);

由於保留的內存區域已被內核排除,並標記爲no-map,因此iomem信息(/ proc / iomem)顯示系統RAM小於主板中的內存量。

root@plnx_aarch64:~# cat /proc/iomem
00000000-6fffffff : System RAM
  00080000-00b37fff : Kernel code
  011c9000-012b8fff : Kernel data

加載設備後,可以確認內存分配:

[  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的方式使用預留的內存,對於這種場景,可以dts中的節點屬性設置爲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內存池,它將使用該特定設備的預留內存區域。
(獨佔這一塊內存,仍然使用DMA的接口)

/* 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);

內核啓動的log:

[    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

驅動加載的log:

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內存池。
屬性:
reusable;
linux,cma-default

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;
      };
   };

內核啓動關於CMA分配的log:

[    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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章