提供されたAPIを条件付きで以下に分割します。
- DMAおよびI / Oに割り当てられたものを含むメモリ
- 中断
- 電圧調整器
- バスドライバー(PCI、SPI、IIO)の場合
- GPIO、ピン制御
- 残り
各カテゴリで、利用可能な機能のリストと、必要に応じて注意する価値のある追加情報を提供します。 しかし、最初に、これらのリソースがどのように管理されるかの原理について簡単に説明します。
デバイスのリソース管理
2007年、Tejun Heoは、いわゆるdevres APIを作成することにより、管理対象デバイスリソースを使用してデバイスドライバーを簡素化することを提案しました。
2007年の事例
コミット9ac7849e35f705830f7b016ff272b0ff1f7ff759
著者:Tejun Heo <htejun@gmail.com>
devres:デバイスのリソース管理
著者: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にあります。