If we're trying to use C2/3 and reads from the register are returning

immediately, back off to the next higher Cx sleep state.  Some machines
with a Via chipset report a valid C3 but a register read doesn't actually
halt the CPU.  This would cause the machine to appear unresponsive as it
repeatedly called cpu_idle() which immediately returned.  Causing interrupts
(i.e. by pressing the power button) would cause the system to make forward
progress, showing that it wasn't actually hung.

Also, enable interrupts a little earlier.  We don't need them disabled
to calculate the delta time for the read.

Reported by:	silby
MFC after:	2 weeks
This commit is contained in:
njl 2005-10-25 21:15:47 +00:00
parent b61364c6ec
commit bcff7c3a7d

View File

@ -116,6 +116,7 @@ static int cpu_quirks; /* Indicate any hardware bugs. */
/* Runtime state. */
static int cpu_cx_count; /* Number of valid states */
static int cpu_non_c3; /* Index of lowest non-C3 state. */
static int cpu_short_slp; /* Count of < 1us sleeps. */
static u_int cpu_cx_stats[MAX_CX_STATES];/* Cx usage history. */
/* Values for sysctl. */
@ -599,7 +600,7 @@ acpi_cpu_cx_cst(struct acpi_cpu_softc *sc)
acpi_PkgInt32(pkg, 2, &cx_ptr->trans_lat) != 0 ||
acpi_PkgInt32(pkg, 3, &cx_ptr->power) != 0) {
device_printf(sc->cpu_dev, "Skipping invalid Cx state package\n");
device_printf(sc->cpu_dev, "skipping invalid Cx state package\n");
continue;
}
@ -779,12 +780,32 @@ acpi_cpu_idle()
* the length of our last sleep.
*/
cx_next_idx = cpu_cx_lowest;
if (sc->cpu_prev_sleep < 100)
if (sc->cpu_prev_sleep < 100) {
/*
* If we sleep too short all the time, this system may not implement
* C2/3 correctly (i.e. reads return immediately). In this case,
* back off and use the next higher level.
*/
if (sc->cpu_prev_sleep <= 1) {
cpu_short_slp++;
if (cpu_short_slp == 1000 && cpu_cx_lowest != 0) {
if (cpu_non_c3 == cpu_cx_lowest && cpu_non_c3 != 0)
cpu_non_c3--;
cpu_cx_lowest--;
cpu_short_slp = 0;
device_printf(sc->cpu_dev,
"too many short sleeps, backing off to C%d\n",
cpu_cx_lowest + 1);
}
} else
cpu_short_slp = 0;
for (i = cpu_cx_lowest; i >= 0; i--)
if (sc->cpu_cx_states[i].trans_lat <= sc->cpu_prev_sleep) {
cx_next_idx = i;
break;
}
}
/*
* Check for bus master activity. If there was activity, clear
@ -855,11 +876,11 @@ acpi_cpu_idle()
AcpiSetRegister(ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_DO_NOT_LOCK);
AcpiSetRegister(ACPI_BITREG_BUS_MASTER_RLD, 0, ACPI_MTX_DO_NOT_LOCK);
}
ACPI_ENABLE_IRQS();
/* Find the actual time asleep in microseconds, minus overhead. */
end_time = acpi_TimerDelta(end_time, start_time);
sc->cpu_prev_sleep = PM_USEC(end_time) - cx_next->trans_lat;
ACPI_ENABLE_IRQS();
}
/*