コードをよりきれいにしましょう:デバイスドライバー用のLinuxカーネルの管理対象リソースについて一言

Linuxカーネルに表示されるドライバーを見ると、開発者はカーネルインフラストラクチャ、またはデバイスドライバーを記述する際の生活を大幅に簡素化する内部APIについて十分に知らないことに注意するしかありません。 今日は、管理対象リソースのトピックに触れます。 特に、それらがどのように機能し、どのようにドライバー開発を簡素化するかを説明します。



提供されたAPIを条件付きで以下に分割します。





各カテゴリで、利用可能な機能のリストと、必要に応じて注意する価値のある追加情報を提供します。 しかし、最初に、これらのリソースがどのように管理されるかの原理について簡単に説明します。



デバイスのリソース管理



2007年、Tejun Heoは、いわゆるdevres APIを作成することにより、管理対象デバイスリソースを使用してデバイスドライバーを簡素化することを提案しました。



2007年の事例
コミット9ac7849e35f705830f7b016ff272b0ff1f7ff759

著者:Tejun Heo <htejun@gmail.com>



devres:デバイスのリソース管理



その考え方は次のとおりです。 Linuxカーネルのデバイスツリーには、各デバイスにstruct device



表現struct device



deviceがあります。 devres_head



フィールドがdevres_head



(実際にはアクセス同期用の別のフィールド)に追加されました。これは、ステージ->probe()



使用された場合、管理対象リソースのリストを示します。 管理リソースには、何らかのデータ構造に関連付けられたヒープ上のメモリが割り当てられます。たとえば、 kmalloc()



場合、それは単なるvoid *



ポインターです。



ステージ->probe()



、既に述べたように、管理されたリソースのリストが補充されます。ステージ->remove()



で、ドライバーサービスの主要部分自体が、占有されているすべてのリソースを追加とまったく逆の順序で解放します。



例外的なケースの場合、対応するリリースをより早く明示的に引き起こすことができます。 ここに問題があります。次のパートの例を使用して分析します。



DMAおよびI / Oに割り当てられたものを含むメモリ



次の基本関数を使用して、メモリを割り当てることができます。

devm_kasprintf()

devm_kcalloc()

devm_kmalloc()

devm_kmemdup()

devm_kstrdup()

devm_kzalloc()



私の意見ではそれぞれの目的は明らかであり、これについては詳しく語りません。 使用例に移りましょう。



構造にメモリを割り当て、ドライバーが終了したときに自動的に解放されるようにするとします。

 struct my_cool_device { struct device *dev; void *memregion; }; int mydev_probe(...) { struct device *dev = ...; struct my_cool_device *cool; cool = devm_kzalloc(dev, ...); if (!cool) return -ENOMEM; cool->memregion = devm_kmalloc(dev, ...); if (!cool->memregion) return -ENOMEM; cool->dev = dev; dev_info(dev, "Found my cool device\n"); return 0; } void mydev_remove(...) { /* Nothing! */ }
      
      







関数の途中でエラーが発生したときに、出口パスがどれほど美しいかに気づきましたか? そして、それはどのように素晴らしい->remove()







何らかの理由でこれを明示的に行う必要がある場合、リソースを解放する方法の例を次に示します。

正しく:

 void mydev_remove(...) { struct device *dev = ...; struct my_cool_device *cool = ...; devm_kfree(dev, cool->memregion); }
      
      





間違った:

 void mydev_remove(...) { struct my_cool_device *cool = ...; kfree(cool->memregion); }
      
      







DMAの使用に適したメモリを割り当てるには

dmam_alloc_coherent()

dmam_alloc_noncoherent()

dmam_pool_create()



I / Oリソースは、以下の機能を使用して割り当てることができます。

devm_ioport_map()

devm_ioremap()

devm_ioremap_resource():リソースをチェックし、メモリ領域を要求し、デバイスの物理アドレスに投影します

pcim_iomap()

pcim_iomap_regions():領域を照会し、必要なBARで指定された物理アドレスをその領域に投影します

pcim_iomap_table():BAR番号でインデックス付けされた予測アドレスの配列



下部はPCIバス上のデバイスを指しますが、同時にI / Oカテゴリに配置されることに注意してください。



中断



devm_request_any_context_irq()

devm_request_irq()

devm_request_threaded_irq()





電圧調整器



devm_regulator_bulk_get()

devm_regulator_get()

devm_regulator_register()





バスドライバー(PCI、SPI、IIO)の場合



バスIIO:

devm_iio_device_alloc()

devm_iio_device_register()

devm_iio_kfifo_allocate()

devm_iio_trigger_alloc()



MDIOバス:

devm_mdiobus_alloc()

devm_mdiobus_alloc_size()



PCIバス:

pcim_enable_device():成功した場合、すべての操作が管理されていると見なされます

pcim_pin_device():リリース後にデバイスを許可したままにする



pcim_enable_device()



特に注意してpcim_enable_device()



。 適用したら、選択と投影が古い方法で実行されている場合でも、領域のリリースをクリーンアップする必要があります。 たとえば、 コミット5618955c4269で詳細を確認できます。



SPIバス:

devm_spi_register_master()





GPIO、ピン制御



GPIO:

devm_gpiod_get()

devm_gpiod_get_index()

devm_gpiod_get_index_optional()

devm_gpiod_get_optional()



ピン制御:

devm_pinctrl_get()



残り



リソース管理で最も一般的で使用されているヘルパー関数のみに触れました。 残りは、カーネルAPIの対応するドキュメントであるdevres.txtにあります。



All Articles