From owner-svn-src-all@FreeBSD.ORG Thu Dec 10 01:01:54 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 23C051065676; Thu, 10 Dec 2009 01:01:54 +0000 (UTC) (envelope-from jkim@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 11DE18FC12; Thu, 10 Dec 2009 01:01:54 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id nBA11rtK046080; Thu, 10 Dec 2009 01:01:53 GMT (envelope-from jkim@svn.freebsd.org) Received: (from jkim@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id nBA11rYe046077; Thu, 10 Dec 2009 01:01:53 GMT (envelope-from jkim@svn.freebsd.org) Message-Id: <200912100101.nBA11rYe046077@svn.freebsd.org> From: Jung-uk Kim Date: Thu, 10 Dec 2009 01:01:53 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r200341 - head/sys/dev/pci X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 10 Dec 2009 01:01:54 -0000 Author: jkim Date: Thu Dec 10 01:01:53 2009 New Revision: 200341 URL: http://svn.freebsd.org/changeset/base/200341 Log: Implement a rudimentary suspend/resume methods for PCI P2P bridge. Reviewed by: jhb, imp Modified: head/sys/dev/pci/pci.c head/sys/dev/pci/pci_pci.c Modified: head/sys/dev/pci/pci.c ============================================================================== --- head/sys/dev/pci/pci.c Thu Dec 10 00:16:11 2009 (r200340) +++ head/sys/dev/pci/pci.c Thu Dec 10 01:01:53 2009 (r200341) @@ -253,7 +253,7 @@ disable. 1 means conservatively place d agressively place devices into D3 state. 3 means put absolutely everything\n\ in D3 state."); -static int pci_do_power_resume = 1; +int pci_do_power_resume = 1; TUNABLE_INT("hw.pci.do_power_resume", &pci_do_power_resume); SYSCTL_INT(_hw_pci, OID_AUTO, do_power_resume, CTLFLAG_RW, &pci_do_power_resume, 1, Modified: head/sys/dev/pci/pci_pci.c ============================================================================== --- head/sys/dev/pci/pci_pci.c Thu Dec 10 00:16:11 2009 (r200340) +++ head/sys/dev/pci/pci_pci.c Thu Dec 10 01:01:53 2009 (r200341) @@ -52,7 +52,18 @@ __FBSDID("$FreeBSD$"); #include "pcib_if.h" +#ifdef __HAVE_ACPI +#include +#include "acpi_if.h" +#else +#define ACPI_PWR_FOR_SLEEP(x, y, z) +#endif + +extern int pci_do_power_resume; + static int pcib_probe(device_t dev); +static int pcib_suspend(device_t dev); +static int pcib_resume(device_t dev); static device_method_t pcib_methods[] = { /* Device interface */ @@ -60,8 +71,8 @@ static device_method_t pcib_methods[] = DEVMETHOD(device_attach, pcib_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_suspend, pcib_suspend), + DEVMETHOD(device_resume, pcib_resume), /* Bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), @@ -121,6 +132,154 @@ pcib_is_io_open(struct pcib_softc *sc) } /* + * Get current I/O decode. + */ +static void +pcib_get_io_decode(struct pcib_softc *sc) +{ + device_t dev; + uint32_t iolow; + + dev = sc->dev; + + iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1); + if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) + sc->iobase = PCI_PPBIOBASE( + pci_read_config(dev, PCIR_IOBASEH_1, 2), iolow); + else + sc->iobase = PCI_PPBIOBASE(0, iolow); + + iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1); + if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) + sc->iolimit = PCI_PPBIOLIMIT( + pci_read_config(dev, PCIR_IOLIMITH_1, 2), iolow); + else + sc->iolimit = PCI_PPBIOLIMIT(0, iolow); +} + +/* + * Get current memory decode. + */ +static void +pcib_get_mem_decode(struct pcib_softc *sc) +{ + device_t dev; + pci_addr_t pmemlow; + + dev = sc->dev; + + sc->membase = PCI_PPBMEMBASE(0, + pci_read_config(dev, PCIR_MEMBASE_1, 2)); + sc->memlimit = PCI_PPBMEMLIMIT(0, + pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); + + pmemlow = pci_read_config(dev, PCIR_PMBASEL_1, 2); + if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64) + sc->pmembase = PCI_PPBMEMBASE( + pci_read_config(dev, PCIR_PMBASEH_1, 4), pmemlow); + else + sc->pmembase = PCI_PPBMEMBASE(0, pmemlow); + + pmemlow = pci_read_config(dev, PCIR_PMLIMITL_1, 2); + if ((pmemlow & PCIM_BRPM_MASK) == PCIM_BRPM_64) + sc->pmemlimit = PCI_PPBMEMLIMIT( + pci_read_config(dev, PCIR_PMLIMITH_1, 4), pmemlow); + else + sc->pmemlimit = PCI_PPBMEMLIMIT(0, pmemlow); +} + +/* + * Restore previous I/O decode. + */ +static void +pcib_set_io_decode(struct pcib_softc *sc) +{ + device_t dev; + uint32_t iohi; + + dev = sc->dev; + + iohi = sc->iobase >> 16; + if (iohi > 0) + pci_write_config(dev, PCIR_IOBASEH_1, iohi, 2); + pci_write_config(dev, PCIR_IOBASEL_1, sc->iobase >> 8, 1); + + iohi = sc->iolimit >> 16; + if (iohi > 0) + pci_write_config(dev, PCIR_IOLIMITH_1, iohi, 2); + pci_write_config(dev, PCIR_IOLIMITL_1, sc->iolimit >> 8, 1); +} + +/* + * Restore previous memory decode. + */ +static void +pcib_set_mem_decode(struct pcib_softc *sc) +{ + device_t dev; + pci_addr_t pmemhi; + + dev = sc->dev; + + pci_write_config(dev, PCIR_MEMBASE_1, sc->membase >> 16, 2); + pci_write_config(dev, PCIR_MEMLIMIT_1, sc->memlimit >> 16, 2); + + pmemhi = sc->pmembase >> 32; + if (pmemhi > 0) + pci_write_config(dev, PCIR_PMBASEH_1, pmemhi, 4); + pci_write_config(dev, PCIR_PMBASEL_1, sc->pmembase >> 16, 2); + + pmemhi = sc->pmemlimit >> 32; + if (pmemhi > 0) + pci_write_config(dev, PCIR_PMLIMITH_1, pmemhi, 4); + pci_write_config(dev, PCIR_PMLIMITL_1, sc->pmemlimit >> 16, 2); +} + +/* + * Get current bridge configuration. + */ +static void +pcib_cfg_save(struct pcib_softc *sc) +{ + device_t dev; + + dev = sc->dev; + + sc->command = pci_read_config(dev, PCIR_COMMAND, 2); + sc->pribus = pci_read_config(dev, PCIR_PRIBUS_1, 1); + sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); + sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); + sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); + sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); + if (sc->command & PCIM_CMD_PORTEN) + pcib_get_io_decode(sc); + if (sc->command & PCIM_CMD_MEMEN) + pcib_get_mem_decode(sc); +} + +/* + * Restore previous bridge configuration. + */ +static void +pcib_cfg_restore(struct pcib_softc *sc) +{ + device_t dev; + + dev = sc->dev; + + pci_write_config(dev, PCIR_COMMAND, sc->command, 2); + pci_write_config(dev, PCIR_PRIBUS_1, sc->pribus, 1); + pci_write_config(dev, PCIR_SECBUS_1, sc->secbus, 1); + pci_write_config(dev, PCIR_SUBBUS_1, sc->subbus, 1); + pci_write_config(dev, PCIR_BRIDGECTL_1, sc->bridgectl, 2); + pci_write_config(dev, PCIR_SECLAT_1, sc->seclat, 1); + if (sc->command & PCIM_CMD_PORTEN) + pcib_set_io_decode(sc); + if (sc->command & PCIM_CMD_MEMEN) + pcib_set_mem_decode(sc); +} + +/* * Generic device interface */ static int @@ -138,7 +297,6 @@ void pcib_attach_common(device_t dev) { struct pcib_softc *sc; - uint8_t iolow; struct sysctl_ctx_list *sctx; struct sysctl_oid *soid; @@ -148,14 +306,9 @@ pcib_attach_common(device_t dev) /* * Get current bridge configuration. */ - sc->command = pci_read_config(dev, PCIR_COMMAND, 1); - sc->domain = pci_get_domain(dev); - sc->pribus = pci_read_config(dev, PCIR_PRIBUS_1, 1); - sc->secbus = pci_read_config(dev, PCIR_SECBUS_1, 1); - sc->subbus = pci_read_config(dev, PCIR_SUBBUS_1, 1); - sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2); - sc->bridgectl = pci_read_config(dev, PCIR_BRIDGECTL_1, 2); - sc->seclat = pci_read_config(dev, PCIR_SECLAT_1, 1); + sc->domain = pci_get_domain(dev); + sc->secstat = pci_read_config(dev, PCIR_SECSTAT_1, 2); + pcib_cfg_save(sc); /* * Setup sysctl reporting nodes @@ -172,51 +325,6 @@ pcib_attach_common(device_t dev) CTLFLAG_RD, &sc->subbus, 0, "Subordinate bus number"); /* - * Determine current I/O decode. - */ - if (sc->command & PCIM_CMD_PORTEN) { - iolow = pci_read_config(dev, PCIR_IOBASEL_1, 1); - if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { - sc->iobase = PCI_PPBIOBASE(pci_read_config(dev, PCIR_IOBASEH_1, 2), - pci_read_config(dev, PCIR_IOBASEL_1, 1)); - } else { - sc->iobase = PCI_PPBIOBASE(0, pci_read_config(dev, PCIR_IOBASEL_1, 1)); - } - - iolow = pci_read_config(dev, PCIR_IOLIMITL_1, 1); - if ((iolow & PCIM_BRIO_MASK) == PCIM_BRIO_32) { - sc->iolimit = PCI_PPBIOLIMIT(pci_read_config(dev, PCIR_IOLIMITH_1, 2), - pci_read_config(dev, PCIR_IOLIMITL_1, 1)); - } else { - sc->iolimit = PCI_PPBIOLIMIT(0, pci_read_config(dev, PCIR_IOLIMITL_1, 1)); - } - } - - /* - * Determine current memory decode. - */ - if (sc->command & PCIM_CMD_MEMEN) { - sc->membase = PCI_PPBMEMBASE(0, pci_read_config(dev, PCIR_MEMBASE_1, 2)); - sc->memlimit = PCI_PPBMEMLIMIT(0, pci_read_config(dev, PCIR_MEMLIMIT_1, 2)); - iolow = pci_read_config(dev, PCIR_PMBASEL_1, 1); - if ((iolow & PCIM_BRPM_MASK) == PCIM_BRPM_64) - sc->pmembase = PCI_PPBMEMBASE( - pci_read_config(dev, PCIR_PMBASEH_1, 4), - pci_read_config(dev, PCIR_PMBASEL_1, 2)); - else - sc->pmembase = PCI_PPBMEMBASE(0, - pci_read_config(dev, PCIR_PMBASEL_1, 2)); - iolow = pci_read_config(dev, PCIR_PMLIMITL_1, 1); - if ((iolow & PCIM_BRPM_MASK) == PCIM_BRPM_64) - sc->pmemlimit = PCI_PPBMEMLIMIT( - pci_read_config(dev, PCIR_PMLIMITH_1, 4), - pci_read_config(dev, PCIR_PMLIMITL_1, 2)); - else - sc->pmemlimit = PCI_PPBMEMLIMIT(0, - pci_read_config(dev, PCIR_PMLIMITL_1, 2)); - } - - /* * Quirk handling. */ switch (pci_get_devid(dev)) { @@ -337,6 +445,41 @@ pcib_attach(device_t dev) } int +pcib_suspend(device_t dev) +{ + device_t acpi_dev; + int dstate, error; + + pcib_cfg_save(device_get_softc(dev)); + error = bus_generic_suspend(dev); + if (error == 0 && pci_do_power_resume) { + acpi_dev = devclass_get_device(devclass_find("acpi"), 0); + if (acpi_dev != NULL) { + dstate = PCI_POWERSTATE_D3; + ACPI_PWR_FOR_SLEEP(acpi_dev, dev, &dstate); + pci_set_powerstate(dev, dstate); + } + } + return (error); +} + +int +pcib_resume(device_t dev) +{ + device_t acpi_dev; + + if (pci_do_power_resume) { + acpi_dev = devclass_get_device(devclass_find("acpi"), 0); + if (acpi_dev != NULL) { + ACPI_PWR_FOR_SLEEP(acpi_dev, dev, NULL); + pci_set_powerstate(dev, PCI_POWERSTATE_D0); + } + } + pcib_cfg_restore(device_get_softc(dev)); + return (bus_generic_resume(dev)); +} + +int pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct pcib_softc *sc = device_get_softc(dev);