Skip to content

Commit 4fc9bbf

Browse files
hikerockiesbjorn-helgaas
authored andcommitted
PCI: Disable Bus Master only on kexec reboot
Add a flag to tell the PCI subsystem that kernel is shutting down in preparation to kexec a kernel. Add code in PCI subsystem to use this flag to clear Bus Master bit on PCI devices only in case of kexec reboot. This fixes a power-off problem on Acer Aspire V5-573G and likely other machines and avoids any other issues caused by clearing Bus Master bit on PCI devices in normal shutdown path. The problem was introduced by b566a22 ("PCI: disable Bus Master on PCI device shutdown"). This patch is based on discussion at http://marc.info/?l=linux-pci&m=138425645204355&w=2 Link: https://bugzilla.kernel.org/show_bug.cgi?id=63861 Reported-by: Chang Liu <cl91tp@gmail.com> Signed-off-by: Khalid Aziz <khalid.aziz@oracle.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Konstantin Khlebnikov <koct9i@gmail.com> Cc: stable@vger.kernel.org # v3.5+
1 parent f407dae commit 4fc9bbf

File tree

3 files changed

+16
-3
lines changed

3 files changed

+16
-3
lines changed

drivers/pci/pci-driver.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/cpu.h>
2020
#include <linux/pm_runtime.h>
2121
#include <linux/suspend.h>
22+
#include <linux/kexec.h>
2223
#include "pci.h"
2324

2425
struct pci_dynid {
@@ -415,12 +416,17 @@ static void pci_device_shutdown(struct device *dev)
415416
pci_msi_shutdown(pci_dev);
416417
pci_msix_shutdown(pci_dev);
417418

419+
#ifdef CONFIG_KEXEC
418420
/*
419-
* Turn off Bus Master bit on the device to tell it to not
420-
* continue to do DMA. Don't touch devices in D3cold or unknown states.
421+
* If this is a kexec reboot, turn off Bus Master bit on the
422+
* device to tell it to not continue to do DMA. Don't touch
423+
* devices in D3cold or unknown states.
424+
* If it is not a kexec reboot, firmware will hit the PCI
425+
* devices with big hammer and stop their DMA any way.
421426
*/
422-
if (pci_dev->current_state <= PCI_D3hot)
427+
if (kexec_in_progress && (pci_dev->current_state <= PCI_D3hot))
423428
pci_clear_master(pci_dev);
429+
#endif
424430
}
425431

426432
#ifdef CONFIG_PM

include/linux/kexec.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ extern u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4];
198198
extern size_t vmcoreinfo_size;
199199
extern size_t vmcoreinfo_max_size;
200200

201+
/* flag to track if kexec reboot is in progress */
202+
extern bool kexec_in_progress;
203+
201204
int __init parse_crashkernel(char *cmdline, unsigned long long system_ram,
202205
unsigned long long *crash_size, unsigned long long *crash_base);
203206
int parse_crashkernel_high(char *cmdline, unsigned long long system_ram,

kernel/kexec.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4];
4747
size_t vmcoreinfo_size;
4848
size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data);
4949

50+
/* Flag to indicate we are going to kexec a new kernel */
51+
bool kexec_in_progress = false;
52+
5053
/* Location of the reserved area for the crash kernel */
5154
struct resource crashk_res = {
5255
.name = "Crash kernel",
@@ -1675,6 +1678,7 @@ int kernel_kexec(void)
16751678
} else
16761679
#endif
16771680
{
1681+
kexec_in_progress = true;
16781682
kernel_restart_prepare(NULL);
16791683
printk(KERN_EMERG "Starting new kernel\n");
16801684
machine_shutdown();

0 commit comments

Comments
 (0)