コンピューターの電源を完全にオフにしてから再びオンにしたときにのみ正しく機能するPCIeデバイスがあります。単純なreboot
またはreboot -p
コマンドを発行しても、PCIeカードの電源が入れ直されず、再起動後に機能しなくなります。
OSからPCIeスロット内のデバイスの電源を入れ直す方法はありますか? /sys/bus/pci/devices/0000*/
で確認できますが、ボードを正しくリセットする方法がわかりません。力を切り替えることが唯一の方法のようです。
それがなければ、reboot
コマンドで完全な電源再投入を引き起こす設定をどこかに変更できますか?
ちなみに私はUbuntu 12.10を実行しています。
私はあなたがこれらのコマンドでそれを行うことができると思います:
無効にする
echo 0 > /sys/bus/pci/slots/$NUMBER/power
enable
echo 1 > /sys/bus/pci/slots/$NUMBER/power
どこ $NUMBER
はPCIスロットの番号です。
lspci -vv
はデバイスの識別に役立つ場合があります。これはあまり文書化されていません...
私はこれに遭遇しました &Lのスレッド 、同様の問題:このコマンドでリセットできると言うその質問に対するいくつかの回答があります:
echo "1" > /sys/bus/pci/devices/$NUMBER/reset
しかし、私はそこで答えを読むでしょう!この方法でそれを行うには条件があります!具体的には この回答を読む !
PCIバス内のデバイスをリセットする方法を提供するUnixコマンドsetpci
があります。
私はこのコマンドで特定の例を確認しなかったので、例についてグーグルして man page を確認する必要があります。使い方に自信があるまで、このコマンドで軽く踏みます。私がそれについて読んだことから、それはハードウェアを直接操作しているので、このタイプの機能を公開しているツールを使用する場合と比較して、それを自分で行うことには常にリスクがあります!
remove
およびrescan
を使用すると、カーネルはreboot
なしでPCIデバイスに電源を供給できます。
echo "1" > /sys/bus/pci/devices/DDDD\:BB\:DD.F//remove
sleep 1
echo "1" > /sys/bus/pci/rescan
ここで、DDDD.BB.DD.F = Domain:Bus:Device.Function
PCI Expressのリセットは少し複雑です。リセットには、従来のリセットと機能レベルのリセットの2つの主なタイプがあります。従来のリセットには、基本リセットと非基本リセットの2つのタイプもあります。詳細については、PCI Express仕様を参照してください。
「コールドリセット」は、PCIeデバイスに電源が投入された後に行われる基本的なリセットです。コールドリセットをトリガーする標準的な方法はないようです。システムをオフにしてから再びオンにすることを除いては。私のマシンでは、/sys/bus/pci/slots
ディレクトリが空です。
「ウォームリセット」は、デバイスの電源を切断せずにトリガーされる基本的なリセットです。ウォームリセットをトリガーする標準的な方法はないようです。
「ホットリセット」は、PCI Expressリンクを介してトリガーされる従来のリセットです。ホットリセットは、リンクが強制的に電気的にアイドル状態になったとき、またはホットリセットビットが設定されたTS1およびTS2の順序付きセットを送信することによってトリガーされます。ソフトウェアは、デバイスの上流にあるブリッジポートのPCI構成スペースにあるブリッジ制御レジスタのセカンダリバスリセットビットを設定してクリアすることにより、ホットリセットを開始できます。
「機能レベルのリセット」(FLR)は、PCI Expressデバイスの単一の機能にのみ影響するリセットです。 PCIeデバイス全体をリセットしてはなりません。 PCIe仕様では、機能レベルのリセットを実装する必要はありません。機能レベルのリセットは、PCI構成スペースのPCI Express機能構造内の機能のデバイス制御レジスターにある機能レベルのリセットの開始ビットを設定することによって開始されます。
Linuxは、関数レベルのリセット機能を/sys/bus/pci/devices/$dev/reset
の形式で公開しています。このファイルに1を書き込むと、対応する関数で関数レベルのリセットが開始されます。これは、デバイス全体ではなくデバイスの特定の機能にのみ影響し、デバイスはPCIe仕様に従って機能レベルのリセットを実装する必要がないことに注意してください。
ホットリセットをトリガーするための「ナイス」な方法を知りません(sysfsエントリがありません)。ただし、そのためにsetpciを使用することは可能です。
#!/bin/bash
dev=$1
if [ -z "$dev" ]; then
echo "Error: no device specified"
exit 1
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
dev="0000:$dev"
fi
if [ ! -e "/sys/bus/pci/devices/$dev" ]; then
echo "Error: device $dev not found"
exit 1
fi
port=$(basename $(dirname $(readlink "/sys/bus/pci/devices/$dev")))
if [ ! -e "/sys/bus/pci/devices/$port" ]; then
echo "Error: device $port not found"
exit 1
fi
echo "Removing $dev..."
echo 1 > "/sys/bus/pci/devices/$dev/remove"
echo "Performing hot reset of port $port..."
bc=$(setpci -s $port BRIDGE_CONTROL)
echo "Bridge control:" $bc
setpci -s $port BRIDGE_CONTROL=$(printf "%04x" $(("0x$bc" | 0x40)))
sleep 0.01
setpci -s $port BRIDGE_CONTROL=$bc
sleep 0.5
echo "Rescanning bus..."
echo 1 > "/sys/bus/pci/devices/$port/rescan"
このスクリプトを実行する前に、接続されているすべてのドライバーがアンロードされていることを確認してください。このスクリプトは、PCIeデバイスの取り外しを試み、次にアップストリームスイッチポートにホットリセットを発行するように命令し、PCIeバスの再スキャンを試みます。また、このスクリプトは単一の機能を備えたデバイスでのみテストされているため、複数の機能を備えたデバイスでは、再加工が必要になる場合があります。
Alex.forencichによって投稿された回答を基に構築
CentOS 7でこれを機能させるには、いくつかの変更を加える必要がありました。これは、ルートとして実行していないためです。このバージョンには、実行中のコマンドが表示されます。
#!/bin/bash
# e.g. $ ./pcie_hot_reset.sh 04:00.0
DEV=$1
if [ -z "$DEV" ]; then
echo "Error: no device specified"
exit 1
fi
if [ ! -e "/sys/bus/pci/devices/$DEV" ]; then
DEV="0000:$DEV"
fi
if [ ! -e "/sys/bus/pci/devices/$DEV" ]; then
echo "Error: device $DEV not found"
exit 1
fi
PORT=$(basename $(dirname $(readlink "/sys/bus/pci/devices/$DEV")))
if [ ! -e "/sys/bus/pci/devices/$PORT" ]; then
echo "Error: device $PORT not found"
exit 1
fi
echo -e "\nRemoving $DEV"
CMD="echo 1 | Sudo tee /sys/bus/pci/devices/$DEV/remove"
printf "> $CMD\n"
eval $CMD
echo -e "\nPerforming hot reset of port $PORT"
CMD="setpci -s $PORT BRIDGE_CONTROL"
printf "> $CMD\n"
BR_CTRL=$(eval $CMD)
echo "Bridge control: $BR_CTRL"
CMD="Sudo setpci -s $PORT BRIDGE_CONTROL=$(printf "%04x" $((0x${BR_CTRL} | 0x40)))"
printf "> $CMD\n"
eval $CMD
sleep 0.01
CMD="Sudo setpci -s $PORT BRIDGE_CONTROL=$BR_CTRL"
printf "> $CMD\n"
eval $CMD
sleep 0.5
echo -e "\nRescanning bus"
CMD="echo 1 | Sudo tee /sys/bus/pci/devices/$PORT/rescan"
printf "> $CMD\n"
eval $CMD
出力例:
$ ./pcie_hot_reset.sh 04:00.0
Removing 0000:04:00.0
> echo 1 | Sudo tee /sys/bus/pci/devices/0000:04:00.0/remove
1
Performing hot reset of port 0000:00:03.0
> setpci -s 0000:00:03.0 BRIDGE_CONTROL
Bridge control: 0010
> Sudo setpci -s 0000:00:03.0 BRIDGE_CONTROL=0050
> Sudo setpci -s 0000:00:03.0 BRIDGE_CONTROL=0010
Rescanning bus
> echo 1 | Sudo tee /sys/bus/pci/devices/0000:00:03.0/rescan
1