So setzen Sie ein PCIe-Gerät zurück bzw. schalten es aus und wieder ein

20

Ich habe ein PCIe-Gerät, das nur dann ordnungsgemäß funktioniert, wenn der Computer vollständig aus- und wieder eingeschaltet ist. Wenn Sie einen einfachen Befehl rebootoder einen reboot -pBefehl eingeben , wird die PCIe-Karte nicht aus- und wieder eingeschaltet, sodass sie nach dem Neustart nicht funktioniert.

Gibt es eine Möglichkeit, vom Betriebssystem aus ein Gerät in einem PCIe-Steckplatz aus- und wieder einzuschalten? Ich kann es in finden /sys/bus/pci/devices/0000*/, aber ich kann nicht herausfinden, wie man das Brett richtig zurücksetzt. Machtwechsel scheint der einzige Weg zu sein.

Kann ich ansonsten irgendwo eine Einstellung ändern, bei der ein rebootBefehl vollständig aus- und wieder eingeschaltet wird ?

Ich verwende übrigens Ubuntu 12.10.

zachd1_618
quelle
Hast du es versucht reboot -f? Dies ist vergleichbar mit dem Drücken des Netzschalters der CPU.
ktan
1
Vor zwei Jahren hat das OP darauf hingewiesen, dass ein Soft rebootnicht funktioniert. Sie führen reboot -fimmer noch einen Soft-Neustart durch.
Roaima

Antworten:

16

Mögliche Methode # 1

Ich denke, Sie können es mit diesen Befehlen tun:

deaktivieren

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

aktivieren

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

Wo $NUMBERist die Nummer des PCI-Steckplatzes.

lspci -vvkann helfen, das Gerät zu identifizieren. Dies ist nicht sehr gut dokumentiert ...

Mögliche Methode # 2

Ich bin auf diesen Thread bei U & L gestoßen , ein ähnliches Problem: Es gibt einige Antworten auf diese Frage, die besagen, dass Sie mit diesem Befehl zurücksetzen können:

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

Allerdings würde ich die Antworten dort lesen! Es gibt Umstände, die das so machen! Speziell würde ich diese Antwort lesen !

Mögliche Methode # 3

Es gibt einen Unix-Befehl, setpcimit dem Sie möglicherweise ein Gerät im PCI-Bus zurücksetzen können.

Ich habe mit diesem Befehl keine konkreten Beispiele gesehen, daher müssen Sie bei Google nach Beispielen suchen und die Manpage durchsehen . Ich würde mit diesem Befehl leichtfertig umgehen, bis Sie sicher sind, dass er verwendet wird. Nach dem, was ich darüber gelesen habe, wird die Hardware direkt manipuliert, und es besteht immer das Risiko, dies selbst zu tun, anstatt ein Tool zu verwenden, das diese Art von Funktionalität verfügbar macht!

slm
quelle
1
In den Steckplätzen wird nichts angezeigt, obwohl mehrere Karten eingesteckt sind. Ich habe ein Stromverzeichnis /sys/bus/pci/devices/$NUMBER/. Aber nichts scheint die Einstellung 0 oder 1 zu rechtfertigen
zachd1_618
1
Ich bin auf diesen Thread auf U & L gestoßen, ein ähnliches Problem: Es gibt einige Antworten auf diesen Q, die besagen, dass Sie mit diesem zurücksetzen können: Echo "1"> / sys / bus / pci / devices / $ NUMBER / reset. Lesen Sie, dass Q, es gibt Bedingungen um es so zu tun!
SLM
Danke für den Link. Ich habe es jedoch versucht und es scheint nichts zu tun. Insbesondere schaltet sich das Gerät nicht aus und das System weiß immer noch, dass es vorhanden ist. (Wenn die Karte eingeschaltet und eingesteckt ist, gibt es Geräte in / dev, die ich beobachten kann). Sie verschwinden nicht, wenn ich echo "1" > ....
Zachd1_618
1
Entladen Sie die Kernelmodule für diese Karte vor dem Aus- und Einschalten? Ich denke, das muss man auch tun.
SLM
1
Ich denke, ich werde den Kernel-Quellcode überprüfen, um zu sehen, ob das Umschalten ihn powertatsächlich in D3 bringt.
Wald
7

removeund rescanermöglicht es dem Kernel, das PCI-Gerät durch einen Cycler mit Strom zu versorgen, ohne reboot:

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

Dabei ist DDDD.BB.DD.F = Domain: Bus: Device.Function

Cyber
quelle
echo "1"> / sys / bus / pci / rescan funktioniert bei mir im lenovo g560 mini pci slot. Ich habe eine USB 3.0-Minipci-Karte eingesteckt. Das System ist Ubuntu 16.04 x64
kodmanyagha
Es funktioniert nicht bei allen Geräten. Ich habe einen Cavium-Netzwerkadapter, der mit dieser Methode nicht ausgeschaltet werden kann, da ich über eine serielle Leitung immer noch auf den U-Boot zugreifen kann.
Eric
7

Zurücksetzen in PCI Express ist etwas komplex. Es gibt zwei Haupttypen von Zurücksetzungen - herkömmliche Zurücksetzungen und Zurücksetzungen auf Funktionsebene. Es gibt auch zwei Arten von konventionellen Rücksetzungen, Grundrücksetzungen und nicht-Grundrücksetzungen. Alle Details finden Sie in der PCI-Express-Spezifikation.

Ein "Kaltstart" ist ein grundlegender Neustart, der nach dem Einschalten eines PCIe-Geräts erfolgt. Es scheint keine Standardmethode zum Auslösen eines Kaltstartens zu geben, außer zum Aus- und Wiedereinschalten des Systems. Auf meinen Rechnern ist das /sys/bus/pci/slotsVerzeichnis leer.

Ein "Warm-Reset" ist ein grundlegender Reset, der ausgelöst wird, ohne dass die Stromversorgung des Geräts unterbrochen wird. Es scheint keine Standardmethode zu geben, um einen Warmstart auszulösen.

Ein "Hot-Reset" ist ein herkömmlicher Reset, der über eine PCI-Express-Verbindung ausgelöst wird. Ein Hot-Reset wird entweder ausgelöst, wenn eine Verbindung in den Leerlauf geschaltet wird, oder indem von TS1 und TS2 bestellte Sätze mit gesetztem Hot-Reset-Bit gesendet werden. Die Software kann einen Hot-Reset einleiten, indem sie das Reset-Bit für den sekundären Bus im Bridge-Steuerregister im PCI-Konfigurationsbereich des Bridge-Ports vor dem Gerät setzt und anschließend löscht.

Ein "Function Level Reset" (FLR) ist ein Reset, der nur eine einzelne Funktion eines PCI-Express-Geräts betrifft. Es darf nicht das gesamte PCIe-Gerät zurückgesetzt werden. Das Implementieren von Zurücksetzungen auf Funktionsebene ist in der PCIe-Spezifikation nicht erforderlich. Ein Zurücksetzen auf Funktionsebene wird eingeleitet, indem das Bit zum Zurücksetzen auf Funktionsebene im Gerätesteuerregister der Funktion in der PCI-Express-Fähigkeitsstruktur im PCI-Konfigurationsbereich gesetzt wird.

Linux stellt die Funktionalität zum Zurücksetzen auf Funktionsebene in Form von zur Verfügung /sys/bus/pci/devices/$dev/reset. Wenn Sie eine 1 in diese Datei schreiben, wird die entsprechende Funktion auf Funktionsebene zurückgesetzt. Beachten Sie, dass dies nur die spezifische Funktion des Geräts betrifft, nicht das gesamte Gerät, und dass Geräte nicht zur Implementierung von Zurücksetzungen auf Funktionsebene gemäß der PCIe-Spezifikation erforderlich sind.

Mir ist keine "nette" Methode bekannt, um einen Hot-Reset auszulösen (dafür gibt es keinen sysfs-Eintrag). Es ist jedoch möglich, setpci zu verwenden:

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

Stellen Sie sicher, dass alle angehängten Treiber entladen sind, bevor Sie dieses Skript ausführen. In diesem Skript wird versucht, das PCIe-Gerät zu entfernen. Anschließend wird der Upstream-Switch-Port angewiesen, einen Hot-Reset durchzuführen. Anschließend wird versucht, den PCIe-Bus erneut zu scannen. Dieses Skript wurde auch nur auf Geräten mit einer einzigen Funktion getestet. Daher muss es möglicherweise für Geräte mit mehreren Funktionen überarbeitet werden.

alex.forencich
quelle
Dieses Skript funktionierte für meinen AMD RX480. Kontext: PCI-Passthrough zu einem Win10-Gast, dann Herunterfahren oder Neustarten des Gasts. Das erneute Starten des Gasts (ohne Verwendung dieses Skripts) würde hängen bleiben, wenn die GPU noch angeschlossen wäre. Das Ausführen dieses Skripts in der Zwischenzeit hat das Problem behoben