1993-06-12 14:58:17 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 1990 The Regents of the University of California.
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
* Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
|
1993-06-12 14:58:17 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to Berkeley by
|
|
|
|
* William Jolitz and Don Ahn.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
1993-10-16 13:48:52 +00:00
|
|
|
* from: @(#)clock.c 7.2 (Berkeley) 5/12/91
|
1996-10-25 13:46:21 +00:00
|
|
|
*/
|
|
|
|
|
2003-06-02 16:32:55 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
1996-10-25 13:46:21 +00:00
|
|
|
/*
|
|
|
|
* Routines to handle clock hardware.
|
1994-09-20 00:31:07 +00:00
|
|
|
*/
|
|
|
|
|
1996-06-11 16:02:55 +00:00
|
|
|
#include "opt_clock.h"
|
2002-01-30 12:41:12 +00:00
|
|
|
#include "opt_isa.h"
|
2001-01-29 11:57:27 +00:00
|
|
|
#include "opt_mca.h"
|
1996-01-04 21:13:23 +00:00
|
|
|
|
1994-08-13 03:50:34 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
2000-06-23 07:44:33 +00:00
|
|
|
#include <sys/bus.h>
|
2001-03-28 09:17:56 +00:00
|
|
|
#include <sys/lock.h>
|
2004-07-10 22:16:18 +00:00
|
|
|
#include <sys/kdb.h>
|
2000-10-20 07:31:00 +00:00
|
|
|
#include <sys/mutex.h>
|
2000-09-07 01:33:02 +00:00
|
|
|
#include <sys/proc.h>
|
1994-08-13 03:50:34 +00:00
|
|
|
#include <sys/kernel.h>
|
2004-05-30 17:57:46 +00:00
|
|
|
#include <sys/module.h>
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
#include <sys/rman.h>
|
2005-12-13 19:08:55 +00:00
|
|
|
#include <sys/sched.h>
|
2009-05-02 12:59:47 +00:00
|
|
|
#include <sys/smp.h>
|
1996-05-01 08:39:02 +00:00
|
|
|
#include <sys/sysctl.h>
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
#include <sys/timeet.h>
|
|
|
|
#include <sys/timetc.h>
|
1996-05-01 08:39:02 +00:00
|
|
|
|
1994-11-05 23:55:07 +00:00
|
|
|
#include <machine/clock.h>
|
Tweak how the MD code calls the fooclock() methods some. Instead of
passing a pointer to an opaque clockframe structure and requiring the
MD code to supply CLKF_FOO() macros to extract needed values out of the
opaque structure, just pass the needed values directly. In practice this
means passing the pair (usermode, pc) to hardclock() and profclock() and
passing the boolean (usermode) to hardclock_cpu() and hardclock_process().
Other details:
- Axe clockframe and CLKF_FOO() macros on all architectures. Basically,
all the archs were taking a trapframe and converting it into a clockframe
one way or another. Now they can just extract the PC and usermode values
directly out of the trapframe and pass it to fooclock().
- Renamed hardclock_process() to hardclock_cpu() as the latter is more
accurate.
- On Alpha, we now run profclock() at hz (profhz == hz) rather than at
the slower stathz.
- On Alpha, for the TurboLaser machines that don't have an 8254
timecounter, call hardclock() directly. This removes an extra
conditional check from every clock interrupt on Alpha on the BSP.
There is probably room for even further pruning here by changing Alpha
to use the simplified timecounter we use on x86 with the lapic timer
since we don't get interrupts from the 8254 on Alpha anyway.
- On x86, clkintr() shouldn't ever be called now unless using_lapic_timer
is false, so add a KASSERT() to that affect and remove a condition
to slightly optimize the non-lapic case.
- Change prototypeof arm_handler_execute() so that it's first arg is a
trapframe pointer rather than a void pointer for clarity.
- Use KCOUNT macro in profclock() to lookup the kernel profiling bucket.
Tested on: alpha, amd64, arm, i386, ia64, sparc64
Reviewed by: bde (mostly)
2005-12-22 22:16:09 +00:00
|
|
|
#include <machine/cpu.h>
|
2003-11-03 21:53:38 +00:00
|
|
|
#include <machine/intr_machdep.h>
|
2005-05-14 09:10:02 +00:00
|
|
|
#include <machine/ppireg.h>
|
|
|
|
#include <machine/timerreg.h>
|
1996-05-01 08:39:02 +00:00
|
|
|
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifdef PC98
|
|
|
|
#include <pc98/pc98/pc98_machdep.h>
|
|
|
|
#else
|
1999-05-31 18:36:14 +00:00
|
|
|
#include <isa/rtc.h>
|
2010-07-13 06:57:27 +00:00
|
|
|
#endif
|
2002-01-30 12:41:12 +00:00
|
|
|
#ifdef DEV_ISA
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifdef PC98
|
|
|
|
#include <pc98/cbus/cbus.h>
|
|
|
|
#else
|
2005-05-14 09:10:02 +00:00
|
|
|
#include <isa/isareg.h>
|
2010-07-13 06:57:27 +00:00
|
|
|
#endif
|
2000-06-23 07:44:33 +00:00
|
|
|
#include <isa/isavar.h>
|
2002-01-30 12:41:12 +00:00
|
|
|
#endif
|
1994-09-18 23:08:56 +00:00
|
|
|
|
2001-01-29 11:57:27 +00:00
|
|
|
#ifdef DEV_MCA
|
2003-03-24 19:14:46 +00:00
|
|
|
#include <i386/bios/mca_machdep.h>
|
1999-09-03 02:04:28 +00:00
|
|
|
#endif
|
|
|
|
|
1999-05-28 14:08:59 +00:00
|
|
|
int clkintr_pending;
|
1998-02-20 16:36:17 +00:00
|
|
|
#ifndef TIMER_FREQ
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifdef PC98
|
|
|
|
#define TIMER_FREQ 2457600
|
|
|
|
#else
|
1998-02-20 16:36:17 +00:00
|
|
|
#define TIMER_FREQ 1193182
|
1996-07-21 08:20:51 +00:00
|
|
|
#endif
|
2010-07-13 06:57:27 +00:00
|
|
|
#endif
|
2008-03-26 15:03:24 +00:00
|
|
|
u_int i8254_freq = TIMER_FREQ;
|
|
|
|
TUNABLE_INT("hw.i8254.freq", &i8254_freq);
|
|
|
|
int i8254_max_count;
|
2010-09-17 04:48:50 +00:00
|
|
|
static int i8254_timecounter = 1;
|
1994-11-05 23:55:07 +00:00
|
|
|
|
2008-04-14 08:00:00 +00:00
|
|
|
struct mtx clock_lock;
|
2004-04-27 20:03:26 +00:00
|
|
|
static struct intsrc *i8254_intsrc;
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
static uint16_t i8254_lastcount;
|
|
|
|
static uint16_t i8254_offset;
|
2004-04-27 20:03:26 +00:00
|
|
|
static int (*i8254_pending)(struct intsrc *);
|
1998-02-20 16:36:17 +00:00
|
|
|
static int i8254_ticked;
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
|
|
|
|
struct attimer_softc {
|
|
|
|
int intr_en;
|
2010-07-12 06:46:17 +00:00
|
|
|
int port_rid, intr_rid;
|
|
|
|
struct resource *port_res;
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
struct resource *intr_res;
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifdef PC98
|
|
|
|
int port_rid2;
|
|
|
|
struct resource *port_res2;
|
|
|
|
#endif
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
void *intr_handler;
|
|
|
|
struct timecounter tc;
|
|
|
|
struct eventtimer et;
|
2010-09-17 04:48:50 +00:00
|
|
|
int mode;
|
|
|
|
#define MODE_STOP 0
|
|
|
|
#define MODE_PERIODIC 1
|
|
|
|
#define MODE_ONESHOT 2
|
|
|
|
uint32_t period;
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
};
|
|
|
|
static struct attimer_softc *attimer_sc = NULL;
|
1996-07-20 18:47:23 +00:00
|
|
|
|
2010-09-18 07:36:43 +00:00
|
|
|
static int timer0_period = -2;
|
|
|
|
|
1996-07-20 18:47:23 +00:00
|
|
|
/* Values for timerX_state: */
|
1996-07-21 08:20:51 +00:00
|
|
|
#define RELEASED 0
|
|
|
|
#define RELEASE_PENDING 1
|
|
|
|
#define ACQUIRED 2
|
|
|
|
#define ACQUIRE_PENDING 3
|
1996-07-20 18:47:23 +00:00
|
|
|
|
|
|
|
static u_char timer2_state;
|
1994-04-21 14:19:16 +00:00
|
|
|
|
2002-03-20 07:51:46 +00:00
|
|
|
static unsigned i8254_get_timecount(struct timecounter *tc);
|
2010-09-17 04:48:50 +00:00
|
|
|
static void set_i8254_freq(int mode, uint32_t period);
|
2009-05-02 12:59:47 +00:00
|
|
|
|
2007-02-23 12:19:07 +00:00
|
|
|
static int
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
clkintr(void *arg)
|
1994-05-25 09:21:21 +00:00
|
|
|
{
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
struct attimer_softc *sc = (struct attimer_softc *)arg;
|
2000-09-07 01:33:02 +00:00
|
|
|
|
2010-09-17 04:48:50 +00:00
|
|
|
if (i8254_timecounter && sc->period != 0) {
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
mtx_lock_spin(&clock_lock);
|
1999-05-28 14:08:59 +00:00
|
|
|
if (i8254_ticked)
|
1998-09-20 03:47:54 +00:00
|
|
|
i8254_ticked = 0;
|
1999-05-28 14:08:59 +00:00
|
|
|
else {
|
2008-03-26 15:03:24 +00:00
|
|
|
i8254_offset += i8254_max_count;
|
1998-09-20 03:47:54 +00:00
|
|
|
i8254_lastcount = 0;
|
|
|
|
}
|
1999-05-28 14:08:59 +00:00
|
|
|
clkintr_pending = 0;
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
mtx_unlock_spin(&clock_lock);
|
1998-09-20 03:47:54 +00:00
|
|
|
}
|
2008-05-24 06:27:54 +00:00
|
|
|
|
2010-09-17 04:48:50 +00:00
|
|
|
if (sc && sc->et.et_active && sc->mode != MODE_STOP)
|
2010-07-13 12:46:06 +00:00
|
|
|
sc->et.et_event_cb(&sc->et, sc->et.et_arg);
|
2009-06-09 07:26:52 +00:00
|
|
|
|
2001-01-29 11:57:27 +00:00
|
|
|
#ifdef DEV_MCA
|
1999-09-03 02:04:28 +00:00
|
|
|
/* Reset clock interrupt by asserting bit 7 of port 0x61 */
|
|
|
|
if (MCA_system)
|
|
|
|
outb(0x61, inb(0x61) | 0x80);
|
|
|
|
#endif
|
2007-02-23 12:19:07 +00:00
|
|
|
return (FILTER_HANDLED);
|
1994-04-21 14:19:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
timer_spkr_acquire(void)
|
1994-04-21 14:19:16 +00:00
|
|
|
{
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
int mode;
|
|
|
|
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifdef PC98
|
|
|
|
mode = TIMER_SEL1 | TIMER_SQWAVE | TIMER_16BIT;
|
|
|
|
#else
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
mode = TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT;
|
2010-07-13 06:57:27 +00:00
|
|
|
#endif
|
1996-07-20 18:47:23 +00:00
|
|
|
|
|
|
|
if (timer2_state != RELEASED)
|
|
|
|
return (-1);
|
|
|
|
timer2_state = ACQUIRED;
|
1996-07-21 08:20:51 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This access to the timer registers is as atomic as possible
|
|
|
|
* because it is a single instruction. We could do better if we
|
|
|
|
* knew the rate. Use of splclock() limits glitches to 10-100us,
|
|
|
|
* and this is probably good enough for timer2, so we aren't as
|
|
|
|
* careful with it as with timer0.
|
|
|
|
*/
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifdef PC98
|
|
|
|
outb(TIMER_MODE, TIMER_SEL1 | (mode & 0x3f));
|
|
|
|
#else
|
1996-07-21 08:20:51 +00:00
|
|
|
outb(TIMER_MODE, TIMER_SEL2 | (mode & 0x3f));
|
2010-07-13 06:57:27 +00:00
|
|
|
#endif
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
ppi_spkr_on(); /* enable counter2 output to speaker */
|
1996-07-20 18:47:23 +00:00
|
|
|
return (0);
|
1994-04-21 14:19:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
timer_spkr_release(void)
|
1994-04-21 14:19:16 +00:00
|
|
|
{
|
1996-07-20 18:47:23 +00:00
|
|
|
|
|
|
|
if (timer2_state != ACQUIRED)
|
|
|
|
return (-1);
|
|
|
|
timer2_state = RELEASED;
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifdef PC98
|
|
|
|
outb(TIMER_MODE, TIMER_SEL1 | TIMER_SQWAVE | TIMER_16BIT);
|
|
|
|
#else
|
1996-07-21 08:20:51 +00:00
|
|
|
outb(TIMER_MODE, TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT);
|
2010-07-13 06:57:27 +00:00
|
|
|
#endif
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
ppi_spkr_off(); /* disable counter2 output to speaker */
|
1996-07-20 18:47:23 +00:00
|
|
|
return (0);
|
1994-04-21 14:19:16 +00:00
|
|
|
}
|
|
|
|
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
void
|
|
|
|
timer_spkr_setfreq(int freq)
|
|
|
|
{
|
|
|
|
|
|
|
|
freq = i8254_freq / freq;
|
|
|
|
mtx_lock_spin(&clock_lock);
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifdef PC98
|
|
|
|
outb(TIMER_CNTR1, freq & 0xff);
|
|
|
|
outb(TIMER_CNTR1, freq >> 8);
|
|
|
|
#else
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
outb(TIMER_CNTR2, freq & 0xff);
|
|
|
|
outb(TIMER_CNTR2, freq >> 8);
|
2010-07-13 06:57:27 +00:00
|
|
|
#endif
|
The "free-lance" timer in the i8254 is only used for the speaker
these days, so de-generalize the acquire_timer/release_timer api
to just deal with speakers.
The new (optional) MD functions are:
timer_spkr_acquire()
timer_spkr_release()
and
timer_spkr_setfreq()
the last of which configures the timer to generate a tone of a given
frequency, in Hz instead of 1/1193182th of seconds.
Drop entirely timer2 on pc98, it is not used anywhere at all.
Move sysbeep() to kern/tty_cons.c and use the timer_spkr*() if
they exist, and do nothing otherwise.
Remove prototypes and empty acquire-/release-timer() and sysbeep()
functions from the non-beeping archs.
This eliminate the need for the speaker driver to know about
i8254frequency at all. In theory this makes the speaker driver MI,
contingent on the timer_spkr_*() functions existing but the driver
does not know this yet and still attaches to the ISA bus.
Syscons is more tricky, in one function, sc_tone(), it knows the hz
and things are just fine.
In the other function, sc_bell() it seems to get the period from
the KDMKTONE ioctl in terms if 1/1193182th second, so we hardcode
the 1193182 and leave it at that. It's probably not important.
Change a few other sysbeep() uses which obviously knew that the
argument was in terms of i8254 frequency, and leave alone those
that look like people thought sysbeep() took frequency in hertz.
This eliminates the knowledge of i8254_freq from all but the actual
clock.c code and the prof_machdep.c on amd64 and i386, where I think
it would be smart to ask for help from the timecounters anyway [TBD].
2008-03-26 20:09:21 +00:00
|
|
|
mtx_unlock_spin(&clock_lock);
|
|
|
|
}
|
|
|
|
|
1994-04-21 14:19:16 +00:00
|
|
|
static int
|
1995-08-25 19:24:56 +00:00
|
|
|
getit(void)
|
1994-04-21 14:19:16 +00:00
|
|
|
{
|
2000-10-06 02:20:21 +00:00
|
|
|
int high, low;
|
1994-04-21 14:19:16 +00:00
|
|
|
|
2004-07-11 17:50:59 +00:00
|
|
|
mtx_lock_spin(&clock_lock);
|
1996-06-17 12:50:22 +00:00
|
|
|
|
|
|
|
/* Select timer0 and latch counter value. */
|
1996-10-25 13:46:21 +00:00
|
|
|
outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
|
1996-06-17 12:50:22 +00:00
|
|
|
|
1994-04-21 14:19:16 +00:00
|
|
|
low = inb(TIMER_CNTR0);
|
|
|
|
high = inb(TIMER_CNTR0);
|
1996-06-17 12:50:22 +00:00
|
|
|
|
2004-07-11 17:50:59 +00:00
|
|
|
mtx_unlock_spin(&clock_lock);
|
1994-04-21 14:19:16 +00:00
|
|
|
return ((high << 8) | low);
|
|
|
|
}
|
|
|
|
|
2011-04-08 19:54:29 +00:00
|
|
|
#ifndef DELAYDEBUG
|
2011-04-11 19:27:44 +00:00
|
|
|
static u_int
|
|
|
|
get_tsc(__unused struct timecounter *tc)
|
2011-03-14 22:05:59 +00:00
|
|
|
{
|
|
|
|
|
2011-04-14 19:11:45 +00:00
|
|
|
return (rdtsc32());
|
2011-03-14 22:05:59 +00:00
|
|
|
}
|
|
|
|
|
2011-04-11 19:27:44 +00:00
|
|
|
static __inline int
|
|
|
|
delay_tc(int n)
|
2011-03-14 22:05:59 +00:00
|
|
|
{
|
2011-04-11 19:27:44 +00:00
|
|
|
struct timecounter *tc;
|
|
|
|
timecounter_get_t *func;
|
|
|
|
uint64_t end, freq, now;
|
2011-03-14 22:05:59 +00:00
|
|
|
u_int last, mask, u;
|
|
|
|
|
2011-04-11 19:27:44 +00:00
|
|
|
tc = timecounter;
|
|
|
|
freq = atomic_load_acq_64(&tsc_freq);
|
2011-04-12 22:41:52 +00:00
|
|
|
if (tsc_is_invariant && freq != 0) {
|
2011-04-11 19:27:44 +00:00
|
|
|
func = get_tsc;
|
|
|
|
mask = ~0u;
|
|
|
|
} else {
|
|
|
|
if (tc->tc_quality <= 0)
|
|
|
|
return (0);
|
|
|
|
func = tc->tc_get_timecount;
|
|
|
|
mask = tc->tc_counter_mask;
|
|
|
|
freq = tc->tc_frequency;
|
|
|
|
}
|
2011-03-14 22:05:59 +00:00
|
|
|
now = 0;
|
2011-04-11 19:27:44 +00:00
|
|
|
end = freq * n / 1000000;
|
|
|
|
if (func == get_tsc)
|
|
|
|
sched_pin();
|
|
|
|
last = func(tc) & mask;
|
2011-03-14 22:05:59 +00:00
|
|
|
do {
|
|
|
|
cpu_spinwait();
|
2011-04-11 19:27:44 +00:00
|
|
|
u = func(tc) & mask;
|
2011-03-14 22:05:59 +00:00
|
|
|
if (u < last)
|
|
|
|
now += mask - last + u + 1;
|
|
|
|
else
|
|
|
|
now += u - last;
|
|
|
|
last = u;
|
|
|
|
} while (now < end);
|
2011-04-11 19:27:44 +00:00
|
|
|
if (func == get_tsc)
|
|
|
|
sched_unpin();
|
|
|
|
return (1);
|
2011-03-14 22:05:59 +00:00
|
|
|
}
|
2011-04-08 19:54:29 +00:00
|
|
|
#endif
|
2011-03-14 22:05:59 +00:00
|
|
|
|
1994-04-21 14:19:16 +00:00
|
|
|
/*
|
|
|
|
* Wait "n" microseconds.
|
2008-03-26 15:03:24 +00:00
|
|
|
* Relies on timer 1 counting down from (i8254_freq / hz)
|
1994-04-21 14:19:16 +00:00
|
|
|
* Note: timer had better have been programmed before this is first used!
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
DELAY(int n)
|
|
|
|
{
|
1997-01-29 22:51:44 +00:00
|
|
|
int delta, prev_tick, tick, ticks_left;
|
1994-04-21 14:19:16 +00:00
|
|
|
#ifdef DELAYDEBUG
|
|
|
|
int getit_calls = 1;
|
|
|
|
int n1;
|
|
|
|
static int state = 0;
|
2011-04-08 19:54:29 +00:00
|
|
|
|
|
|
|
if (state == 0) {
|
|
|
|
state = 1;
|
|
|
|
for (n1 = 1; n1 <= 10000000; n1 *= 10)
|
|
|
|
DELAY(n1);
|
|
|
|
state = 2;
|
|
|
|
}
|
|
|
|
if (state == 1)
|
|
|
|
printf("DELAY(%d)...", n);
|
|
|
|
#else
|
2011-04-11 19:27:44 +00:00
|
|
|
if (delay_tc(n))
|
2011-03-14 22:05:59 +00:00
|
|
|
return;
|
1994-04-21 14:19:16 +00:00
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* Read the counter first, so that the rest of the setup overhead is
|
|
|
|
* counted. Guess the initial overhead is 20 usec (on most systems it
|
|
|
|
* takes about 1.5 usec for each of the i/o's in getit(). The loop
|
|
|
|
* takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
|
|
|
|
* multiplications and divisions to scale the count take a while).
|
2004-07-11 17:50:59 +00:00
|
|
|
*
|
|
|
|
* However, if ddb is active then use a fake counter since reading
|
|
|
|
* the i8254 counter involves acquiring a lock. ddb must not do
|
|
|
|
* locking for many reasons, but it calls here for at least atkbd
|
|
|
|
* input.
|
1994-04-21 14:19:16 +00:00
|
|
|
*/
|
2004-07-11 17:50:59 +00:00
|
|
|
#ifdef KDB
|
|
|
|
if (kdb_active)
|
|
|
|
prev_tick = 1;
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
prev_tick = getit();
|
1997-01-29 22:51:44 +00:00
|
|
|
n -= 0; /* XXX actually guess no initial overhead */
|
1994-04-21 14:19:16 +00:00
|
|
|
/*
|
2008-03-26 15:03:24 +00:00
|
|
|
* Calculate (n * (i8254_freq / 1e6)) without using floating point
|
1994-04-21 14:19:16 +00:00
|
|
|
* and without any avoidable overflows.
|
|
|
|
*/
|
1997-01-29 22:51:44 +00:00
|
|
|
if (n <= 0)
|
|
|
|
ticks_left = 0;
|
|
|
|
else if (n < 256)
|
|
|
|
/*
|
|
|
|
* Use fixed point to avoid a slow division by 1000000.
|
|
|
|
* 39099 = 1193182 * 2^15 / 10^6 rounded to nearest.
|
|
|
|
* 2^15 is the first power of 2 that gives exact results
|
|
|
|
* for n between 0 and 256.
|
|
|
|
*/
|
|
|
|
ticks_left = ((u_int)n * 39099 + (1 << 15) - 1) >> 15;
|
|
|
|
else
|
|
|
|
/*
|
|
|
|
* Don't bother using fixed point, although gcc-2.7.2
|
|
|
|
* generates particularly poor code for the long long
|
|
|
|
* division, since even the slow way will complete long
|
|
|
|
* before the delay is up (unless we're interrupted).
|
|
|
|
*/
|
2008-03-26 15:03:24 +00:00
|
|
|
ticks_left = ((u_int)n * (long long)i8254_freq + 999999)
|
1997-01-29 22:51:44 +00:00
|
|
|
/ 1000000;
|
1994-04-21 14:19:16 +00:00
|
|
|
|
|
|
|
while (ticks_left > 0) {
|
2004-07-11 17:50:59 +00:00
|
|
|
#ifdef KDB
|
|
|
|
if (kdb_active) {
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifdef PC98
|
|
|
|
outb(0x5f, 0);
|
|
|
|
#else
|
2004-07-11 17:50:59 +00:00
|
|
|
inb(0x84);
|
2010-07-13 06:57:27 +00:00
|
|
|
#endif
|
2004-07-11 17:50:59 +00:00
|
|
|
tick = prev_tick - 1;
|
|
|
|
if (tick <= 0)
|
2008-03-26 15:03:24 +00:00
|
|
|
tick = i8254_max_count;
|
2004-07-11 17:50:59 +00:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
tick = getit();
|
1994-04-21 14:19:16 +00:00
|
|
|
#ifdef DELAYDEBUG
|
|
|
|
++getit_calls;
|
|
|
|
#endif
|
1997-01-16 18:28:20 +00:00
|
|
|
delta = prev_tick - tick;
|
1994-04-21 14:19:16 +00:00
|
|
|
prev_tick = tick;
|
1997-01-16 18:28:20 +00:00
|
|
|
if (delta < 0) {
|
2008-03-26 15:03:24 +00:00
|
|
|
delta += i8254_max_count;
|
1997-01-16 18:28:20 +00:00
|
|
|
/*
|
2008-03-26 15:03:24 +00:00
|
|
|
* Guard against i8254_max_count being wrong.
|
1997-01-16 18:28:20 +00:00
|
|
|
* This shouldn't happen in normal operation,
|
2008-03-26 15:03:24 +00:00
|
|
|
* but it may happen if set_i8254_freq() is
|
1997-01-16 18:28:20 +00:00
|
|
|
* traced.
|
|
|
|
*/
|
|
|
|
if (delta < 0)
|
|
|
|
delta = 0;
|
|
|
|
}
|
|
|
|
ticks_left -= delta;
|
1994-04-21 14:19:16 +00:00
|
|
|
}
|
|
|
|
#ifdef DELAYDEBUG
|
|
|
|
if (state == 1)
|
|
|
|
printf(" %d calls to getit() at %d usec each\n",
|
|
|
|
getit_calls, (n + 5) / getit_calls);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
1996-05-01 08:39:02 +00:00
|
|
|
static void
|
2010-09-17 04:48:50 +00:00
|
|
|
set_i8254_freq(int mode, uint32_t period)
|
1996-05-01 08:39:02 +00:00
|
|
|
{
|
2010-09-18 07:36:43 +00:00
|
|
|
int new_count;
|
1996-05-01 08:39:02 +00:00
|
|
|
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
mtx_lock_spin(&clock_lock);
|
2010-09-18 07:36:43 +00:00
|
|
|
if (mode == MODE_STOP) {
|
|
|
|
if (i8254_timecounter) {
|
|
|
|
mode = MODE_PERIODIC;
|
|
|
|
new_count = 0x10000;
|
|
|
|
} else
|
|
|
|
new_count = -1;
|
|
|
|
} else {
|
|
|
|
new_count = min(((uint64_t)i8254_freq * period +
|
|
|
|
0x80000000LLU) >> 32, 0x10000);
|
|
|
|
}
|
|
|
|
if (new_count == timer0_period)
|
|
|
|
goto out;
|
|
|
|
i8254_max_count = ((new_count & ~0xffff) != 0) ? 0xffff : new_count;
|
|
|
|
timer0_period = (mode == MODE_PERIODIC) ? new_count : -1;
|
2010-09-17 04:48:50 +00:00
|
|
|
switch (mode) {
|
|
|
|
case MODE_STOP:
|
|
|
|
outb(TIMER_MODE, TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT);
|
2010-09-18 07:36:43 +00:00
|
|
|
outb(TIMER_CNTR0, 0);
|
|
|
|
outb(TIMER_CNTR0, 0);
|
2010-09-17 04:48:50 +00:00
|
|
|
break;
|
|
|
|
case MODE_PERIODIC:
|
1998-02-13 06:33:16 +00:00
|
|
|
outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
|
2010-09-18 07:36:43 +00:00
|
|
|
outb(TIMER_CNTR0, new_count & 0xff);
|
|
|
|
outb(TIMER_CNTR0, new_count >> 8);
|
2010-09-17 04:48:50 +00:00
|
|
|
break;
|
|
|
|
case MODE_ONESHOT:
|
|
|
|
outb(TIMER_MODE, TIMER_SEL0 | TIMER_INTTC | TIMER_16BIT);
|
2010-09-18 07:36:43 +00:00
|
|
|
outb(TIMER_CNTR0, new_count & 0xff);
|
|
|
|
outb(TIMER_CNTR0, new_count >> 8);
|
2010-09-17 04:48:50 +00:00
|
|
|
break;
|
1998-02-13 06:33:16 +00:00
|
|
|
}
|
2010-09-18 07:36:43 +00:00
|
|
|
out:
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
mtx_unlock_spin(&clock_lock);
|
1996-05-01 08:39:02 +00:00
|
|
|
}
|
|
|
|
|
2001-09-04 16:02:06 +00:00
|
|
|
static void
|
1999-10-30 14:56:01 +00:00
|
|
|
i8254_restore(void)
|
|
|
|
{
|
|
|
|
|
2010-09-18 07:36:43 +00:00
|
|
|
timer0_period = -2;
|
|
|
|
if (attimer_sc != NULL)
|
2010-09-17 04:48:50 +00:00
|
|
|
set_i8254_freq(attimer_sc->mode, attimer_sc->period);
|
|
|
|
else
|
|
|
|
set_i8254_freq(0, 0);
|
1999-10-30 14:56:01 +00:00
|
|
|
}
|
|
|
|
|
2010-02-25 14:13:39 +00:00
|
|
|
#ifndef __amd64__
|
2001-09-04 16:02:06 +00:00
|
|
|
/*
|
2002-10-17 13:55:39 +00:00
|
|
|
* Restore all the timers non-atomically (XXX: should be atomically).
|
|
|
|
*
|
|
|
|
* This function is called from pmtimer_resume() to restore all the timers.
|
|
|
|
* This should not be necessary, but there are broken laptops that do not
|
|
|
|
* restore all the timers on resume.
|
2010-02-25 14:13:39 +00:00
|
|
|
* As long as pmtimer is not part of amd64 suport, skip this for the amd64
|
|
|
|
* case.
|
2001-09-04 16:02:06 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
timer_restore(void)
|
|
|
|
{
|
|
|
|
|
2008-03-26 15:03:24 +00:00
|
|
|
i8254_restore(); /* restore i8254_freq and hz */
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifndef PC98
|
2008-04-14 08:00:00 +00:00
|
|
|
atrtc_restore(); /* reenable RTC interrupts */
|
2010-07-13 06:57:27 +00:00
|
|
|
#endif
|
2001-09-04 16:02:06 +00:00
|
|
|
}
|
2010-02-25 14:13:39 +00:00
|
|
|
#endif
|
2001-09-04 16:02:06 +00:00
|
|
|
|
2007-01-23 08:01:20 +00:00
|
|
|
/* This is separate from startrtclock() so that it can be called early. */
|
|
|
|
void
|
|
|
|
i8254_init(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
mtx_init(&clock_lock, "clk", NULL, MTX_SPIN | MTX_NOPROFILE);
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifdef PC98
|
|
|
|
if (pc98_machine_type & M_8M)
|
|
|
|
i8254_freq = 1996800L; /* 1.9968 MHz */
|
|
|
|
#endif
|
2010-09-17 04:48:50 +00:00
|
|
|
set_i8254_freq(0, 0);
|
2007-01-23 08:01:20 +00:00
|
|
|
}
|
|
|
|
|
1993-11-25 01:38:01 +00:00
|
|
|
void
|
1995-05-30 08:16:23 +00:00
|
|
|
startrtclock()
|
1993-11-25 01:38:01 +00:00
|
|
|
{
|
1996-05-01 08:39:02 +00:00
|
|
|
|
2003-02-11 11:43:25 +00:00
|
|
|
init_TSC();
|
1993-06-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
1994-12-30 12:43:35 +00:00
|
|
|
void
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
cpu_initclocks(void)
|
1993-06-12 14:58:17 +00:00
|
|
|
{
|
2000-10-06 02:20:21 +00:00
|
|
|
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
cpu_initclocks_bsp();
|
1994-05-25 09:21:21 +00:00
|
|
|
}
|
1996-05-01 08:39:02 +00:00
|
|
|
|
|
|
|
static int
|
2000-07-04 11:25:35 +00:00
|
|
|
sysctl_machdep_i8254_freq(SYSCTL_HANDLER_ARGS)
|
1996-05-01 08:39:02 +00:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
u_int freq;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use `i8254' instead of `timer' in external names because `timer'
|
2011-02-23 09:22:33 +00:00
|
|
|
* is too generic. Should use it everywhere.
|
1996-05-01 08:39:02 +00:00
|
|
|
*/
|
2008-03-26 15:03:24 +00:00
|
|
|
freq = i8254_freq;
|
2007-06-04 18:25:08 +00:00
|
|
|
error = sysctl_handle_int(oidp, &freq, 0, req);
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
if (error == 0 && req->newptr != NULL) {
|
2010-09-17 04:48:50 +00:00
|
|
|
i8254_freq = freq;
|
2010-09-18 07:36:43 +00:00
|
|
|
if (attimer_sc != NULL) {
|
2010-09-17 04:48:50 +00:00
|
|
|
set_i8254_freq(attimer_sc->mode, attimer_sc->period);
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
attimer_sc->tc.tc_frequency = freq;
|
|
|
|
} else {
|
2010-09-17 04:48:50 +00:00
|
|
|
set_i8254_freq(0, 0);
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
}
|
|
|
|
}
|
1996-05-01 08:39:02 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW,
|
2011-04-14 00:07:08 +00:00
|
|
|
0, sizeof(u_int), sysctl_machdep_i8254_freq, "IU",
|
|
|
|
"i8254 timer frequency");
|
1996-05-01 08:39:02 +00:00
|
|
|
|
1998-05-28 09:30:28 +00:00
|
|
|
static unsigned
|
1998-06-07 08:40:53 +00:00
|
|
|
i8254_get_timecount(struct timecounter *tc)
|
1998-02-20 16:36:17 +00:00
|
|
|
{
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
device_t dev = (device_t)tc->tc_priv;
|
|
|
|
struct attimer_softc *sc = device_get_softc(dev);
|
2010-02-25 14:13:39 +00:00
|
|
|
register_t flags;
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
uint16_t count;
|
1998-02-20 16:36:17 +00:00
|
|
|
u_int high, low;
|
|
|
|
|
2010-09-17 04:48:50 +00:00
|
|
|
if (sc->period == 0)
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
return (i8254_max_count - getit());
|
|
|
|
|
2010-02-25 14:13:39 +00:00
|
|
|
#ifdef __amd64__
|
|
|
|
flags = read_rflags();
|
|
|
|
#else
|
|
|
|
flags = read_eflags();
|
|
|
|
#endif
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
mtx_lock_spin(&clock_lock);
|
1998-02-20 16:36:17 +00:00
|
|
|
|
|
|
|
/* Select timer0 and latch counter value. */
|
|
|
|
outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
|
|
|
|
|
|
|
|
low = inb(TIMER_CNTR0);
|
|
|
|
high = inb(TIMER_CNTR0);
|
2008-03-26 15:03:24 +00:00
|
|
|
count = i8254_max_count - ((high << 8) | low);
|
1999-05-28 14:08:59 +00:00
|
|
|
if (count < i8254_lastcount ||
|
|
|
|
(!i8254_ticked && (clkintr_pending ||
|
2010-02-25 14:13:39 +00:00
|
|
|
((count < 20 || (!(flags & PSL_I) &&
|
2008-04-12 20:46:06 +00:00
|
|
|
count < i8254_max_count / 2u)) &&
|
2004-04-27 20:03:26 +00:00
|
|
|
i8254_pending != NULL && i8254_pending(i8254_intsrc))))) {
|
1998-02-20 16:36:17 +00:00
|
|
|
i8254_ticked = 1;
|
2008-03-26 15:03:24 +00:00
|
|
|
i8254_offset += i8254_max_count;
|
1998-02-20 16:36:17 +00:00
|
|
|
}
|
|
|
|
i8254_lastcount = count;
|
|
|
|
count += i8254_offset;
|
Change and clean the mutex lock interface.
mtx_enter(lock, type) becomes:
mtx_lock(lock) for sleep locks (MTX_DEF-initialized locks)
mtx_lock_spin(lock) for spin locks (MTX_SPIN-initialized)
similarily, for releasing a lock, we now have:
mtx_unlock(lock) for MTX_DEF and mtx_unlock_spin(lock) for MTX_SPIN.
We change the caller interface for the two different types of locks
because the semantics are entirely different for each case, and this
makes it explicitly clear and, at the same time, it rids us of the
extra `type' argument.
The enter->lock and exit->unlock change has been made with the idea
that we're "locking data" and not "entering locked code" in mind.
Further, remove all additional "flags" previously passed to the
lock acquire/release routines with the exception of two:
MTX_QUIET and MTX_NOSWITCH
The functionality of these flags is preserved and they can be passed
to the lock/unlock routines by calling the corresponding wrappers:
mtx_{lock, unlock}_flags(lock, flag(s)) and
mtx_{lock, unlock}_spin_flags(lock, flag(s)) for MTX_DEF and MTX_SPIN
locks, respectively.
Re-inline some lock acq/rel code; in the sleep lock case, we only
inline the _obtain_lock()s in order to ensure that the inlined code
fits into a cache line. In the spin lock case, we inline recursion and
actually only perform a function call if we need to spin. This change
has been made with the idea that we generally tend to avoid spin locks
and that also the spin locks that we do have and are heavily used
(i.e. sched_lock) do recurse, and therefore in an effort to reduce
function call overhead for some architectures (such as alpha), we
inline recursion for this case.
Create a new malloc type for the witness code and retire from using
the M_DEV type. The new type is called M_WITNESS and is only declared
if WITNESS is enabled.
Begin cleaning up some machdep/mutex.h code - specifically updated the
"optimized" inlined code in alpha/mutex.h and wrote MTX_LOCK_SPIN
and MTX_UNLOCK_SPIN asm macros for the i386/mutex.h as we presently
need those.
Finally, caught up to the interface changes in all sys code.
Contributors: jake, jhb, jasone (in no particular order)
2001-02-09 06:11:45 +00:00
|
|
|
mtx_unlock_spin(&clock_lock);
|
1998-02-20 16:36:17 +00:00
|
|
|
return (count);
|
|
|
|
}
|
|
|
|
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
static int
|
|
|
|
attimer_start(struct eventtimer *et,
|
|
|
|
struct bintime *first, struct bintime *period)
|
|
|
|
{
|
|
|
|
device_t dev = (device_t)et->et_priv;
|
|
|
|
struct attimer_softc *sc = device_get_softc(dev);
|
2010-09-17 04:48:50 +00:00
|
|
|
|
|
|
|
if (period != NULL) {
|
|
|
|
sc->mode = MODE_PERIODIC;
|
|
|
|
sc->period = period->frac >> 32;
|
|
|
|
} else {
|
|
|
|
sc->mode = MODE_ONESHOT;
|
|
|
|
sc->period = first->frac >> 32;
|
|
|
|
}
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
if (!sc->intr_en) {
|
|
|
|
i8254_intsrc->is_pic->pic_enable_source(i8254_intsrc);
|
|
|
|
sc->intr_en = 1;
|
|
|
|
}
|
2010-09-17 04:48:50 +00:00
|
|
|
set_i8254_freq(sc->mode, sc->period);
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
attimer_stop(struct eventtimer *et)
|
|
|
|
{
|
|
|
|
device_t dev = (device_t)et->et_priv;
|
|
|
|
struct attimer_softc *sc = device_get_softc(dev);
|
|
|
|
|
2010-09-17 04:48:50 +00:00
|
|
|
sc->mode = MODE_STOP;
|
|
|
|
sc->period = 0;
|
|
|
|
set_i8254_freq(sc->mode, sc->period);
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2002-01-30 12:41:12 +00:00
|
|
|
#ifdef DEV_ISA
|
2000-06-23 07:44:33 +00:00
|
|
|
/*
|
2008-04-12 20:46:06 +00:00
|
|
|
* Attach to the ISA PnP descriptors for the timer
|
2000-06-23 07:44:33 +00:00
|
|
|
*/
|
|
|
|
static struct isa_pnp_id attimer_ids[] = {
|
|
|
|
{ 0x0001d041 /* PNP0100 */, "AT timer" },
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifdef PC98
|
|
|
|
static void
|
|
|
|
pc98_alloc_resource(device_t dev)
|
|
|
|
{
|
|
|
|
static bus_addr_t iat1[] = {0, 2, 4, 6};
|
|
|
|
static bus_addr_t iat2[] = {0, 4};
|
|
|
|
struct attimer_softc *sc;
|
|
|
|
|
|
|
|
sc = device_get_softc(dev);
|
|
|
|
|
|
|
|
sc->port_rid = 0;
|
|
|
|
bus_set_resource(dev, SYS_RES_IOPORT, sc->port_rid, IO_TIMER1, 1);
|
|
|
|
sc->port_res = isa_alloc_resourcev(dev, SYS_RES_IOPORT,
|
|
|
|
&sc->port_rid, iat1, 4, RF_ACTIVE);
|
|
|
|
if (sc->port_res == NULL)
|
|
|
|
device_printf(dev, "Warning: Couldn't map I/O.\n");
|
|
|
|
else
|
|
|
|
isa_load_resourcev(sc->port_res, iat1, 4);
|
|
|
|
|
|
|
|
sc->port_rid2 = 4;
|
|
|
|
bus_set_resource(dev, SYS_RES_IOPORT, sc->port_rid2, TIMER_CNTR1, 1);
|
|
|
|
sc->port_res2 = isa_alloc_resourcev(dev, SYS_RES_IOPORT,
|
|
|
|
&sc->port_rid2, iat2, 2, RF_ACTIVE);
|
|
|
|
if (sc->port_res2 == NULL)
|
|
|
|
device_printf(dev, "Warning: Couldn't map I/O.\n");
|
|
|
|
else
|
|
|
|
isa_load_resourcev(sc->port_res2, iat2, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
pc98_release_resource(device_t dev)
|
|
|
|
{
|
|
|
|
struct attimer_softc *sc;
|
|
|
|
|
|
|
|
sc = device_get_softc(dev);
|
|
|
|
|
|
|
|
if (sc->port_res)
|
|
|
|
bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid,
|
|
|
|
sc->port_res);
|
|
|
|
if (sc->port_res2)
|
|
|
|
bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid2,
|
|
|
|
sc->port_res2);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-06-23 07:44:33 +00:00
|
|
|
static int
|
|
|
|
attimer_probe(device_t dev)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
2008-04-12 20:46:06 +00:00
|
|
|
result = ISA_PNP_PROBE(device_get_parent(dev), dev, attimer_ids);
|
2010-07-01 18:59:05 +00:00
|
|
|
/* ENOENT means no PnP-ID, device is hinted. */
|
|
|
|
if (result == ENOENT) {
|
|
|
|
device_set_desc(dev, "AT timer");
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifdef PC98
|
|
|
|
/* To print resources correctly. */
|
|
|
|
pc98_alloc_resource(dev);
|
|
|
|
pc98_release_resource(dev);
|
|
|
|
#endif
|
2010-07-01 18:59:05 +00:00
|
|
|
return (BUS_PROBE_LOW_PRIORITY);
|
|
|
|
}
|
|
|
|
return (result);
|
2000-06-23 07:44:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
attimer_attach(device_t dev)
|
|
|
|
{
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
struct attimer_softc *sc;
|
2010-07-12 06:46:17 +00:00
|
|
|
u_long s;
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
attimer_sc = sc = device_get_softc(dev);
|
|
|
|
bzero(sc, sizeof(struct attimer_softc));
|
2010-07-13 06:57:27 +00:00
|
|
|
#ifdef PC98
|
|
|
|
pc98_alloc_resource(dev);
|
|
|
|
#else
|
2010-07-12 06:46:17 +00:00
|
|
|
if (!(sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
|
|
|
&sc->port_rid, IO_TIMER1, IO_TIMER1 + 3, 4, RF_ACTIVE)))
|
|
|
|
device_printf(dev,"Warning: Couldn't map I/O.\n");
|
2010-07-13 06:57:27 +00:00
|
|
|
#endif
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
i8254_intsrc = intr_lookup_source(0);
|
|
|
|
if (i8254_intsrc != NULL)
|
|
|
|
i8254_pending = i8254_intsrc->is_pic->pic_source_pending;
|
2010-09-17 04:48:50 +00:00
|
|
|
resource_int_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"timecounter", &i8254_timecounter);
|
|
|
|
set_i8254_freq(0, 0);
|
|
|
|
if (i8254_timecounter) {
|
|
|
|
sc->tc.tc_get_timecount = i8254_get_timecount;
|
|
|
|
sc->tc.tc_counter_mask = 0xffff;
|
|
|
|
sc->tc.tc_frequency = i8254_freq;
|
|
|
|
sc->tc.tc_name = "i8254";
|
|
|
|
sc->tc.tc_quality = 0;
|
|
|
|
sc->tc.tc_priv = dev;
|
|
|
|
tc_init(&sc->tc);
|
|
|
|
}
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"clock", &i) != 0 || i != 0) {
|
2010-07-01 18:51:18 +00:00
|
|
|
sc->intr_rid = 0;
|
2010-07-12 06:46:17 +00:00
|
|
|
while (bus_get_resource(dev, SYS_RES_IRQ, sc->intr_rid,
|
|
|
|
&s, NULL) == 0 && s != 0)
|
|
|
|
sc->intr_rid++;
|
2010-06-22 19:42:27 +00:00
|
|
|
if (!(sc->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ,
|
|
|
|
&sc->intr_rid, 0, 0, 1, RF_ACTIVE))) {
|
|
|
|
device_printf(dev,"Can't map interrupt.\n");
|
|
|
|
return (0);
|
|
|
|
}
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
/* Dirty hack, to make bus_setup_intr to not enable source. */
|
|
|
|
i8254_intsrc->is_handlers++;
|
|
|
|
if ((bus_setup_intr(dev, sc->intr_res,
|
|
|
|
INTR_MPSAFE | INTR_TYPE_CLK,
|
|
|
|
(driver_filter_t *)clkintr, NULL,
|
|
|
|
sc, &sc->intr_handler))) {
|
|
|
|
device_printf(dev, "Can't setup interrupt.\n");
|
2010-06-22 19:42:27 +00:00
|
|
|
i8254_intsrc->is_handlers--;
|
|
|
|
return (0);
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
}
|
|
|
|
i8254_intsrc->is_handlers--;
|
2010-06-22 19:42:27 +00:00
|
|
|
i8254_intsrc->is_pic->pic_enable_intr(i8254_intsrc);
|
|
|
|
sc->et.et_name = "i8254";
|
|
|
|
sc->et.et_flags = ET_FLAGS_PERIODIC;
|
2010-09-17 04:48:50 +00:00
|
|
|
if (!i8254_timecounter)
|
|
|
|
sc->et.et_flags |= ET_FLAGS_ONESHOT;
|
2010-06-22 19:42:27 +00:00
|
|
|
sc->et.et_quality = 100;
|
|
|
|
sc->et.et_frequency = i8254_freq;
|
2010-07-20 10:58:56 +00:00
|
|
|
sc->et.et_min_period.sec = 0;
|
2010-07-20 15:48:29 +00:00
|
|
|
sc->et.et_min_period.frac =
|
|
|
|
((0x0002LLU << 48) / i8254_freq) << 16;
|
2010-07-20 10:58:56 +00:00
|
|
|
sc->et.et_max_period.sec = 0xffff / i8254_freq;
|
|
|
|
sc->et.et_max_period.frac =
|
2010-07-20 15:48:29 +00:00
|
|
|
((0xfffeLLU << 48) / i8254_freq) << 16;
|
2010-06-22 19:42:27 +00:00
|
|
|
sc->et.et_start = attimer_start;
|
|
|
|
sc->et.et_stop = attimer_stop;
|
|
|
|
sc->et.et_priv = dev;
|
|
|
|
et_register(&sc->et);
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
}
|
2000-06-23 07:44:33 +00:00
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
2010-02-25 14:13:39 +00:00
|
|
|
static int
|
|
|
|
attimer_resume(device_t dev)
|
|
|
|
{
|
|
|
|
|
|
|
|
i8254_restore();
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2000-06-23 07:44:33 +00:00
|
|
|
static device_method_t attimer_methods[] = {
|
|
|
|
/* Device interface */
|
|
|
|
DEVMETHOD(device_probe, attimer_probe),
|
|
|
|
DEVMETHOD(device_attach, attimer_attach),
|
|
|
|
DEVMETHOD(device_detach, bus_generic_detach),
|
|
|
|
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
2008-04-12 20:46:06 +00:00
|
|
|
DEVMETHOD(device_suspend, bus_generic_suspend),
|
2010-02-25 14:13:39 +00:00
|
|
|
DEVMETHOD(device_resume, attimer_resume),
|
2000-06-23 07:44:33 +00:00
|
|
|
{ 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
static driver_t attimer_driver = {
|
|
|
|
"attimer",
|
|
|
|
attimer_methods,
|
Implement new event timers infrastructure. It provides unified APIs for
writing event timer drivers, for choosing best possible drivers by machine
independent code and for operating them to supply kernel with hardclock(),
statclock() and profclock() events in unified fashion on various hardware.
Infrastructure provides support for both per-CPU (independent for every CPU
core) and global timers in periodic and one-shot modes. MI management code
at this moment uses only periodic mode, but one-shot mode use planned for
later, as part of tickless kernel project.
For this moment infrastructure used on i386 and amd64 architectures. Other
archs are welcome to follow, while their current operation should not be
affected.
This patch updates existing drivers (i8254, RTC and LAPIC) for the new
order, and adds event timers support into the HPET driver. These drivers
have different capabilities:
LAPIC - per-CPU timer, supports periodic and one-shot operation, may
freeze in C3 state, calibrated on first use, so may be not exactly precise.
HPET - depending on hardware can work as per-CPU or global, supports
periodic and one-shot operation, usually provides several event timers.
i8254 - global, limited to periodic mode, because same hardware used also
as time counter.
RTC - global, supports only periodic mode, set of frequencies in Hz
limited by powers of 2.
Depending on hardware capabilities, drivers preferred in following orders,
either LAPIC, HPETs, i8254, RTC or HPETs, LAPIC, i8254, RTC.
User may explicitly specify wanted timers via loader tunables or sysctls:
kern.eventtimer.timer1 and kern.eventtimer.timer2.
If requested driver is unavailable or unoperational, system will try to
replace it. If no more timers available or "NONE" specified for second,
system will operate using only one timer, multiplying it's frequency by few
times and uing respective dividers to honor hz, stathz and profhz values,
set during initial setup.
2010-06-20 21:33:29 +00:00
|
|
|
sizeof(struct attimer_softc),
|
2000-06-23 07:44:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static devclass_t attimer_devclass;
|
|
|
|
|
|
|
|
DRIVER_MODULE(attimer, isa, attimer_driver, attimer_devclass, 0, 0);
|
2001-08-30 09:17:03 +00:00
|
|
|
DRIVER_MODULE(attimer, acpi, attimer_driver, attimer_devclass, 0, 0);
|
2007-06-15 22:58:14 +00:00
|
|
|
|
2002-01-30 12:41:12 +00:00
|
|
|
#endif /* DEV_ISA */
|