调整ZONE_DMA32区域

问题场景:

arm64 开启了CONFIG_ZONE_DMA32,其区域默认是offset ~ offset+4G,其中offset一般为0,但是部分驱动无法完全访问到4G,需要限制DMA32区域的范围为0-2G。


qemu提取dts文件

尝试在qemu上调整一下ZONE_DMA32的大小,按照如下步骤导出qemu的dts文件:
./dtc -o dump.dts -O dts -I dtb dump.dtb
qemu-system-aarch64 -machine virt,dumpdtb=dump.dtb
cp dump.dtb linux/scripts/dtc/
cd linux/scripts/dtc/
make        这步如果内核已经编译过了,可以跳过。
./dtc -o dump.dts -O dts -I dtb dump.dtb
生成的dts文件之后打开可见如下内存范围为0x40000000-0x80000000默认是1~2G内存范围,
359         memory {
360                 reg = <0x00 0x40000000 0x00 0x8000000>;
361                 device_type = "memory";
362         }; 

通过qemu的cmdline可以传入例如8192m以调整内存大小。


内核调整DMA ZONE的关键节点

 对于x8664位系统: 

        x86_64 needs two ZONE_DMAs because it supports devices that are only able to do DMA         to the lower 16M but also 32 bit devices that  can only do DMA areas below 4G.

而对于arm64位系统:只有一个ZONE_DMA32 ,在zone_sizes_init会确定ZONE DMA32、ZONE_NORMAL的大小,DMA32的尽头就是NORMAL的开始。max_dma即 PFN_DOWN(arm64_dma_phys_limit),那么只要调整arm64_dma_phys_limit即可调整ZONE_DMA32的范围。

static void __init zone_sizes_init(unsigned long min, unsigned long max)
{
	struct memblock_region *reg;
	unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
	unsigned long max_dma = min;

	memset(zone_size, 0, sizeof(zone_size));

	/* 4GB maximum for 32-bit only capable devices */
#ifdef CONFIG_ZONE_DMA32
	max_dma = PFN_DOWN(arm64_dma_phys_limit);
	zone_size[ZONE_DMA32] = max_dma - min;
#endif
	zone_size[ZONE_NORMAL] = max - max_dma;

	memcpy(zhole_size, zone_size, sizeof(zhole_size));

。。。

}

通过cmdline来定制ZONE_DMA32的最大值,修改diff如下:

+static unsigned long dma_reset_end = 0;
+static int __init dma_reset_end_setup(char *str)
+{
+	static int once;
+	if (once)
+		return 0;
+	once = 1;
+	dma_reset_end = memparse(str, &str);
+	printk("dma_reset_end=0x%lx\n", dma_reset_end);
+	return 0;
+}
/*
 * Return the maximum physical address for ZONE_DMA32 (DMA_BIT_MASK(32)). It
 * currently assumes that for memory starting above 4G, 32-bit devices will
 * use a DMA offset.
 */
static phys_addr_t __init max_zone_dma_phys(void)
{
+	phys_addr_t max;
	phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
-   return min(offset + (1ULL << 32), memblock_end_of_DRAM());
-}
+	max =  min(offset + (1ULL << 32), memblock_end_of_DRAM());
+	if (dma_reset_end)
+		max = min(max, dma_reset_end);
+	return max;
+}

在cmdline增加dma_reset_end定制

Kernel command line: root=/dev/sda rodata=off rdinit=/usr/sbin/init kgdboc=ttyAMA0,115200 rootfstype=ramfs loglevel=7 slub_debug=u dma_reset_end=0x90000000 console=ttyAMA0 rw

修改效果:


修改前:
[    0.000000] Zone ranges:
[    0.000000]   DMA32    [mem 0x0000000040000000-0x00000000ffffffff]——范围1G-4G
[    0.000000]   Normal   [mem 0x0000000100000000-0x000000023fffffff]——范围4G-9G
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000040000000-0x000000023fffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000040000000-0x000000023fffffff]
[    0.000000] On node 0 totalpages: 131072
[    0.000000]   DMA32 zone: 60 pages used for memmap
[    0.000000]   DMA32 zone: 0 pages reserved
[    0.000000]   DMA32 zone: 49152 pages, LIFO batch:3
[    0.000000]   Normal zone: 100 pages used for memmap
[    0.000000]   Normal zone: 81920 pages, LIFO batch:3
[    0.000000]   Kernel command line: root=/dev/sda rodata=off rdinit=/usr/sbin/init kgdboc=ttyAMA0,115200 rootfstype=ramfs loglevel=7  slub_debug=u console=ttyAMA0 rw

修改后:
[    0.000000] max_dma_phys have been modified. old:0x100000000 new:0x90000000
[    0.000000] Zone ranges:
[    0.000000]   DMA32    [mem 0x0000000040000000-0x000000008fffffff]——范围是1G-2.25G
[    0.000000]   Normal   [mem 0x0000000090000000-0x000000023fffffff]——范围2.25G-9G
[    0.000000] Movable zone start for each node
[    0.000000] Kernel command line: root=/dev/sda rodata=off rdinit=/usr/sbin/init kgdboc=ttyAMA0,115200 rootfstype=ramfs loglevel=7  slub_debug=u dma_reset_end=0x90000000 console=ttyAMA0 rw 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值