Module Name:    src
Committed By:   msaitoh
Date:           Sat Dec 15 05:38:45 UTC 2018

Modified Files:
        src/sys/dev/pci: pci.c

Log Message:
 Clearing PCI_PMCSR_PME_STS(W1C) bit is required to stop asserting PME#.
This change would prevent unexpected rebooting from shutdown -p or
unexpected resuming from suspend.


To generate a diff of this commit:
cvs rdiff -u -r1.153 -r1.154 src/sys/dev/pci/pci.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/pci.c
diff -u src/sys/dev/pci/pci.c:1.153 src/sys/dev/pci/pci.c:1.154
--- src/sys/dev/pci/pci.c:1.153	Sat Dec  1 01:23:24 2018
+++ src/sys/dev/pci/pci.c	Sat Dec 15 05:38:45 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: pci.c,v 1.153 2018/12/01 01:23:24 msaitoh Exp $	*/
+/*	$NetBSD: pci.c,v 1.154 2018/12/15 05:38:45 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 1995, 1996, 1997, 1998
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.153 2018/12/01 01:23:24 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.154 2018/12/15 05:38:45 msaitoh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_pci.h"
@@ -1221,16 +1221,36 @@ pci_child_suspend(device_t dv, const pmf
 	return true;
 }
 
+static void
+pci_pme_check_and_clear(device_t dv, pci_chipset_tag_t pc, pcitag_t tag,
+    int off)
+{
+	pcireg_t pmcsr;
+
+	pmcsr = pci_conf_read(pc, tag, off + PCI_PMCSR);
+
+	if (pmcsr & PCI_PMCSR_PME_STS) {
+		/* Clear W1C bit */
+		pmcsr |= PCI_PMCSR_PME_STS;
+		pci_conf_write(pc, tag, off + PCI_PMCSR, pmcsr);
+		aprint_verbose_dev(dv, "Clear PME# now\n");
+	}
+}
+
 static bool
 pci_child_resume(device_t dv, const pmf_qual_t *qual)
 {
 	struct pci_child_power *priv = device_pmf_bus_private(dv);
 
-	if (priv->p_has_pm &&
-	    pci_set_powerstate_int(priv->p_pc, priv->p_tag,
-	    PCI_PMCSR_STATE_D0, priv->p_pm_offset, priv->p_pm_cap)) {
-		aprint_error_dev(dv, "unsupported state, continuing.\n");
-		return false;
+	if (priv->p_has_pm) {
+		if (pci_set_powerstate_int(priv->p_pc, priv->p_tag,
+		    PCI_PMCSR_STATE_D0, priv->p_pm_offset, priv->p_pm_cap)) {
+			aprint_error_dev(dv,
+			    "unsupported state, continuing.\n");
+			return false;
+		}
+		pci_pme_check_and_clear(dv, priv->p_pc, priv->p_tag,
+		    priv->p_pm_offset);
 	}
 
 	pci_conf_restore(priv->p_pc, priv->p_tag, &priv->p_pciconf);
@@ -1286,6 +1306,7 @@ pci_child_register(device_t child)
 		priv->p_has_pm = true;
 		priv->p_pm_offset = off;
 		priv->p_pm_cap = reg;
+		pci_pme_check_and_clear(child, priv->p_pc, priv->p_tag, off);
 	} else {
 		priv->p_has_pm = false;
 		priv->p_pm_offset = -1;

Reply via email to