[patch] USB after second suspend/resume on ThinkPads.
John Baldwin
jhb at freebsd.org
Wed Jun 18 21:14:01 UTC 2014
On Wednesday, June 18, 2014 2:46:09 pm Edward Tomasz Napierała wrote:
> On 0618T1303, John Baldwin wrote:
> > On Wednesday, June 18, 2014 12:13:15 pm Edward Tomasz Napierała wrote:
> > > On 0618T0947, John Baldwin wrote:
> > > > On Monday, June 16, 2014 3:21:55 pm Edward Tomasz Napierała wrote:
> > > > > Hi. Patch below should fix a problem where USB stops working after
> > > > > _second_ suspend/resume, which happens on various ThinkPad models.
> > > > > Please test, and report both success stories and failures. If nothing
> > > > > comes up, I'll commit it in a week or so.
> > > >
> > > > Good find. Have you thought about a more generic fix for this wherein you
> > > > track power resources and flip them on during resume in ACPI before doing
> > > > DEVICE_RESUME() on the root bus?
> > >
> > > Thing is, after resume this device claims to be on already. The following
> > > simple hack was enough to make it work:
> >
> > Ahh, I think I see. Try this instead:
> >
> > Index: sys/dev/acpica/acpi_powerres.c
> > ===================================================================
> > --- acpi_powerres.c (revision 267550)
> > +++ acpi_powerres.c (working copy)
> > @@ -645,7 +645,7 @@ acpi_pwr_switch_power(void)
> > acpi_name(rp->ap_resource), status));
> > /* XXX is this correct? Always switch if in doubt? */
> > continue;
> > - } else if (rp->ap_state == ACPI_PWR_UNK)
> > + } else
> > rp->ap_state = cur;
> >
> > /*
> > @@ -689,7 +689,7 @@ acpi_pwr_switch_power(void)
> > acpi_name(rp->ap_resource), status));
> > /* XXX is this correct? Always switch if in doubt? */
> > continue;
> > - } else if (rp->ap_state == ACPI_PWR_UNK)
> > + } else
> > rp->ap_state = cur;
> >
> > /*
> >
> > (We were ignoring what _STA told us and believed it was ON because we had
> > cached that state previously.)
>
> Works!
Hmmm. If we go this route, ap_state is actually useless and should just be
removed. Here is an updated version that does that. If this works as well
then this is probably a commit candidate.
Index: acpi_powerres.c
===================================================================
--- acpi_powerres.c (revision 267550)
+++ acpi_powerres.c (working copy)
@@ -64,7 +64,6 @@ ACPI_MODULE_NAME("POWERRES")
/* Return values from _STA on a power resource */
#define ACPI_PWR_OFF 0
#define ACPI_PWR_ON 1
-#define ACPI_PWR_UNK (-1)
/* A relationship between a power resource and a consumer. */
struct acpi_powerreference {
@@ -90,7 +89,6 @@ struct acpi_powerresource {
ACPI_HANDLE ap_resource;
UINT64 ap_systemlevel;
UINT64 ap_order;
- int ap_state;
};
static TAILQ_HEAD(acpi_powerresource_list, acpi_powerresource)
@@ -173,7 +171,6 @@ acpi_pwr_register_resource(ACPI_HANDLE res)
}
rp->ap_systemlevel = obj->PowerResource.SystemLevel;
rp->ap_order = obj->PowerResource.ResourceOrder;
- rp->ap_state = ACPI_PWR_UNK;
/* Sort the resource into the list */
status = AE_OK;
@@ -638,7 +635,6 @@ acpi_pwr_switch_power(void)
continue;
}
- /* We could cache this if we trusted it not to change under us */
status = acpi_GetInteger(rp->ap_resource, "_STA", &cur);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get status of %s - %d\n",
@@ -645,8 +641,7 @@ acpi_pwr_switch_power(void)
acpi_name(rp->ap_resource), status));
/* XXX is this correct? Always switch if in doubt? */
continue;
- } else if (rp->ap_state == ACPI_PWR_UNK)
- rp->ap_state = cur;
+ }
/*
* Switch if required. Note that we ignore the result of the switch
@@ -653,7 +648,7 @@ acpi_pwr_switch_power(void)
* effort; we don't know what to do if it fails, so checking wouldn't
* help much.
*/
- if (rp->ap_state != ACPI_PWR_ON) {
+ if (cur != ACPI_PWR_ON) {
status = AcpiEvaluateObject(rp->ap_resource, "_ON", NULL, NULL);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
@@ -661,7 +656,6 @@ acpi_pwr_switch_power(void)
acpi_name(rp->ap_resource),
AcpiFormatException(status)));
} else {
- rp->ap_state = ACPI_PWR_ON;
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s on\n",
acpi_name(rp->ap_resource)));
}
@@ -682,7 +676,6 @@ acpi_pwr_switch_power(void)
continue;
}
- /* We could cache this if we trusted it not to change under us */
status = acpi_GetInteger(rp->ap_resource, "_STA", &cur);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get status of %s - %d\n",
@@ -689,8 +682,7 @@ acpi_pwr_switch_power(void)
acpi_name(rp->ap_resource), status));
/* XXX is this correct? Always switch if in doubt? */
continue;
- } else if (rp->ap_state == ACPI_PWR_UNK)
- rp->ap_state = cur;
+ }
/*
* Switch if required. Note that we ignore the result of the switch
@@ -697,7 +689,7 @@ acpi_pwr_switch_power(void)
* effort; we don't know what to do if it fails, so checking wouldn't
* help much.
*/
- if (rp->ap_state != ACPI_PWR_OFF) {
+ if (cur != ACPI_PWR_OFF) {
status = AcpiEvaluateObject(rp->ap_resource, "_OFF", NULL, NULL);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
@@ -705,7 +697,6 @@ acpi_pwr_switch_power(void)
acpi_name(rp->ap_resource),
AcpiFormatException(status)));
} else {
- rp->ap_state = ACPI_PWR_OFF;
ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s off\n",
acpi_name(rp->ap_resource)));
}
--
John Baldwin
More information about the freebsd-current
mailing list