]> git.ipfire.org Git - thirdparty/kernel/stable.git/commit
PCI/portdrv: Prevent LS7A Bus Master clearing on shutdown
authorHuacai Chen <chenhuacai@loongson.cn>
Wed, 1 Feb 2023 04:30:17 +0000 (12:30 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 11 Mar 2023 12:50:41 +0000 (13:50 +0100)
commit104c82d862fa83d701cd0d32e313242d329fd69d
tree2a1f4708bd5821e9324f1986566a7864b1ea30e3
parentab7fb29268b390a79d7efc1d775057a9cca9e034
PCI/portdrv: Prevent LS7A Bus Master clearing on shutdown

[ Upstream commit 62b6dee1b44aa23b3935543aff7df80399ec726b ]

After cc27b735ad3a ("PCI/portdrv: Turn off PCIe services during shutdown")
we observe hangs during poweroff/reboot on systems with LS7A chipset.

This happens because the portdrv .shutdown() method (pcie_portdrv_remove())
clears PCI_COMMAND_MASTER via pci_disable_device(), which prevents bridges
from forwarding memory or I/O Requests in the upstream direction (PCIe
r6.0, sec 7.5.1.1.3).

LS7A Root Ports have a hardware defect: clearing PCI_COMMAND_MASTER *also*
prevents the bridge from forwarding CPU MMIO requests in the downstream
direction, and these MMIO accesses to devices below the bridge happen even
after .shutdown(), e.g., to print console messages.  LS7A neither forwards
the requests nor sends an unsuccessful completion to the CPU, so the CPU
waits forever, resulting in the hang.

The purpose of .shutdown() is to disable interrupts and DMA from the
device.  PCIe ports may generate interrupts (either MSI/MSI-X or INTx) for
AER, DPC, PME, hotplug, etc., but they never perform DMA except MSI/MSI-X.
Clearing PCI_COMMAND_MASTER effectively disables MSI/MSI-X, but not INTx.

The port service driver .remove() methods clear the interrupt enables in
PCI_ERR_ROOT_COMMAND, PCI_EXP_DPC_CTL, PCI_EXP_SLTCTL, and PCI_EXP_RTCTL,
etc., which disables interrupts regardless of whether they are MSI/MSI-X or
INTx.

Add a pcie_portdrv_shutdown() method that calls all the port service driver
.remove() methods to clear the interrupt enables for each service but does
not clear Bus Mastering on the port itself.

[bhelgaas: commit log]
Link: https://lore.kernel.org/r/20230201043018.778499-2-chenhuacai@loongson.cn
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/pci/pcie/portdrv.c