Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F140053657
D48385.id160552.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D48385.id160552.diff
View Options
diff --git a/sys/dev/acpica/acpi_powerres.c b/sys/dev/acpica/acpi_powerres.c
--- a/sys/dev/acpica/acpi_powerres.c
+++ b/sys/dev/acpica/acpi_powerres.c
@@ -76,6 +76,13 @@
/* Device which is powered */
ACPI_HANDLE ac_consumer;
int ac_state;
+
+ struct {
+ bool prx_has;
+ size_t prx_count;
+ ACPI_HANDLE *prx_deps;
+ } ac_prx[ACPI_D_STATE_COUNT];
+
TAILQ_ENTRY(acpi_powerconsumer) ac_link;
TAILQ_HEAD(,acpi_powerreference) ac_references;
};
@@ -96,9 +103,7 @@
ACPI_SERIAL_DECL(powerres, "ACPI power resources");
static ACPI_STATUS acpi_pwr_register_consumer(ACPI_HANDLE consumer);
-#ifdef notyet
static ACPI_STATUS acpi_pwr_deregister_consumer(ACPI_HANDLE consumer);
-#endif /* notyet */
static ACPI_STATUS acpi_pwr_register_resource(ACPI_HANDLE res);
#ifdef notyet
static ACPI_STATUS acpi_pwr_deregister_resource(ACPI_HANDLE res);
@@ -221,6 +226,84 @@
}
#endif /* notyet */
+/*
+ * Evaluate the _PRx (power resources each D-state depends on). This also
+ * populates the acpi_powerresources queue with the power resources discovered
+ * during this step.
+ *
+ * ACPI 7.3.8 - 7.3.11 guarantee that _PRx will return the same data each
+ * time they are evaluated.
+ *
+ * If this function fails, acpi_pwr_deregister_consumer() must be called on the
+ * power consumer to free already allocated memory.
+ */
+static ACPI_STATUS
+acpi_pwr_get_power_resources(ACPI_HANDLE consumer, struct acpi_powerconsumer *pc)
+{
+ ACPI_INTEGER status;
+ ACPI_STRING reslist_name;
+ ACPI_HANDLE reslist_handle;
+ ACPI_STRING reslist_names[] = {"_PR0", "_PR1", "_PR2", "_PR3"};
+ ACPI_BUFFER reslist;
+ ACPI_OBJECT *reslist_object;
+ ACPI_OBJECT *dep;
+ ACPI_HANDLE *res;
+
+ ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
+ ACPI_SERIAL_ASSERT(powerres);
+
+ MPASS(consumer != NULL);
+
+ for (int state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) {
+ pc->ac_prx[state].prx_has = false;
+ pc->ac_prx[state].prx_count = 0;
+ pc->ac_prx[state].prx_deps = NULL;
+
+ reslist_name = reslist_names[state - ACPI_STATE_D0];
+ if (ACPI_FAILURE(AcpiGetHandle(consumer, reslist_name, &reslist_handle)))
+ continue;
+
+ reslist.Pointer = NULL;
+ reslist.Length = ACPI_ALLOCATE_BUFFER;
+ status = AcpiEvaluateObjectTyped(reslist_handle, NULL, NULL, &reslist,
+ ACPI_TYPE_PACKAGE);
+ if (ACPI_FAILURE(status) || reslist.Pointer == NULL)
+ /*
+ * ACPI_ALLOCATE_BUFFER entails everything will be freed on error
+ * by AcpiEvaluateObjectTyped.
+ */
+ continue;
+
+ reslist_object = (ACPI_OBJECT *)reslist.Pointer;
+ pc->ac_prx[state].prx_has = true;
+ pc->ac_prx[state].prx_count = reslist_object->Package.Count;
+
+ if (reslist_object->Package.Count == 0) {
+ AcpiOsFree(reslist_object);
+ continue;
+ }
+
+ pc->ac_prx[state].prx_deps = mallocarray(pc->ac_prx[state].prx_count,
+ sizeof(*pc->ac_prx[state].prx_deps), M_ACPIPWR, M_NOWAIT);
+ if (pc->ac_prx[state].prx_deps == NULL) {
+ AcpiOsFree(reslist_object);
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ for (size_t i = 0; i < reslist_object->Package.Count; i++) {
+ dep = &reslist_object->Package.Elements[i];
+ res = dep->Reference.Handle;
+ pc->ac_prx[state].prx_deps[i] = res;
+
+ /* It's fine to attempt to register the same resource twice. */
+ acpi_pwr_register_resource(res);
+ }
+ AcpiOsFree(reslist_object);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
/*
* Register a power consumer.
*
@@ -229,6 +312,7 @@
static ACPI_STATUS
acpi_pwr_register_consumer(ACPI_HANDLE consumer)
{
+ ACPI_INTEGER status;
struct acpi_powerconsumer *pc;
ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
@@ -239,12 +323,27 @@
return_ACPI_STATUS (AE_OK);
/* Allocate a new power consumer */
- if ((pc = malloc(sizeof(*pc), M_ACPIPWR, M_NOWAIT)) == NULL)
+ if ((pc = malloc(sizeof(*pc), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL)
return_ACPI_STATUS (AE_NO_MEMORY);
TAILQ_INSERT_HEAD(&acpi_powerconsumers, pc, ac_link);
TAILQ_INIT(&pc->ac_references);
pc->ac_consumer = consumer;
+ /*
+ * Get all its power resource dependencies, if it has _PRx. We do this now
+ * as an opportunity to populate the acpi_powerresources queue.
+ *
+ * If this fails, immediately deregister it.
+ */
+ status = acpi_pwr_get_power_resources(consumer, pc);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
+ "failed to get power resources for %s\n",
+ acpi_name(consumer)));
+ acpi_pwr_deregister_consumer(consumer);
+ return_ACPI_STATUS (status);
+ }
+
/* XXX we should try to find its current state */
pc->ac_state = ACPI_STATE_UNKNOWN;
@@ -254,7 +353,6 @@
return_ACPI_STATUS (AE_OK);
}
-#ifdef notyet
/*
* Deregister a power consumer.
*
@@ -279,6 +377,9 @@
/* Pull the consumer off the list and free it */
TAILQ_REMOVE(&acpi_powerconsumers, pc, ac_link);
+ for (size_t i = 0; i < sizeof(pc->ac_prx) / sizeof(*pc->ac_prx); i++)
+ if (pc->ac_prx[i].prx_deps != NULL)
+ free(pc->ac_prx[i].prx_deps, M_ACPIPWR);
free(pc, M_ACPIPWR);
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "deregistered power consumer %s\n",
@@ -286,7 +387,6 @@
return_ACPI_STATUS (AE_OK);
}
-#endif /* notyet */
/*
* Set a power consumer to a particular power state.
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Dec 20, 2:49 PM (8 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27097990
Default Alt Text
D48385.id160552.diff (5 KB)
Attached To
Mode
D48385: acpi_powerres: Fix turning off power resources on first D-state switch
Attached
Detach File
Event Timeline
Log In to Comment