linux kernel中devres机制

按照惯例!引言!有没有觉得在编写驱动的时候总是要手动kmalloc再kfree很麻烦!不管是申请内存,各种资源的申请之后都需要手动去释放,如果只是加载和卸载的时候还是可以接受的,关键是在处理错误情况的时候,需要仔细的核对释放的顺序和需要释放的内容,既繁琐又容易出错。那么linux kernel有没有给我们提供什么工具来解决这个问题呢!(废话当然有,没有哪来的这片博客)这就是devres了,全程是managed device resource,设备资源管理。

如何使用devres

使用起来很简单了,linux提供了不同的内核模块对应的devm_前缀的接口,只要调用这些接口,这些资源就会在device销毁的时候自动释放。接口列表如下:

CLOCK
  devm_clk_get()
  devm_clk_put()
  devm_clk_hw_register()
  devm_of_clk_add_hw_provider()

DMA
  dmam_alloc_coherent()
  dmam_alloc_attrs()
  dmam_declare_coherent_memory()
  dmam_free_coherent()
  dmam_pool_create()
  dmam_pool_destroy()

GPIO
  devm_gpiod_get()
  devm_gpiod_get_index()
  devm_gpiod_get_index_optional()
  devm_gpiod_get_optional()
  devm_gpiod_put()
  devm_gpiochip_add_data()
  devm_gpiochip_remove()
  devm_gpio_request()
  devm_gpio_request_one()
  devm_gpio_free()

IIO
  devm_iio_device_alloc()
  devm_iio_device_free()
  devm_iio_device_register()
  devm_iio_device_unregister()
  devm_iio_kfifo_allocate()
  devm_iio_kfifo_free()
  devm_iio_triggered_buffer_setup()
  devm_iio_triggered_buffer_cleanup()
  devm_iio_trigger_alloc()
  devm_iio_trigger_free()
  devm_iio_trigger_register()
  devm_iio_trigger_unregister()
  devm_iio_channel_get()
  devm_iio_channel_release()
  devm_iio_channel_get_all()
  devm_iio_channel_release_all()

INPUT
  devm_input_allocate_device()

IO region
  devm_release_mem_region()
  devm_release_region()
  devm_release_resource()
  devm_request_mem_region()
  devm_request_region()
  devm_request_resource()

IOMAP
  devm_ioport_map()
  devm_ioport_unmap()
  devm_ioremap()
  devm_ioremap_nocache()
  devm_ioremap_wc()
  devm_ioremap_resource() : checks resource, requests memory on, maps
  devm_iounmap()
  pcim_iomap()
  pcim_iomap_regions()  : do request_region() and iomap() on iple 
  pcim_iomap_table()    : array of mapped addresses indexed by BAR
  pcim_iounmap()

IRQ
  devm_free_irq()
  devm_request_any_context_irq()
  devm_request_irq()
  devm_request_threaded_irq()
  devm_irq_alloc_descs()
  devm_irq_alloc_desc()
  devm_irq_alloc_desc_at()
  devm_irq_alloc_desc_from()
  devm_irq_alloc_descs_from()
  devm_irq_alloc_generic_chip()
  devm_irq_setup_generic_chip()
  devm_irq_sim_init()

LED
  devm_led_classdev_register()
  devm_led_classdev_unregister()

MDIO
  devm_mdiobus_alloc()
  devm_mdiobus_alloc_size()
  devm_mdiobus_free()

MEM
  devm_free_pages()
  devm_get_free_pages()
  devm_kasprintf()
  devm_kcalloc()
  devm_kfree()
  devm_kmalloc()
  devm_kmalloc_array()
  devm_kmemdup()
  devm_kstrdup()
  devm_kvasprintf()
  devm_kzalloc()

MFD
  devm_mfd_add_devices()

MUX
  devm_mux_chip_alloc()
  devm_mux_chip_register()
  devm_mux_control_get()

PER-CPU MEM
  devm_alloc_percpu()
  devm_free_percpu()

PCI
  devm_pci_alloc_host_bridge()  : managed PCI host bridge cation
  devm_pci_remap_cfgspace() : ioremap PCI configuration space
  devm_pci_remap_cfg_resource() : ioremap PCI configuration space 
  pcim_enable_device()      : after success, all PCI ops become ged
  pcim_pin_device()     : keep PCI device enabled after release

PHY
  devm_usb_get_phy()
  devm_usb_put_phy()

PINCTRL
  devm_pinctrl_get()
  devm_pinctrl_put()
  devm_pinctrl_register()
  devm_pinctrl_unregister()

POWER
  devm_reboot_mode_register()
  devm_reboot_mode_unregister()

PWM
  devm_pwm_get()
  devm_pwm_put()

REGULATOR
  devm_regulator_bulk_get()
  devm_regulator_get()
  devm_regulator_put()
  devm_regulator_register()

RESET
  devm_reset_control_get()
  devm_reset_controller_register()

SERDEV
  devm_serdev_device_open()

SLAVE DMA ENGINE
  devm_acpi_dma_controller_register()

SPI
  devm_spi_register_master()

WATCHDOG
  devm_watchdog_register_device()

原理

这个功能使用起来真是方便,不过他的原理是怎样的呢?以dmam_alloc_coherent()为例,实际申请得到的是下面这个结构体。

struct dma_devres {
    size_t      size;
    void        *vaddr;
    dma_addr_t  dma_handle;
  };

将这些结构体使用链表连接起来,在申请的时候加入链表,销毁对象的时候按照链表中的内容依次释放,就实现了对这些资源的管理。

总结时间

内容太少啦也没啥好总结的,总之新版内核给我们提供的一些新的特性还是要学习使用的,又方便又减少出错,何乐而不为呢?

参考文献
linux documendation:https://www.kernel.org/doc/Documentation/driver-model/devres.txt

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注