mirror of
https://github.com/opnsense/src.git
synced 2026-06-10 17:22:46 -04:00
acpi_powerres: D3cold support
Cherry-pick commit 0b76c0a from ACPICA (actypes: Distinguish between
D3hot/cold, and default `ACPI_STATE_D3` to D3cold).
The same distinction is made between `PCI_POWERSTATE_D3_HOT` and
`PCI_POWERSTATE_D3_COLD`, as they're defined by ACPI (and are asserted
to be the same).
D3cold is essentially the same as D3hot except the power resources are
turned off. Add support for D3cold to `acpi_pwr_switch_consumer`.
`acpi_d_state_to_str` replaces the `printf("D%d", d_state)` pattern,
allowing for "D3hot" and "D3cold" strings to be printed instead of just
"D3".
Reviewed by: markj, ziaee, mckusick (mentor)
Approved by: markj, mckusick (mentor)
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D48384
This commit is contained in:
parent
7988e7e167
commit
84bbfc32a3
9 changed files with 98 additions and 50 deletions
|
|
@ -664,10 +664,14 @@ Buses in this state can cause devices to lose some context.
|
|||
Devices
|
||||
.Em must
|
||||
be prepared for the bus to be in this state or higher.
|
||||
.It Dv PCI_POWERSTATE_D3
|
||||
.It Dv PCI_POWERSTATE_D3_HOT
|
||||
State in which the device is off and not running.
|
||||
Device context is lost, and power from the device can
|
||||
be removed.
|
||||
be (but is not necessarily) removed.
|
||||
.It Dv PCI_POWERSTATE_D3_COLD
|
||||
Same as
|
||||
.Dv PCI_POWERSTATE_D3_HOT ,
|
||||
except power has been removed from the device.
|
||||
.It Dv PCI_POWERSTATE_UNKNOWN
|
||||
State of the device is unknown.
|
||||
.El
|
||||
|
|
|
|||
|
|
@ -223,11 +223,11 @@ enum pcie_link_width {
|
|||
|
||||
typedef int pci_power_t;
|
||||
|
||||
#define PCI_D0 PCI_POWERSTATE_D0
|
||||
#define PCI_D1 PCI_POWERSTATE_D1
|
||||
#define PCI_D2 PCI_POWERSTATE_D2
|
||||
#define PCI_D3hot PCI_POWERSTATE_D3
|
||||
#define PCI_D3cold 4
|
||||
#define PCI_D0 PCI_POWERSTATE_D0
|
||||
#define PCI_D1 PCI_POWERSTATE_D1
|
||||
#define PCI_D2 PCI_POWERSTATE_D2
|
||||
#define PCI_D3hot PCI_POWERSTATE_D3_HOT
|
||||
#define PCI_D3cold PCI_POWERSTATE_D3_COLD
|
||||
|
||||
#define PCI_POWER_ERROR PCI_POWERSTATE_UNKNOWN
|
||||
|
||||
|
|
|
|||
|
|
@ -741,9 +741,11 @@ typedef UINT64 ACPI_INTEGER;
|
|||
#define ACPI_STATE_D0 (UINT8) 0
|
||||
#define ACPI_STATE_D1 (UINT8) 1
|
||||
#define ACPI_STATE_D2 (UINT8) 2
|
||||
#define ACPI_STATE_D3 (UINT8) 3
|
||||
#define ACPI_D_STATES_MAX ACPI_STATE_D3
|
||||
#define ACPI_D_STATE_COUNT 4
|
||||
#define ACPI_STATE_D3_HOT (UINT8) 3
|
||||
#define ACPI_STATE_D3_COLD (UINT8) 4
|
||||
#define ACPI_STATE_D3 ACPI_STATE_D3_COLD
|
||||
#define ACPI_D_STATES_MAX ACPI_STATE_D3_COLD
|
||||
#define ACPI_D_STATE_COUNT 5
|
||||
|
||||
#define ACPI_STATE_C0 (UINT8) 0
|
||||
#define ACPI_STATE_C1 (UINT8) 1
|
||||
|
|
|
|||
|
|
@ -2139,12 +2139,13 @@ acpi_set_powerstate(device_t child, int state)
|
|||
status = acpi_pwr_switch_consumer(h, state);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
if (bootverbose)
|
||||
device_printf(child, "set ACPI power state D%d on %s\n",
|
||||
state, acpi_name(h));
|
||||
device_printf(child, "set ACPI power state %s on %s\n",
|
||||
acpi_d_state_to_str(state), acpi_name(h));
|
||||
} else if (status != AE_NOT_FOUND)
|
||||
device_printf(child,
|
||||
"failed to set ACPI power state D%d on %s: %s\n", state,
|
||||
acpi_name(h), AcpiFormatException(status));
|
||||
"failed to set ACPI power state %s on %s: %s\n",
|
||||
acpi_d_state_to_str(state), acpi_name(h),
|
||||
AcpiFormatException(status));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,9 +53,6 @@
|
|||
|
||||
#include <dev/iommu/iommu.h>
|
||||
|
||||
#include "pcib_if.h"
|
||||
#include "pci_if.h"
|
||||
|
||||
/* Hooks for the ACPI CA debugging infrastructure. */
|
||||
#define _COMPONENT ACPI_BUS
|
||||
ACPI_MODULE_NAME("PCI")
|
||||
|
|
@ -266,12 +263,13 @@ acpi_pci_set_powerstate_method(device_t dev, device_t child, int state)
|
|||
status = acpi_pwr_switch_consumer(h, state);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
if (bootverbose)
|
||||
device_printf(dev, "set ACPI power state D%d on %s\n",
|
||||
state, acpi_name(h));
|
||||
device_printf(dev, "set ACPI power state %s on %s\n",
|
||||
acpi_d_state_to_str(state), acpi_name(h));
|
||||
} else if (status != AE_NOT_FOUND)
|
||||
device_printf(dev,
|
||||
"failed to set ACPI power state D%d on %s: %s\n",
|
||||
state, acpi_name(h), AcpiFormatException(status));
|
||||
"failed to set ACPI power state %s on %s: %s\n",
|
||||
acpi_d_state_to_str(state), acpi_name(h),
|
||||
AcpiFormatException(status));
|
||||
if (old_state > state && pci_do_power_resume)
|
||||
error = pci_set_powerstate_method(dev, child, state);
|
||||
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
|
|||
ACPI_BUFFER reslist_buffer;
|
||||
ACPI_OBJECT *reslist_object;
|
||||
ACPI_STATUS status;
|
||||
char *method_name, *reslist_name;
|
||||
char *method_name, *reslist_name = NULL;
|
||||
|
||||
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
|
||||
|
||||
|
|
@ -318,9 +318,26 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
|
|||
panic("acpi added power consumer but can't find it");
|
||||
}
|
||||
|
||||
/* Check for valid transitions. We can only go to D0 from D3. */
|
||||
/* Stop here if we're already at the target D-state. */
|
||||
if (pc->ac_state == state) {
|
||||
status = AE_OK;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for valid transitions. From D3hot or D3cold, we can only go to D0.
|
||||
* The exception to this is going from D3hot to D3cold or the other way
|
||||
* around. This is because they both use _PS3, so the only difference when
|
||||
* doing these transitions is whether or not the power resources for _PR3
|
||||
* are on for devices which support D3cold, and turning these power
|
||||
* resources on/off is always perfectly fine (ACPI 7.3.11).
|
||||
*/
|
||||
status = AE_BAD_PARAMETER;
|
||||
if (pc->ac_state == ACPI_STATE_D3 && state != ACPI_STATE_D0)
|
||||
if (pc->ac_state == ACPI_STATE_D3_HOT && state != ACPI_STATE_D0 &&
|
||||
state != ACPI_STATE_D3_COLD)
|
||||
goto out;
|
||||
if (pc->ac_state == ACPI_STATE_D3_COLD && state != ACPI_STATE_D0 &&
|
||||
state != ACPI_STATE_D3_HOT)
|
||||
goto out;
|
||||
|
||||
/* Find transition mechanism(s) */
|
||||
|
|
@ -337,15 +354,20 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
|
|||
method_name = "_PS2";
|
||||
reslist_name = "_PR2";
|
||||
break;
|
||||
case ACPI_STATE_D3:
|
||||
case ACPI_STATE_D3_HOT:
|
||||
method_name = "_PS3";
|
||||
reslist_name = "_PR3";
|
||||
break;
|
||||
case ACPI_STATE_D3_COLD:
|
||||
method_name = "_PS3";
|
||||
reslist_name = NULL;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "setup to switch %s D%d -> D%d\n",
|
||||
acpi_name(consumer), pc->ac_state, state));
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "setup to switch %s %s -> %s\n",
|
||||
acpi_name(consumer), acpi_d_state_to_str(pc->ac_state),
|
||||
acpi_d_state_to_str(state)));
|
||||
|
||||
/*
|
||||
* Verify that this state is supported, ie. one of method or
|
||||
|
|
@ -359,7 +381,8 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
|
|||
*/
|
||||
if (ACPI_FAILURE(AcpiGetHandle(consumer, method_name, &method_handle)))
|
||||
method_handle = NULL;
|
||||
if (ACPI_FAILURE(AcpiGetHandle(consumer, reslist_name, &reslist_handle)))
|
||||
if (reslist_name == NULL ||
|
||||
ACPI_FAILURE(AcpiGetHandle(consumer, reslist_name, &reslist_handle)))
|
||||
reslist_handle = NULL;
|
||||
if (reslist_handle == NULL && method_handle == NULL) {
|
||||
if (state == ACPI_STATE_D0) {
|
||||
|
|
@ -367,9 +390,12 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
|
|||
status = AE_OK;
|
||||
goto out;
|
||||
}
|
||||
if (state != ACPI_STATE_D3) {
|
||||
if (state == ACPI_STATE_D3_COLD)
|
||||
state = ACPI_STATE_D3_HOT;
|
||||
if (state != ACPI_STATE_D3_HOT) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
|
||||
"attempt to set unsupported state D%d\n", state));
|
||||
"attempt to set unsupported state %s\n",
|
||||
acpi_d_state_to_str(state)));
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -380,21 +406,23 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
|
|||
if (ACPI_FAILURE(AcpiGetHandle(consumer, "_PR0", &pr0_handle))) {
|
||||
status = AE_NOT_FOUND;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
|
||||
"device missing _PR0 (desired state was D%d)\n", state));
|
||||
"device missing _PR0 (desired state was %s)\n",
|
||||
acpi_d_state_to_str(state)));
|
||||
goto out;
|
||||
}
|
||||
reslist_buffer.Length = ACPI_ALLOCATE_BUFFER;
|
||||
status = AcpiEvaluateObject(pr0_handle, NULL, NULL, &reslist_buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
|
||||
"can't evaluate _PR0 for device %s, state D%d\n",
|
||||
acpi_name(consumer), state));
|
||||
"can't evaluate _PR0 for device %s, state %s\n",
|
||||
acpi_name(consumer), acpi_d_state_to_str(state)));
|
||||
goto out;
|
||||
}
|
||||
reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer;
|
||||
if (!ACPI_PKG_VALID(reslist_object, 1)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
|
||||
"invalid package object for state D%d\n", state));
|
||||
"invalid package object for state %s\n",
|
||||
acpi_d_state_to_str(state)));
|
||||
status = AE_TYPE;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -450,8 +478,8 @@ acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
|
|||
*/
|
||||
if (ACPI_FAILURE(status = acpi_pwr_switch_power())) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
|
||||
"failed to switch resources from %s to D%d\n",
|
||||
acpi_name(consumer), state));
|
||||
"failed to switch resources from %s to %s\n",
|
||||
acpi_name(consumer), acpi_d_state_to_str(state)));
|
||||
|
||||
/* XXX is this appropriate? Should we return to previous state? */
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -517,6 +517,15 @@ acpi_get_verbose(struct acpi_softc *sc)
|
|||
return (0);
|
||||
}
|
||||
|
||||
static __inline const char *
|
||||
acpi_d_state_to_str(int state)
|
||||
{
|
||||
const char *strs[ACPI_D_STATE_COUNT] = {"D0", "D1", "D2", "D3", "D3cold"};
|
||||
|
||||
MPASS(state >= ACPI_STATE_D0 && state <= ACPI_D_STATES_MAX);
|
||||
return (strs[state]);
|
||||
}
|
||||
|
||||
char *acpi_name(ACPI_HANDLE handle);
|
||||
int acpi_avoid(ACPI_HANDLE handle);
|
||||
int acpi_disabled(char *subsys);
|
||||
|
|
|
|||
|
|
@ -81,6 +81,9 @@
|
|||
|
||||
#include <dev/iommu/iommu.h>
|
||||
|
||||
#include <contrib/dev/acpica/include/acpi.h>
|
||||
#include <dev/acpica/acpivar.h>
|
||||
|
||||
#include "pcib_if.h"
|
||||
#include "pci_if.h"
|
||||
|
||||
|
|
@ -2896,8 +2899,8 @@ pci_set_powerstate_method(device_t dev, device_t child, int state)
|
|||
}
|
||||
|
||||
if (bootverbose)
|
||||
pci_printf(cfg, "Transition from D%d to D%d\n", oldstate,
|
||||
state);
|
||||
pci_printf(cfg, "Transition from %s to %s\n",
|
||||
acpi_d_state_to_str(oldstate), acpi_d_state_to_str(state));
|
||||
|
||||
PCI_WRITE_CONFIG(dev, child, cfg->pp.pp_location + PCIR_POWER_STATUS,
|
||||
status, 2);
|
||||
|
|
|
|||
|
|
@ -497,22 +497,25 @@ pci_is_vga_memory_range(rman_res_t start, rman_res_t end)
|
|||
/*
|
||||
* PCI power states are as defined by ACPI:
|
||||
*
|
||||
* D0 State in which device is on and running. It is receiving full
|
||||
* power from the system and delivering full functionality to the user.
|
||||
* D1 Class-specific low-power state in which device context may or may not
|
||||
* be lost. Buses in D1 cannot do anything to the bus that would force
|
||||
* devices on that bus to lose context.
|
||||
* D2 Class-specific low-power state in which device context may or may
|
||||
* not be lost. Attains greater power savings than D1. Buses in D2
|
||||
* can cause devices on that bus to lose some context. Devices in D2
|
||||
* must be prepared for the bus to be in D2 or higher.
|
||||
* D3 State in which the device is off and not running. Device context is
|
||||
* lost. Power can be removed from the device.
|
||||
* D0 State in which device is on and running. It is receiving full
|
||||
* power from the system and delivering full functionality to the user.
|
||||
* D1 Class-specific low-power state in which device context may or may not
|
||||
* be lost. Buses in D1 cannot do anything to the bus that would force
|
||||
* devices on that bus to lose context.
|
||||
* D2 Class-specific low-power state in which device context may or may
|
||||
* not be lost. Attains greater power savings than D1. Buses in D2
|
||||
* can cause devices on that bus to lose some context. Devices in D2
|
||||
* must be prepared for the bus to be in D2 or higher.
|
||||
* D3hot State in which the device is off and not running. Device context is
|
||||
* lost. Power can be removed from the device.
|
||||
* D3cold Same as D3hot, but power has been removed from the device.
|
||||
*/
|
||||
#define PCI_POWERSTATE_D0 0
|
||||
#define PCI_POWERSTATE_D1 1
|
||||
#define PCI_POWERSTATE_D2 2
|
||||
#define PCI_POWERSTATE_D3 3
|
||||
#define PCI_POWERSTATE_D3_HOT 3
|
||||
#define PCI_POWERSTATE_D3_COLD 4
|
||||
#define PCI_POWERSTATE_D3 PCI_POWERSTATE_D3_COLD
|
||||
#define PCI_POWERSTATE_UNKNOWN -1
|
||||
|
||||
static __inline int
|
||||
|
|
|
|||
Loading…
Reference in a new issue