Linux request_mem_region函数的用法及注意事项

request_mem_region 是 Linux 内核中用于申请 I/O 内存区域的函数,主要目的是标记一段物理地址空间为“已占用”,防止其他驱动或模块重复申请同一内存区域,从而避免资源冲突。以下是其用法和注意事项:


函数原型

1
2
3
#include <linux/ioport.h> 

struct resource *request_mem_region(unsigned long start, unsigned long len, const char *name);
  • 参数
    • start:物理内存的起始地址。
    • len:需要申请的内存区域长度(字节数)。
    • name:设备或驱动的名称(用于标识资源所有者,可通过 /proc/iomem 查看)。
  • 返回值
    • 成功:返回非 NULL 的 struct resource 指针。
    • 失败:返回 NULL(表示该内存区域已被占用)。

基本用法

  1. 在驱动初始化阶段申请内存区域

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #define MEM_START 0x30000000  // 物理地址起始
    #define MEM_LEN 0x1000 // 长度 4KB

    static struct resource *mem_region;

    static int __init my_driver_init(void) {
    mem_region = request_mem_region(MEM_START, MEM_LEN, "my_device");
    if (!mem_region) {
    printk(KERN_ERR "Failed to request memory region\n");
    return -EBUSY; // 资源已被占用
    }
    // 后续操作:ioremap、访问硬件等
    return 0;
    }
  2. 在驱动退出时释放内存区域

    1
    2
    3
    4
    5
    static void __exit my_driver_exit(void) {
    if (mem_region) {
    release_mem_region(MEM_START, MEM_LEN);
    }
    }

注意事项

  1. 必须检查返回值

    • request_mem_region 返回 NULL,说明内存区域已被其他驱动占用,不可继续操作该区域,否则会导致系统不稳定或硬件冲突。
  2. ioremap 配合使用

    • request_mem_region 仅标记内存区域为“已占用”,不映射物理地址到内核虚拟地址空间。实际访问硬件前,需通过 ioremapioremap_nocache 获取虚拟地址:
      1
      void __iomem *virt_addr = ioremap(MEM_START, MEM_LEN);
  3. 释放资源必须成对调用

    • 使用 release_mem_region 释放内存区域,通常在模块退出函数中调用。若遗漏释放,可能导致资源泄漏,导致后续无法申请该区域。
  4. 权限与并发访问

    • 确保在访问映射后的内存时使用正确的读写函数(如 readl/writel),避免直接使用指针操作。
    • 若需在多个驱动间共享内存区域,需自行实现同步机制(如互斥锁)。
  5. /proc/iomem 的关系

    • 成功申请的内存区域会出现在 /proc/iomem 中,可通过此文件查看系统内存资源分配情况。
  6. 原子上下文限制

    • request_mem_region 可能调用可能导致睡眠的函数(如 kmalloc),因此不能在原子上下文(如中断处理函数) 中调用。
  7. 现代内核的替代方案

    • 对于设备驱动,推荐使用资源管理 API(如 devm_request_mem_region),它可自动释放资源,避免因驱动卸载时遗漏释放导致的问题:
      1
      struct resource *mem_region = devm_request_mem_region(&pdev->dev, MEM_START, MEM_LEN, "my_device");

常见问题

  • 资源冲突:若驱动无法申请到内存区域,需检查 /proc/iomem 确认是否被其他驱动占用。
  • 地址对齐:确保 startlen 符合硬件要求的对齐方式(如页对齐)。
  • 平台依赖性:物理地址的取值范围与具体硬件平台相关(如 ARM、x86 差异)。

通过合理使用 request_mem_region,可以确保驱动安全地管理硬件资源,避免系统级冲突。