PCIeデバイスをリセット/電源オフする方法は?

PCIeデバイスをリセット/電源オフする方法は?

コンピュータが完全にオフになってから再びオンになったときにのみ機能するPCIeデバイスがあります。シンプルrebootまたはreboot -pコマンドを実行しても、PCIeカードの電源が切れて再起動後に動作しないようです。

オペレーティングシステムでPCIeスロットにあるデバイスの電源を入れ直す方法はありますか?で見つけることができますが、/sys/bus/pci/devices/0000*/ボードを正しくリセットする方法がわかりません。電源を入れ替えるのが唯一の方法のようです。

それ以外に、rebootコマンドが完全に再開されるように設定を変更できますか?

ところで、私はUbuntu 12.10を実行しています。

答え1

デバイスを取り外し、PCIe バスを再スキャンします。

そのディレクトリの機能を介してPCIeデバイスを削除removeし、PCIeバスの機能を介して再ロードすると、コンピュータをrescan再起動せずにカーネルがPCIeデバイスを再起動します。

echo "1" > /sys/bus/pci/devices/DDDD\:BB\:DD.F/remove
sleep 1
echo "1" > /sys/bus/pci/rescan

上記のコードはDDDD:BB:DD.Fデバイススロットフォーマットです。ドメイン:バス:device.function

答え2

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を使用してこのファイルに1を書き込むと、/sys/bus/pci/devices/$dev/resetその機能の機能レベルのリセットが始まります。これは、デバイス全体ではなくデバイスの特定の機能にのみ影響し、デバイスは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 バスの再スキャンを試みます。さらに、このスクリプトは単一の機能を持つデバイスでのみテストされているため、複数の機能を持つデバイスにはいくつかの修正が必要になる場合があります。

答え3

潜在的なアプローチ #1

次のコマンドを使用すると可能だと思います。

障害を負う

echo 0 > /sys/bus/pci/slots/$NUMBER/power

〜できるようにする

echo 1 > /sys/bus/pci/slots/$NUMBER/power

$NUMBERPCIスロット番号はどこにありますか?

lspci -vvデバイスを識別するのに役立ちます。これはよく文書化されていません...

潜在的なアプローチ #2

私はこれに会ったU&Lのスレッド、同様の質問:この質問に対するいくつかの答えは、次のコマンドを使用してリセットできることを示します。

echo "1" > /sys/bus/pci/devices/$NUMBER/reset

しかし、そこから答えを読むでしょう!そのためには条件があります!具体的にはこの答えを読んでください

潜在的なアプローチ #3

setpciPCIバスのデバイスをリセットする方法を提供するUnixコマンドがあります。

このコマンドの具体的な例は表示されていないため、Googleで例を見つけて参照する必要があります。マニュアルページ。私はあなたがこのコマンドを使用することに自信があるまでこのコマンドを注意して使用します。私が読んだことによれば、ハードウェアで直接動作するので、これらの機能を提供するツールを使用するのと比較して直接実行することは常に危険です!

答え4

alex.forencichが投稿した回答に基づいて

CentOS 7で動作するにはいくつかの変更が必要でした。部分的にはrootとして実行されていないからです。このバージョンは、実行中のコマンドを示しています。

#!/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

関連情報