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;