0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linux為何引入devres機制

嵌入式軟件開發(fā)交流 ? 來源:嵌入式軟件開發(fā)交流 ? 2023-05-22 09:50 ? 次閱讀

devres簡介

在驅動中經常要在初始化函數(shù)或probe函數(shù)中對設備分配一些資源,比如:irq、regulator、gpio等。在驅動進行初始化的時候如果失敗,那么通常會goto到某個地方釋放資源。有時候編寫驅動時會忘記釋放資源,Linux為了解決這個問題而引入了devres機制。devres 是一種設備資源管理機制(device resource management), 類似于一種垃圾收集處理器。而資源的處理時機是在驅動的 install / remove 時候。這樣我們在為設備分配相關資源之后, 就不必要關心如何釋放它們了。

設備資源

Linux中設備資源包含:

Power

Clock

Memory

GPIO

IRQ

DMA

虛擬地址空間

API函數(shù)

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;
}

通過上面的比對大概能知道這些函數(shù)的差別了。

總結

目前除了一些舊代碼之外,大部分驅動都使用devres相關的接口。也推薦大家在代碼中更多的使用相關接口,這樣代碼會更簡潔,不容易出現(xiàn)內存泄露。

審核編輯:彭靜
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 處理器
    +關注

    關注

    68

    文章

    19286

    瀏覽量

    229866
  • Linux
    +關注

    關注

    87

    文章

    11304

    瀏覽量

    209535
  • 函數(shù)
    +關注

    關注

    3

    文章

    4331

    瀏覽量

    62629

原文標題:Linux devres機制

文章出處:【微信號:嵌入式軟件開發(fā)交流,微信公眾號:嵌入式軟件開發(fā)交流】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    SPM引入的顆粒FSI無法去除,不知為何?

    有時候,SH(SPM)后,會引入較多顆粒,一般在后面的FSI清洗中可以去除95%,但有的時候SH去膠后引入的顆粒,用FSI清洗無法去除,不知為何?有哪位同仁知道的請指點。
    發(fā)表于 04-14 10:44

    SPM引入的顆粒,為何FSI也無法去除?

    有時候,SH(SPM)后,會引入較多顆粒,一般在后面的FSI清洗中可以去除95%,但有的時候SH去膠后引入的顆粒,用FSI清洗無法去除,不知為何?有哪位同仁知道的請指點。
    發(fā)表于 04-14 14:37

    Linux 機制分析

    走入 Linux 的殿堂已經有一年有余了,在這里我想將 Linux 的各種實現(xiàn)機制分析一遍,一方面對自己來說也是溫故而知新,另一方面,促進大家的交流,最好能夠給大家一些拋磚引玉的啟迪。我是硬件出身
    發(fā)表于 05-21 09:51

    Linux的platform機制開發(fā)驅動流程是怎么樣的?

    Linux 2.6起引入了一套新的驅動管理和注冊機制:platform_device和platform_driver。Linux中大部分的設備驅動,都可以使用這套
    發(fā)表于 09-23 07:31

    詳解Linux能力機制

    Linux能力機制
    發(fā)表于 04-20 08:23

    shell原理和問答機制引入推薦

    1.16.ARM裸機第十六部分-shell原理和問答機制引入 互聯(lián)網課程品牌...
    發(fā)表于 12-23 06:12

    為何ARMv8-a架構要引入EL3呢

    ARMv8-a架構是由哪些部分組成的呢?為何ARMv8-a架構要引入EL3呢?
    發(fā)表于 03-02 09:12

    Linux與VxWorks任務調度機制分析

    Linux與VxWorks任務調度機制分析
    發(fā)表于 03-28 09:52 ?19次下載

    linux內存管理機制淺析

    本內容介紹了arm linux內存管理機制,詳細說明了linux內核內存管理,linux虛擬內存管理,arm linux內存管理等方面的知識
    發(fā)表于 12-19 14:09 ?73次下載
    <b class='flag-5'>linux</b>內存管理<b class='flag-5'>機制</b>淺析

    linux內核機制有哪些

     在操作系統(tǒng)引入了進程概念,進程成為調度實體后,系統(tǒng)就具備了并發(fā)執(zhí)行多個進程的能力,但也導致了系統(tǒng)中各個進程之間的資源競爭和共享。另外,由于中斷、異常機制引入,以及內核態(tài)搶占都導致了這些內核執(zhí)行
    發(fā)表于 11-14 15:25 ?5568次閱讀
    <b class='flag-5'>linux</b>內核<b class='flag-5'>機制</b>有哪些

    Linux系統(tǒng)的fork運行機制分析

    如果其中一個進程的輸出結果是“pid1:1001, pid2:1002”,寫出其他進程的輸出結果(不考慮進程執(zhí)行順序)。 明顯這道題的目的是考察linux下fork的執(zhí)行機制。下面我們通過分析這個題目,談談Linux下fork
    發(fā)表于 04-26 16:26 ?1166次閱讀
    <b class='flag-5'>Linux</b>系統(tǒng)的fork運行<b class='flag-5'>機制</b>分析

    Linux Device Tree的基本概念

    一些背景知識(例如:為何引入Device Tree,這個機制是用來解決什么問題的)請參考引入Device Tree的原因,本文主要是介紹Device Tree的基礎概念。
    發(fā)表于 05-10 11:33 ?1185次閱讀
    <b class='flag-5'>Linux</b> Device Tree的基本概念

    Linux內核驅動的platform機制是怎樣的

    Linux 2.6起引入了一套新的驅動管理和注冊機制:platform_device和platform_driver。
    發(fā)表于 11-06 14:12 ?1637次閱讀
    <b class='flag-5'>Linux</b>內核驅動的platform<b class='flag-5'>機制</b>是怎樣的

    Linux內核文件Cache機制

    Linux內核文件Cache機制(開關電源技術與設計 第二版)-Linux內核文件Cache機制? ? ? ? ? ? ? ??
    發(fā)表于 08-31 16:34 ?4次下載
    <b class='flag-5'>Linux</b>內核文件Cache<b class='flag-5'>機制</b>

    zookeeper引入什么機制

    Zookeeper是一個開源的分布式協(xié)調服務,被廣泛應用于構建分布式系統(tǒng)和大規(guī)模集群的管理。作為一個分布式協(xié)調服務,Zookeeper引入了一系列機制來提供可靠的協(xié)調和一致性服務。在這篇文章中,我們
    的頭像 發(fā)表于 12-03 16:38 ?871次閱讀