First cut on an implementation of an ACPI power management counter

backend for timecounters.
Due to known bugs in some chipsets, always read until we get 3 successive
samples which are monotonic, as FreeBSD does in its "safe" variant.
This can be refined later, either by chipset quirks or by a test (as
FreeBSD does).
This commit is contained in:
drochner 2006-06-21 17:47:23 +00:00
parent 9b00231778
commit c14d23ac86
4 changed files with 82 additions and 3 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: acpi.c,v 1.89 2006/06/20 12:31:19 cube Exp $ */ /* $NetBSD: acpi.c,v 1.90 2006/06/21 17:47:23 drochner Exp $ */
/*- /*-
* Copyright (c) 2003 The NetBSD Foundation, Inc. * Copyright (c) 2003 The NetBSD Foundation, Inc.
@ -77,7 +77,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.89 2006/06/20 12:31:19 cube Exp $"); __KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.90 2006/06/21 17:47:23 drochner Exp $");
#include "opt_acpi.h" #include "opt_acpi.h"
#include "opt_pcifixup.h" #include "opt_pcifixup.h"
@ -94,6 +94,7 @@ __KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.89 2006/06/20 12:31:19 cube Exp $");
#include <dev/acpi/acpireg.h> #include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h> #include <dev/acpi/acpivar.h>
#include <dev/acpi/acpi_osd.h> #include <dev/acpi/acpi_osd.h>
#include <dev/acpi/acpi_timer.h>
#ifdef ACPIVERBOSE #ifdef ACPIVERBOSE
#include <dev/acpi/acpidevs_data.h> #include <dev/acpi/acpidevs_data.h>
#endif #endif
@ -351,6 +352,7 @@ acpi_attach(struct device *parent, struct device *self, void *aux)
* Check for fixed-hardware features. * Check for fixed-hardware features.
*/ */
acpi_enable_fixed_events(sc); acpi_enable_fixed_events(sc);
acpitimer_init();
/* /*
* Fix up PCI devices. * Fix up PCI devices.

73
sys/dev/acpi/acpi_timer.c Normal file
View File

@ -0,0 +1,73 @@
/* $NetBSD: acpi_timer.c,v 1.1 2006/06/21 17:47:23 drochner Exp $ */
#include <sys/types.h>
#ifdef __HAVE_TIMECOUNTER
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/timetc.h>
#include <dev/acpi/acpica.h>
#include <dev/acpi/acpi_timer.h>
static u_int acpitimer_read(struct timecounter *);
static struct timecounter acpi_timecounter = {
acpitimer_read,
0,
0x00ffffff,
PM_TIMER_FREQUENCY,
"ACPI_PM_TMR",
900
};
int
acpitimer_init()
{
uint32_t bits;
ACPI_STATUS res;
res = AcpiGetTimerResolution(&bits);
if (res != AE_OK)
return (-1);
if (bits == 32)
acpi_timecounter.tc_counter_mask = 0xffffffff;
tc_init(&acpi_timecounter);
printf("acpitimer: %d bits\n", bits);
return (0);
}
/*
* Some chipsets (PIIX4 variants) do not latch correctly; there
* is a chance that a transition is hit.
* For now, just be conservative. We might detect the situation later
* (by testing, or chipset quirks).
*/
static u_int
acpitimer_read(struct timecounter *tc)
{
uint32_t t1, t2, t3;
AcpiGetTimer(&t2);
AcpiGetTimer(&t3);
do {
t1 = t2;
t2 = t3;
AcpiGetTimer(&t3);
} while ((t1 > t2) || (t2 > t3));
return (t2);
}
#else
int
acpitimer_init()
{
return (0);
}
#endif

View File

@ -0,0 +1,3 @@
/* $NetBSD: acpi_timer.h,v 1.1 2006/06/21 17:47:23 drochner Exp $ */
int acpitimer_init(void);

View File

@ -1,4 +1,4 @@
# $NetBSD: files.acpi,v 1.35 2006/01/31 09:30:06 kochi Exp $ # $NetBSD: files.acpi,v 1.36 2006/06/21 17:47:23 drochner Exp $
include "dev/acpi/acpica/files.acpica" include "dev/acpi/acpica/files.acpica"
@ -12,6 +12,7 @@ file dev/acpi/acpi_resource.c acpi
file dev/acpi/acpi_powerres.c acpi file dev/acpi/acpi_powerres.c acpi
file dev/acpi/acpi_madt.c acpi & mpacpi file dev/acpi/acpi_madt.c acpi & mpacpi
file dev/acpi/acpi_quirks.c acpi file dev/acpi/acpi_quirks.c acpi
file dev/acpi/acpi_timer.c acpi
# ACPI Embedded Controller # ACPI Embedded Controller
device acpiec device acpiec