Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/pci Clearing PCI_PMCSR_PME_STS(W1C) bit is required ...



details:   https://anonhg.NetBSD.org/src/rev/5d71e6415ef9
branches:  trunk
changeset: 446704:5d71e6415ef9
user:      msaitoh <msaitoh%NetBSD.org@localhost>
date:      Sat Dec 15 05:38:45 2018 +0000

description:
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.

diffstat:

 sys/dev/pci/pci.c |  35 ++++++++++++++++++++++++++++-------
 1 files changed, 28 insertions(+), 7 deletions(-)

diffs (68 lines):

diff -r 574456fa835d -r 5d71e6415ef9 sys/dev/pci/pci.c
--- a/sys/dev/pci/pci.c Sat Dec 15 02:03:24 2018 +0000
+++ b/sys/dev/pci/pci.c Sat Dec 15 05:38:45 2018 +0000
@@ -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 @@
        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 @@
                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;



Home | Main Index | Thread Index | Old Index