そのDevice Notificationだが、ただ一般的なInterruptとはちょっと異なる。通常のInterruptの場合、それがHost側に通知されるとControllerはCPUに対しInterruptを上げ、それがKernel内部でDispatchされ、Device DriverのISRをKickし、ISRにHookした割り込み処理ロジックを呼び出す様なイメージになる訳だが、USB 3.0はApplication I/F(厳密に言えば、Base DriverへのAPIというべきだろうか。Class DriverやFilter Driverなどもここに含まれるからだ)がUSB 2.0までと完全に互換であることを設計目標としているから、いまさらこうした従来のInterruptのHandlingを追加すると互換性が崩れてしまう。

そこでDevice Notificationでは、Time Slotを調整するという形で実装が行われた。Device NotificationのPacketの中にNotification Typeを指定する4bitのFieldがあるが、そのFieldは、

0000b Reserved
0001b FUNCTION_WAKE
0010b LATENCY_TOLERANCE_MESSAGE
0011b BUS_INTERVAL_ADJUSTMENT_MESSAGE
0100b-1111b Reserved

と定義されている。このうちFUNCTION_WAKEは文字通りDeviceからHostにWakeup Messageを送るためのもの。昔ならWOR(Wake On Ring : モデムの着信で本体を起動。ちなみにモバイル端末を起動するWake On Radioというものもあるようだ)、今ならWOL(Wake On LAN : LAN経由で本体を起動)などを実装するのに利用できる。

次のLATENCY_TOLERANCE_MESSAGEは、Deviceの応答時間の調整である。これは省電力機構に関係する部分であるが、要するにDeviceを省電力モードにしたい場合、煩雑にUSBの応答を行っていると効果が薄くなる。そこで反応時間を長めにすることで、より長時間待機状態にすることで省電力の効果を高めたい訳だが、例えばInterrupt Transferなどの場合、Maximum service intervalが保障されているから、Deviceが単独で反応時間を延ばすとエラーがあったと判断してRetryや最悪はDevice切り離しがHost側で発生してしまう。これを避けるために、BELT(Best Effort Latency Tolerance)と呼ばれるパラメータが設定可能で、このBELTの値を使ってLatencyを管理することになるが、LATENCY_TOLERANCE_MESSAGEを使うことでこのBELTの値をDeviceからHostに転送できるという仕組みだ。

最後のBUS_INTERVAL_ADJUSTMENT_MESSAGEが、Interruptに関係してくる部分だ。これは名前の通り、Bus Intervalの増減が可能だ。前にも書いたが、Interrupt TransferとIsochronous Transferは、一定期間毎にかならず実施される。第280回でも書いた125μsecがその周期であるが、この時間が変わらない限り、何かイベントが発生しても最悪125μsecの待ちが入る事になる。この待ちを減らし、迅速に反応するためには、周期である125μsecを短くすれば良い事になる。BUS_INTERVAL_ADJUSTMENT_MESSAGEはまさしくこれを行うためのものである。

パケットにはBus Interval Adjustmentという16bitのフィールドが設けられ、BusIntervalAdjustmentGranularityを-32768unit~+32767unitの範囲で変更できる。このBusIntervalAdjustmentGranularityという値は1unit=4096 Bus intervalあたり(USB 2.0の)High Speed Transferの8bit分に相当している。ちょっと判りにくいかもしれないが、数字でいえばおおよそ4.07psほどになる。このオーダーだと、微調整というレベルでしかないが、一応1回あたり最大で±4096unitまで、必要なら複数のDevice Notificationをまとめて出すことでこれ以上(最大でも-32768unit~+32767unit)の調整が可能となっており、これで多少なりともBus Intervalを短縮することが出来るというわけだ。

このあたりは、ただし互換性を考えると無条件に短くするという訳にもいかないのだろう。例えばUSB 2.0との混在環境においては、USB 2.0のEndpoint DeviceはこうしたTimeslotの変更機能を持っていないから、125μsecごとにInterrupt TransferやIsochronous Transferを行うという前提で内部ロジックを構成している。もちろん、通信はあくまでHost側からの制御で行うから、Hostと無関係に(Device内部のClockを使って)125μsec毎にデータを送り出すような実装はありえない。ただ、だからといってHostから50μm毎ににInterrupt Transferの指示が出るような実装は想定していないだろうし、そうした使い方をすると動作しなくなっても不思議ではない。これを避けようとすると、せいぜいが「多少間隔を短くする」程度でしか対処が出来ない。このあたりは互換性を重視する以上、やむをえないのかもしれない。

(続く)