Re: [PATCH v3] ACPI / Sleep: Check low power idle constraints for debug only
From: Srinivas Pandruvada
Date: Sat Aug 12 2017 - 11:59:33 EST
On Sat, 2017-08-12 at 16:27 +0200, Rafael J. Wysocki wrote:
[...]
> > +
> > +struct lpi_constraints {
> > + char *name;
> > + int min_dstate;
> If you store the handle here as well, you won't need to
> look it up every time _check_constraints() is called.
The reason I didn't keep handle here, I thought handle can be stale or
change for PnP device on plug in and out. Is this not true?
> >
> > +};
> > +
> > +static struct lpi_constraints *lpi_constraints_table;
> > +static int lpi_constraints_table_size;
> > +
> > +static void lpi_device_get_constraints(void)
> > +{
> > + union acpi_object *out_obj;
> > + int i;
> > +
> > + out_obj = acpi_evaluate_dsm_typed(lps0_device_handle,
> > &lps0_dsm_guid,
> > + ÂÂ1,
> > ACPI_LPS0_GET_DEVICE_CONSTRAINTS,
> > + ÂÂNULL,
> > ACPI_TYPE_PACKAGE);
> > +
> > + acpi_handle_debug(lps0_device_handle, "_DSM function 1
> > eval %s\n",
> > + ÂÂout_obj ? "successful" : "failed");
> > +
> > + if (!out_obj)
> > + return;
> > +
> > + lpi_constraints_table = kcalloc(out_obj->package.count,
> > + sizeof(*lpi_constraints_ta
> > ble),
> > + GFP_KERNEL);
> > + if (!lpi_constraints_table)
> > + goto free_acpi_buffer;
> > +
> > + pr_debug("LPI: constraints dump begin\n");
> Please add an empty line after this.ÂÂAlso something like
> "constraints
> list begin" would sound better IMO.
>
OK.
> >
> > + for (i = 0; i < out_obj->package.count; i++) {
> > + union acpi_object *package = &out_obj-
> > >package.elements[i];
> > + struct lpi_device_info info = { };
> > + int package_count = 0, j;
> > +
> > + if (!package)
> > + continue;
> > +
> > + for (j = 0; j < package->package.count; ++j) {
> > + union acpi_object *element =
> > + &(package-
> > >package.elements[j]);
> > +
> > + switch (element->type) {
> > + case ACPI_TYPE_INTEGER:
> > + info.enabled = element-
> > >integer.value;
> > + break;
> > + case ACPI_TYPE_STRING:
> > + info.name = element-
> > >string.pointer;
> > + break;
> > + case ACPI_TYPE_PACKAGE:
> > + package_count = element-
> > >package.count;
> > + info.package = element-
> > >package.elements;
> > + break;
> > + }
> > + }
> > +
> > + if (!info.enabled || !info.package || !info.name)
> > + continue;
> > +
> I would evaluate acpi_get_handle() here and store the handle in the
> constraints table (if persent).ÂÂAnd you can skip the entry
> altogether
> if not present, because you won't be printing it anyway.
>
> >
> > + lpi_constraints_table[lpi_constraints_table_size].
> > name =
> > + kstrdup(info.name,
> > GFP_KERNEL);
> > + if
> > (!lpi_constraints_table[lpi_constraints_table_size].name)
> > + goto free_constraints;
> > +
> > + pr_debug("index:%d Name:%s\n", i, info.name);
> > +
> > + for (j = 0; j < package_count; ++j) {
> > + union acpi_object *info_obj =
> > &info.package[j];
> > + union acpi_object *cnstr_pkg;
> > + union acpi_object *obj;
> > + struct lpi_device_constraint dev_info;
> > +
> > + switch (info_obj->type) {
> > + case ACPI_TYPE_INTEGER:
> > + /* version */
> > + break;
> > + case ACPI_TYPE_PACKAGE:
> > + if (info_obj->package.count < 2)
> > + break;
> > +
> > + cnstr_pkg = info_obj-
> > >package.elements;
> > + obj = &cnstr_pkg[0];
> > + dev_info.uid = obj->integer.value;
> > + obj = &cnstr_pkg[1];
> > + dev_info.min_dstate = obj-
> > >integer.value;
> > + pr_debug("uid %d min_dstate %d\n",
> > + Âdev_info.uid,
> > + Âdev_info.min_dstate);
> > + lpi_constraints_table[
> > + lpi_constraints_table_size
> > ].min_dstate =
> > + dev_info.min_dstat
> > e;
> > + break;
> > + }
> > + }
> > +
> > + lpi_constraints_table_size++;
> > + }
> > +
> > + pr_debug("LPI: constraints dump end\n");
> > +free_acpi_buffer:
> > + ACPI_FREE(out_obj);
> > + return;
> > +
> > +free_constraints:
> > + ACPI_FREE(out_obj);
> > + for (i = 0; i < lpi_constraints_table_size; ++i)
> > + kfree(lpi_constraints_table[i].name);
> > + kfree(lpi_constraints_table);
> > + lpi_constraints_table_size = 0;
> > +}
> > +
> > +static void lpi_check_constraints(void)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < lpi_constraints_table_size; ++i) {
> > + acpi_handle handle;
> > + struct acpi_device *adev;
> > + int state, ret;
> > +
> > + if (ACPI_FAILURE(acpi_get_handle(NULL,
> > + Âlpi_constraints_t
> > able[i].name,
> > + Â&handle)))
> > + continue;
> So if you store the handle, the above won't be necessary.
>
> >
> > +
> > + if (acpi_bus_get_device(handle, &adev))
> > + continue;
> > +
> > + ret = acpi_device_get_power(adev, &state);
> > + if (ret)
> > + pr_debug("LPI: %s required min power state
> > %d, current power state %d, real power state [ERROR]\n",
> > + Âlpi_constraints_table[i].name,
> > + Âlpi_constraints_table[i].min_dsta
> > te,
> > + Âadev->power.state);
> > + else
> > + pr_debug("LPI: %s required min power state
> > %d, current power state %d, real power state %d\n",
> > + Âlpi_constraints_table[i].name,
> > + Âlpi_constraints_table[i].min_dsta
> > te,
> > + Âadev->power.state, state);
> I'm not convinced about the value of the above TBH.
>
> Also in theory _PSC may go and access things like PCI config spaces
> of devices
> which isn't a good idea for devices in D3_cold, so maybe skip this?
OK.
>
> >
> > +
> > + if (adev->flags.power_manageable && adev-
> > >power.state <
> > + lpi_constraints_table[i].m
> > in_dstate)
> > + pr_info("LPI: Constraint [%s] not
> > matched\n",
> "Constrant [%s] not met"?
>
> Also I'd use acpi_handle_info(adev->handle, ...) to print this.
>
> >
> > + Âlpi_constraints_table[i].name);
> I would print a message if !flags.power_manageable, because it means
> we
> can't get the constraint right in general.
>
> Also I would print both power.state and min_state (possibly using
> acpi_power_state_string()) in this message as that is valuable for
> debugging.
OK.
Thanks,
Srinivas