Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 24 Sep 2003 11:05:36 -0700 (PDT)
From:      John Baldwin <jhb@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 38520 for review
Message-ID:  <200309241805.h8OI5alR099408@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=38520

Change 38520 by jhb@jhb_laptop on 2003/09/24 11:05:16

	Update the ACPI PCI bus driver to set the ACPI device power state
	"outside" of the PCI power state.

Affected files ...

.. //depot/projects/power/sys/dev/acpica/acpi_pci.c#2 edit

Differences ...

==== //depot/projects/power/sys/dev/acpica/acpi_pci.c#2 (text+ko) ====

@@ -65,11 +65,8 @@
 static int	acpi_pci_attach(device_t dev);
 static int	acpi_pci_read_ivar(device_t dev, device_t child, int which,
     uintptr_t *result);
-#if 0
 static int	acpi_pci_set_powerstate_method(device_t dev, device_t child,
     int state);
-static int	acpi_pci_get_powerstate_method(device_t dev, device_t child);
-#endif
 static ACPI_STATUS acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level,
     void *context, void **status);
 
@@ -108,9 +105,8 @@
 	DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method),
 	DEVMETHOD(pci_enable_io,	pci_enable_io_method),
 	DEVMETHOD(pci_disable_io,	pci_disable_io_method),
-	/* XXX: We should override these two. */
 	DEVMETHOD(pci_get_powerstate,	pci_get_powerstate_method),
-	DEVMETHOD(pci_set_powerstate,	pci_set_powerstate_method),
+	DEVMETHOD(pci_set_powerstate,	acpi_pci_set_powerstate_method),
 	DEVMETHOD(pci_assign_interrupt, pci_assign_interrupt_method),
 
 	{ 0, 0 }
@@ -140,24 +136,58 @@
     return(pci_read_ivar(dev, child, which, result));
 }
 
-#if 0
 /*
  * PCI power manangement
  */
 static int
 acpi_pci_set_powerstate_method(device_t dev, device_t child, int state)
 {
-	/* XXX: TODO */
-	return (ENXIO);
-}
+	ACPI_STATUS status;
+	int acpi_state, old_state, error;
+
+	switch (state) {
+	case PCI_POWERSTATE_D0:
+		acpi_state = ACPI_STATE_D0;
+		break;
+	case PCI_POWERSTATE_D1:
+		acpi_state = ACPI_STATE_D1;
+		break;
+	case PCI_POWERSTATE_D2:
+		acpi_state = ACPI_STATE_D2;
+		break;
+	case PCI_POWERSTATE_D3:
+		acpi_state = ACPI_STATE_D3;
+		break;
+	default:
+		return (EINVAL);
+	}
 
-static int
-acpi_pci_get_powerstate_method(device_t dev, device_t child)
-{
-	/* XXX: TODO */
-	return (ENXIO);
+	/*
+	 * We set the state using PCI Power Management outside of setting
+	 * the ACPI state.  This means that when powering down a device, we
+	 * first shut it down using PCI, and then using ACPI, which lets ACPI
+	 * try to power down any Power Resources that are now no longer used.
+	 * When powering up a device, we let ACPI set the state first so that
+	 * it can enable any needed Power Resources before changing the PCI
+	 * power state.
+	 */
+	old_state = pci_get_powerstate(child);
+	if (old_state < state) {
+		error = pci_set_powerstate_method(dev, child, state);
+		if (error)
+			return (error);
+	}
+	status = acpi_SetPowerState(acpi_get_handle(child), acpi_state);
+	if (ACPI_FAILURE(status))
+		device_printf(dev,
+		    "Failed to set ACPI power state D%d on %s: %s\n",
+		    acpi_state, device_get_nameunit(child),
+		    AcpiFormatException(status));
+	if (state > old_state)
+		return (pci_set_powerstate_method(dev, child, state));
+	else
+		return (0);
 }
-#endif
 
 static ACPI_STATUS
 acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 level, void *context,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200309241805.h8OI5alR099408>