0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux为何引入devres机制

嵌入式软件开发交流 来源:嵌入式软件开发交流 2023-05-22 09:50 次阅读

devres简介

在驱动中经常要在初始化函数或probe函数中对设备分配一些资源,比如:irq、regulator、gpio等。在驱动进行初始化的时候如果失败,那么通常会goto到某个地方释放资源。有时候编写驱动时会忘记释放资源,Linux为了解决这个问题而引入了devres机制。devres 是一种设备资源管理机制(device resource management), 类似于一种垃圾收集处理器。而资源的处理时机是在驱动的 install / remove 时候。这样我们在为设备分配相关资源之后, 就不必要关心如何释放它们了。

设备资源

Linux中设备资源包含:

Power

Clock

Memory

GPIO

IRQ

DMA

虚拟地址空间

API函数

Clock

//drivers/clk/clk-devres.c
devm_clk_get()
devm_clk_put()
devm_clk_hw_register()
devm_of_clk_add_hw_provider()

DMA

//drivers/base/dma-mapping.c
dmaenginem_async_device_register()
dmam_alloc_coherent()
dmam_alloc_attrs()
dmam_declare_coherent_memory()
dmam_free_coherent()
dmam_pool_create()
dmam_pool_destroy()

GPIO

//drivers/gpio/gpiolib-devres.c
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

//drivers/iio/industrialio-core.c
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

//drivers/input/input.c
devm_input_allocate_device()

IO region

//kernel/resource.c
devm_release_mem_region()
devm_release_region()
devm_release_resource()
devm_request_mem_region()
devm_request_region()
devm_request_resource()

IOMAP

//lib/devres.c
devm_ioport_map()
devm_ioport_unmap()
devm_ioremap()
devm_ioremap_nocache()
devm_ioremap_wc()
devm_ioremap_resource()
devm_iounmap()
pcim_iomap()
pcim_iomap_regions()
pcim_iomap_table()
pcim_iounmap()

IRQ

//kernel/irq/devres.c
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()

Memory

//drivers/base/devres.c
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()

PCI

//drivers/pci/probe.c
devm_pci_alloc_host_bridge()
devm_pci_remap_cfgspace()
devm_pci_remap_cfg_resource()
pcim_enable_device()
pcim_pin_device()

Pinctrl

//drivres/pinctrl/core.c
devm_pinctrl_get()
devm_pinctrl_put()
devm_pinctrl_register()
devm_pinctrl_unregister()

Regulator

//drivers/regulator/core.c
devm_regulator_bulk_get()
devm_regulator_get()
devm_regulator_put()
devm_regulator_register()

驱动对比

非devres驱动:

static int __init soc_camera_probe(struct platform_device *pdev)
{
    ...


    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    irq = platform_get_irq(pdev, 0);
    if (!res || (int)irq <= 0) {
        err = -ENODEV;
       goto exit;
   }


   clk = clk_get(&pdev->dev, "csi_clk");
   if (IS_ERR(clk)) {
       err = PTR_ERR(clk);
       goto exit;
   }


   pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
   if (!pcdev) {
       dev_err(&pdev->dev, "Could not allocate pcdev
");
       err = -ENOMEM;
       goto exit_put_clk;
   }


   ...


   /*
    * Request the regions.
    */
   if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) {
       err = -EBUSY;
       goto exit_kfree;
   }


   base = ioremap(res->start, resource_size(res));
   if (!base) {
       err = -ENOMEM;
       goto exit_release;
   }
   ...


   /* request dma */
   pcdev->dma_chan = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_HIGH);
   if (pcdev->dma_chan < 0) {
       dev_err(&pdev->dev, "Can't request DMA for MX1 CSI
");
       err = -EBUSY;
       goto exit_iounmap;
   }
   ...


   /* request irq */
   err = claim_fiq(&fh);
   if (err) {
       dev_err(&pdev->dev, "Camera interrupt register failed
");
       goto exit_free_dma;
   }


   ...
   err = soc_camera_host_register(&pcdev->soc_host);
   if (err)
       goto exit_free_irq;


   dev_info(&pdev->dev, "MX1 Camera driver loaded
");


   return 0;


exit_free_irq:
   disable_fiq(irq);
   mxc_set_irq_fiq(irq, 0);
   release_fiq(&fh);
exit_free_dma:
   imx_dma_free(pcdev->dma_chan);
exit_iounmap:
   iounmap(base);
exit_release:
   release_mem_region(res->start, resource_size(res));
exit_kfree:
   kfree(pcdev);
exit_put_clk:
   clk_put(clk);
exit:
   return err;
}

devres驱动:

static int __init soc_camera_probe(struct platform_device *pdev)
{
    ...


    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    irq = platform_get_irq(pdev, 0);
    if (!res || (int)irq <= 0) {
        return -ENODEV;
    }


   clk = devm_clk_get(&pdev->dev, "csi_clk");
   if (IS_ERR(clk)) {
       return PTR_ERR(clk);
   }


   pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL);
   if (!pcdev) {
       dev_err(&pdev->dev, "Could not allocate pcdev
");
       return -ENOMEM;
   }


   ...


   /*
    * Request the regions.
    */
   if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), DRIVER_NAME)) {
       return -EBUSY;
   }


   base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
   if (!base) {
       return -ENOMEM;
   }
   ...


   /* request dma */
   pcdev->dma_chan = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_HIGH);
   if (pcdev->dma_chan < 0) {
       dev_err(&pdev->dev, "Can't request DMA for MX1 CSI
");
       return -EBUSY;
   }
   ...


   /* request irq */
   err = claim_fiq(&fh);
   if (err) {
       dev_err(&pdev->dev, "Camera interrupt register failed
");
       return err;
   }


   ...
   err = soc_camera_host_register(&pcdev->soc_host);
   if (err)
       return err;


   dev_info(&pdev->dev, "MX1 Camera driver loaded
");


   return 0;
}

通过上面的比对大概能知道这些函数的差别了。

总结

目前除了一些旧代码之外,大部分驱动都使用devres相关的接口。也推荐大家在代码中更多的使用相关接口,这样代码会更简洁,不容易出现内存泄露。

审核编辑:彭静
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 处理器
    +关注

    关注

    68

    文章

    19134

    浏览量

    228914
  • Linux
    +关注

    关注

    87

    文章

    11216

    浏览量

    208786
  • 函数
    +关注

    关注

    3

    文章

    4298

    浏览量

    62350

原文标题:Linux devres机制

文章出处:【微信号:嵌入式软件开发交流,微信公众号:嵌入式软件开发交流】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    SPM引入的颗粒FSI无法去除,不知为何

    有时候,SH(SPM)后,会引入较多颗粒,一般在后面的FSI清洗中可以去除95%,但有的时候SH去胶后引入的颗粒,用FSI清洗无法去除,不知为何?有哪位同仁知道的请指点。
    发表于 04-14 10:44

    SPM引入的颗粒,为何FSI也无法去除?

    有时候,SH(SPM)后,会引入较多颗粒,一般在后面的FSI清洗中可以去除95%,但有的时候SH去胶后引入的颗粒,用FSI清洗无法去除,不知为何?有哪位同仁知道的请指点。
    发表于 04-14 14:37

    Linux 机制分析

    走入 Linux 的殿堂已经有一年有余了,在这里我想将 Linux 的各种实现机制分析一遍,一方面对自己来说也是温故而知新,另一方面,促进大家的交流,最好能够给大家一些抛砖引玉的启迪。我是硬件出身
    发表于 05-21 09:51

    Linux的platform机制开发驱动流程是怎么样的?

    Linux 2.6起引入了一套新的驱动管理和注册机制:platform_device和platform_driver。Linux中大部分的设备驱动,都可以使用这套
    发表于 09-23 07:31

    详解Linux能力机制

    Linux能力机制
    发表于 04-20 08:23

    shell原理和问答机制引入推荐

    1.16.ARM裸机第十六部分-shell原理和问答机制引入 互联网课程品牌...
    发表于 12-23 06:12

    为何ARMv8-a架构要引入EL3呢

    ARMv8-a架构是由哪些部分组成的呢?为何ARMv8-a架构要引入EL3呢?
    发表于 03-02 09:12

    Linux与VxWorks任务调度机制分析

    Linux与VxWorks任务调度机制分析
    发表于 03-28 09:52 19次下载

    linux内存管理机制浅析

    本内容介绍了arm linux内存管理机制,详细说明了linux内核内存管理,linux虚拟内存管理,arm linux内存管理等方面的知识
    发表于 12-19 14:09 73次下载
    <b class='flag-5'>linux</b>内存管理<b class='flag-5'>机制</b>浅析

    linux内核机制有哪些

     在操作系统引入了进程概念,进程成为调度实体后,系统就具备了并发执行多个进程的能力,但也导致了系统中各个进程之间的资源竞争和共享。另外,由于中断、异常机制引入,以及内核态抢占都导致了这些内核执行
    发表于 11-14 15:25 5534次阅读
    <b class='flag-5'>linux</b>内核<b class='flag-5'>机制</b>有哪些

    Linux系统的fork运行机制分析

    如果其中一个进程的输出结果是“pid1:1001, pid2:1002”,写出其他进程的输出结果(不考虑进程执行顺序)。 明显这道题的目的是考察linux下fork的执行机制。下面我们通过分析这个题目,谈谈Linux下fork
    发表于 04-26 16:26 1148次阅读
    <b class='flag-5'>Linux</b>系统的fork运行<b class='flag-5'>机制</b>分析

    Linux Device Tree的基本概念

    一些背景知识(例如:为何引入Device Tree,这个机制是用来解决什么问题的)请参考引入Device Tree的原因,本文主要是介绍Device Tree的基础概念。
    发表于 05-10 11:33 1177次阅读
    <b class='flag-5'>Linux</b> Device Tree的基本概念

    Linux内核驱动的platform机制是怎样的

    Linux 2.6起引入了一套新的驱动管理和注册机制:platform_device和platform_driver。
    发表于 11-06 14:12 1603次阅读
    <b class='flag-5'>Linux</b>内核驱动的platform<b class='flag-5'>机制</b>是怎样的

    Linux内核文件Cache机制

    Linux内核文件Cache机制(开关电源技术与设计 第二版)-Linux内核文件Cache机制                
    发表于 08-31 16:34 4次下载
    <b class='flag-5'>Linux</b>内核文件Cache<b class='flag-5'>机制</b>

    zookeeper引入什么机制

    Zookeeper是一个开源的分布式协调服务,被广泛应用于构建分布式系统和大规模集群的管理。作为一个分布式协调服务,Zookeeper引入了一系列机制来提供可靠的协调和一致性服务。在这篇文章中,我们
    的头像 发表于 12-03 16:38 795次阅读