web-dev-qa-db-ja.com

PCIeデバイスの電源をリセット/サイクルする方法は?

コンピューターの電源を完全にオフにしてから再びオンにしたときにのみ正しく機能するPCIeデバイスがあります。単純なrebootまたはreboot -pコマンドを発行しても、PCIeカードの電源が入れ直されず、再起動後に機能しなくなります。

OSからPCIeスロット内のデバイスの電源を入れ直す方法はありますか? /sys/bus/pci/devices/0000*/で確認できますが、ボードを正しくリセットする方法がわかりません。力を切り替えることが唯一の方法のようです。

それがなければ、rebootコマンドで完全な電源再投入を引き起こす設定をどこかに変更できますか?

ちなみに私はUbuntu 12.10を実行しています。

22
zachd1_618

潜在的な方法#1

私はあなたがこれらのコマンドでそれを行うことができると思います:

無効にする

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

enable

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

どこ $NUMBERはPCIスロットの番号です。

lspci -vvはデバイスの識別に役立つ場合があります。これはあまり文書化されていません...

潜在的な方法#2

私はこれに遭遇しました &Lのスレッド 、同様の問題:このコマンドでリセットできると言うその質問に対するいくつかの回答があります:

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

しかし、私はそこで答えを読むでしょう!この方法でそれを行うには条件があります!具体的には この回答を読む

潜在的な方法#3

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

私はこのコマンドで特定の例を確認しなかったので、例についてグーグルして man page を確認する必要があります。使い方に自信があるまで、このコマンドで軽く踏みます。私がそれについて読んだことから、それはハードウェアを直接操作しているので、このタイプの機能を公開しているツールを使用する場合と比較して、それを自分で行うことには常にリスクがあります!

17
slm

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

10
cyber

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バスの再スキャンを試みます。また、このスクリプトは単一の機能を備えたデバイスでのみテストされているため、複数の機能を備えたデバイスでは、再加工が必要になる場合があります。

9
alex.forencich

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
0
mhck