前言
devm是内核提供的基础机制,用于方便驱动开发者所分配资源的自动回收。参考内核文档devres.txt。总的来说,就是驱动开发者只需要调用这类接口分配期望的资源,不用关心释放问题。这些资源的释放会在device对象销毁时自动释放。
devres使用
不同的内核模块提供了对应的devm_xxx接口,如下(不仅仅这些):
MEM
devm_kmalloc()
devm_kzalloc()
devm_kcalloc()
devm_kmalloc_array()
devm_kstrdup()
devm_kfree()
IIO
devm_iio_device_alloc()
devm_iio_device_free()
devm_iio_trigger_alloc()
devm_iio_trigger_free()
devm_iio_device_register()
devm_iio_device_unregister()
IO region
devm_request_region()
devm_request_mem_region()
devm_release_region()
devm_release_mem_region()
IRQ
devm_request_irq()
devm_free_irq()
DMA
dmam_alloc_coherent()
dmam_free_coherent()
dmam_alloc_noncoherent()
dmam_free_noncoherent()
dmam_declare_coherent_memory()
dmam_pool_create()
dmam_pool_destroy()
PCI
pcim_enable_device() : after success, all PCI ops become managed
pcim_pin_device() : keep PCI device enabled after release
IOMAP
devm_ioport_map()
devm_ioport_unmap()
devm_ioremap()
devm_ioremap_nocache()
devm_iounmap()
devm_ioremap_resource() : checks resource, requests memory region, ioremaps
devm_request_and_ioremap() : obsoleted by devm_ioremap_resource()
pcim_iomap()
pcim_iounmap()
pcim_iomap_table() : array of mapped addresses indexed by BAR
pcim_iomap_regions() : do request_region() and iomap() on multiple BARs
REGULATOR
devm_regulator_get()
devm_regulator_put()
devm_regulator_bulk_get()
devm_regulator_register()
CLOCK
devm_clk_get()
devm_clk_put()
PINCTRL
devm_pinctrl_get()
devm_pinctrl_put()
PWM
devm_pwm_get()
devm_pwm_put()
PHY
devm_usb_get_phy()
devm_usb_put_phy()
SLAVE DMA ENGINE
devm_acpi_dma_controller_register()
SPI
devm_spi_register_master()
内核提供了devres_xxx
的机制,并基于devres_xxx
又给出了devres group
机制。devres group
主要用于处理初始化的时候,有多种资源类型需要初始化,每种资源类型的初始化又由多个devres_xxx
资源申请组成的情况,将这些devres_xxx
按类别组合成group,这样在需要显示释放某一类的资源时,调用devres group的api即可实现。内核给出的例子:
if (!devres_open_group(dev, NULL, GFP_KERNEL))//启动group
return -ENOMEM;
acquire A;//申请资源A
if (failed)
goto err;
acquire B;//申请资源B
if (failed)
goto err;
...
devres_remove_group(dev, NULL);//如果一切顺利,那么关掉group
return 0;
err:
devres_release_group(dev, NULL);//如果出错,那么释放掉启动group后所有申请的资源
return err_code;
实现原理
具体的实现很简单,当然我们应该也能猜测到。在分配内存的时候,会分配比我们要求大的空间,空间的前面部分用于存放实现devres机制的数据结构,然后返回的是用户期望的空间的指针(该指针是实际分配的空间指针的devres结构的偏移)。
struct devres_node {
struct list_head entry;//通过该成员,挂接到device的devres链表上
dr_release_t release;//对应的资源释放回调
};
struct devres {
struct devres_node node;
/* -- 3 pointers */
unsigned long long data[]; /* guarantee ull alignment *///实际的数据部分
};
devres采用零长数组的方式实现。