#author("2017-11-07T12:09:12+09:00","default:afuruta","afuruta") #author("2017-11-07T12:11:27+09:00","default:afuruta","afuruta") * HPET Driver [#aa2af7c4] Linux Kernel の HPET(High Precision Event Timer Driver) を見ていきます。HPET のドライバには次の機能が実装されています。 ** 普通の PC の HPET 構造 [#b4e017c0] 次の図は廉価で普及している PC を構成している HPET の構造です。HPET ブロックは PC のチップセット内に 1 組存在します。HPET を構成する timer は PIT と RTC を置換する timer とアプリケーションが自由に使える timer で構成されます。timer の個数は少なくとも 3 個、多い場合は (2 + プロセッサ数) 個 あるいは これより 2, 3 個多くなっています。 #ref(HPETPCModel.png); Interrupt Routing 回路により timer が割り込みをかける IRQ 番号は柔軟に設定できます。HPET timer で PIT(Programmable Interrupt Timer), RTC(Real Time Clock) の割り込みを置換した場合、PIT, RTC から発生する割り込みは PIC あるいは APIC から切り離され補足できなくなります。1 個の timer が発生する割り込みは 1 個の割り込み要因となります。timer が発生する割り込みは他の割り込みと共有できます。ほぼ Low Active の Level 割り込みを使いワイヤード OR による共有となります。 #textbox(note,HPET の最小構成は仕様書を参照してください){{ HPET の最小(必須・オプション)構成は [[HPET specification>https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf]] "2.2 Minimum Recommended Hardware Implementation" を参照してください。多くの PC で実装されている PIT, RTC を置き換える機能はオプション扱いになっています。 }} ** hpet.c ドライバ の HPET 構造 [#o606dbc9] HPET ドライバ &ogfileone(drivers/char/hpet.c); で対応する HPET のハードウエア構成は普及している PC の構造に比べてより複雑です。次の図に示す通り HPET ブロックが PC (プラット・ホーム)内に複数存在している場合に対応しています。ACPI を列挙する call back (&ogdefs(hpet_acpi_add()); の中で使っている &ogrefs(acpi_walk_resources(),acpi_walk_resources,rsxface.c);) を使ったデバイス登録において、複数存在し繰り返し probe された場合にも対応しています。 #ref(HPETStructureInLinuxKernelDriver.png); 始めに発見された HPET は PIT, RTC を置き換える機能があるかもしれません。それ以外の HPET は汎用の timer を複数持つ構成になります。HPET ドライバは複数の HPET がそれぞれ異なる構成・クロック源になるを想定しています。 #textbox(note,HPET ブロックが複数あった場合、アプリケーションは適した HPET ブロックを選べるのか?){{ /dev/hpet を close せずに open していけば順次空いている HPET の timer が割り当てられていくので、探すことはできるかもしれません。一時的であってもプラット・ホームが提供している資源を使い果たすことになるので、平行して HPET timer 資源を獲得しようとするプロセスがあるのならば、資源獲得競争で期待した動作にならない可能性を考慮した方が良いでしょう。 }} &ogfileone(drivers/char/hpet.c); 内のデータ構造と HPET の対応を見ていきます。&ogdefs(hpet_acpi_add()); の中でローカル変数として確保した &ogdefs(hpet_data); 構造体に call back で呼ばれた &ogdefs(hpet_resocues()); が HPET ブロックの物理アドレス(&ogrefs(hd_phys_address,hd_phys_address,hpet.c);)、論理アドレス(&ogrefs(hd_address,hd_address,hpet.c);)、timer 数(&ogrefs(hd_nirqs,hd_nirqs,hpet.c);)、複数の IRQ 番号(&ogrefs(id_irq,hd_irq,hpet.c);)を格納していきます。 &ogfileone(drivers/char/hpet.c); 内のデータ構造と HPET の対応を見ていきます。&ogdefs(hpet_acpi_add()); の中でローカル変数として確保した &ogdefs(hpet_data); 構造体に call back で呼ばれた &ogdefs(hpet_resources()); が HPET ブロックの物理アドレス(&ogrefs(hd_phys_address,hd_phys_address,hpet.c);)、論理アドレス(&ogrefs(hd_address,hd_address,hpet.c);)、timer 数(&ogrefs(hd_nirqs,hd_nirqs,hpet.c);)、複数の IRQ 番号(&ogrefs(id_irq,hd_irq,hpet.c);)を格納していきます。 #ref(HPETStructureWithDataStructure.png); * ほんの触りだけ通ります [#u2ac4260] HPET driver が関係する事柄は多岐にわたります。それぞれを深く追っていると記述量が多くなり、書き切れなくなるのでおおよその理解で十分な範囲で説明していきます。ソースコードを読み進めてある程度自発的に理解を深めることを期待しています。 * 環境準備 [#mb3b5b34] ** HPET を有効にする [#e24ada8c] HPET が存在するか確かめる。 #pre(soft){{ &span(ConsoleOut){$ };&span(ConsoleIn){cat /proc/iomem | grep -i HPET}; &span(Alias,ConsoleOut){ feff0000-feff03ff};&span(ConsoleOut){ : HPET 0}; }} #pre(soft){{ &span(ConsoleOut){$ };&span(ConsoleIn){cd /sys/bus/acpi/devices}; &span(ConsoleOut){$ };&span(ConsoleIn){ls | grep PNP0103}; &span(ConsoleOut){PNP0103:00}; }} * Device Register [#w5daa5b5] ** ACPI device [#dbc409ae] ** memory mapped device [#pd369493] * Device Node [#b644cf52] ** misc device [#b12b4220] ** file_operations [#j3297397] * 割り込み処理 [#w25e4619] ** Share, Level Low High, Edge Rise Fall [#s812608a] ** request_irq() free_irq() [#ff217206] ** IRQ handler [#ifffb723] * User context に割り込みを伝える [#s3d02be6] ** poll [#lc3431a8] ** signal [#m466bf68] ** blocking non-blocking [#v2ac2792] * Test Application [#b3e17334] ** hpet_sample plus [#ofc77fee] ** サンプルアプリが動かない [#xf759f97]