Rename statclock_disable variable to atrtcclock_disable that it actually is,
and hide it inside of atrtc driver. Add new tunable hint.atrtc.0.clock controlling it. Setting it to 0 disables using RTC clock as stat-/ profclock sources. Teach i386 and amd64 SMP platforms to emulate stat-/profclocks using i8254 hardclock, when LAPIC and RTC clocks are disabled. This allows to reduce global interrupt rate of idle system down to about 100 interrupts per core, permitting C3 and deeper C-states provide maximum CPU power efficiency.
This commit is contained in:
parent
2500b6d96d
commit
1703f2b424
@ -15,7 +15,6 @@
|
||||
* XXX large parts of the driver and its interface are misplaced.
|
||||
*/
|
||||
extern int clkintr_pending;
|
||||
extern int statclock_disable;
|
||||
extern u_int i8254_freq;
|
||||
extern int i8254_max_count;
|
||||
extern uint64_t tsc_freq;
|
||||
|
@ -76,7 +76,6 @@ __FBSDID("$FreeBSD$");
|
||||
int clkintr_pending;
|
||||
static int pscnt = 1;
|
||||
static int psdiv = 1;
|
||||
int statclock_disable;
|
||||
#ifndef TIMER_FREQ
|
||||
#define TIMER_FREQ 1193182
|
||||
#endif
|
||||
@ -91,6 +90,7 @@ static u_int32_t i8254_lastcount;
|
||||
static u_int32_t i8254_offset;
|
||||
static int (*i8254_pending)(struct intsrc *);
|
||||
static int i8254_ticked;
|
||||
static int using_atrtc_timer;
|
||||
static int using_lapic_timer;
|
||||
|
||||
/* Values for timerX_state: */
|
||||
@ -122,6 +122,8 @@ hardclockintr(struct trapframe *frame)
|
||||
hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
|
||||
else
|
||||
hardclock_cpu(TRAPF_USERMODE(frame));
|
||||
if (!using_atrtc_timer)
|
||||
statclockintr(frame);
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
@ -163,10 +165,7 @@ clkintr(struct trapframe *frame)
|
||||
if (smp_started)
|
||||
ipi_all_but_self(IPI_HARDCLOCK);
|
||||
#endif
|
||||
if (PCPU_GET(cpuid) == 0)
|
||||
hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
|
||||
else
|
||||
hardclock_cpu(TRAPF_USERMODE(frame));
|
||||
hardclockintr(frame);
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
@ -461,7 +460,6 @@ startrtclock()
|
||||
void
|
||||
cpu_initclocks()
|
||||
{
|
||||
int diag;
|
||||
|
||||
using_lapic_timer = lapic_setup_clock();
|
||||
/*
|
||||
@ -493,21 +491,17 @@ cpu_initclocks()
|
||||
* kernel clocks, then setup the RTC to periodically interrupt to
|
||||
* drive statclock() and profclock().
|
||||
*/
|
||||
if (!statclock_disable && !using_lapic_timer) {
|
||||
diag = rtcin(RTC_DIAG);
|
||||
if (diag != 0)
|
||||
printf("RTC BIOS diagnostic error %b\n",
|
||||
diag, RTCDG_BITS);
|
||||
|
||||
/* Setting stathz to nonzero early helps avoid races. */
|
||||
stathz = RTC_NOPROFRATE;
|
||||
profhz = RTC_PROFRATE;
|
||||
|
||||
/* Enable periodic interrupts from the RTC. */
|
||||
intr_add_handler("rtc", 8,
|
||||
(driver_filter_t *)rtcintr, NULL, NULL,
|
||||
INTR_TYPE_CLK, NULL);
|
||||
atrtc_enable_intr();
|
||||
if (!using_lapic_timer) {
|
||||
using_atrtc_timer = atrtc_setup_clock();
|
||||
if (using_atrtc_timer) {
|
||||
/* Enable periodic interrupts from the RTC. */
|
||||
intr_add_handler("rtc", 8,
|
||||
(driver_filter_t *)rtcintr, NULL, NULL,
|
||||
INTR_TYPE_CLK, NULL);
|
||||
atrtc_enable_intr();
|
||||
} else {
|
||||
profhz = stathz = hz;
|
||||
}
|
||||
}
|
||||
|
||||
init_TSC_tc();
|
||||
|
@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/vm_param.h>
|
||||
|
||||
#include <i386/bios/apm.h>
|
||||
#include <isa/rtc.h>
|
||||
|
||||
/* Used by the apm_saver screen saver module */
|
||||
int apm_display(int newstate);
|
||||
@ -1155,7 +1156,7 @@ apm_attach(device_t dev)
|
||||
cv_init(&sc->cv, "cbb cv");
|
||||
|
||||
if (device_get_flags(dev) & 0x20)
|
||||
statclock_disable = 1;
|
||||
atrtcclock_disable = 1;
|
||||
|
||||
sc->initialized = 0;
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
* XXX large parts of the driver and its interface are misplaced.
|
||||
*/
|
||||
extern int clkintr_pending;
|
||||
extern int statclock_disable;
|
||||
extern u_int i8254_freq;
|
||||
extern int i8254_max_count;
|
||||
extern uint64_t tsc_freq;
|
||||
|
@ -91,7 +91,6 @@ __FBSDID("$FreeBSD$");
|
||||
int clkintr_pending;
|
||||
static int pscnt = 1;
|
||||
static int psdiv = 1;
|
||||
int statclock_disable;
|
||||
#ifndef TIMER_FREQ
|
||||
#define TIMER_FREQ 1193182
|
||||
#endif
|
||||
@ -106,6 +105,7 @@ static u_int32_t i8254_lastcount;
|
||||
static u_int32_t i8254_offset;
|
||||
static int (*i8254_pending)(struct intsrc *);
|
||||
static int i8254_ticked;
|
||||
static int using_atrtc_timer;
|
||||
static int using_lapic_timer;
|
||||
|
||||
/* Values for timerX_state: */
|
||||
@ -137,6 +137,8 @@ hardclockintr(struct trapframe *frame)
|
||||
hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
|
||||
else
|
||||
hardclock_cpu(TRAPF_USERMODE(frame));
|
||||
if (!using_atrtc_timer)
|
||||
statclockintr(frame);
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
@ -190,10 +192,7 @@ clkintr(struct trapframe *frame)
|
||||
if (smp_started)
|
||||
ipi_all_but_self(IPI_HARDCLOCK);
|
||||
#endif
|
||||
if (PCPU_GET(cpuid) == 0)
|
||||
hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
|
||||
else
|
||||
hardclock_cpu(TRAPF_USERMODE(frame));
|
||||
hardclockintr(frame);
|
||||
#ifdef DEV_MCA
|
||||
/* Reset clock interrupt by asserting bit 7 of port 0x61 */
|
||||
if (MCA_system)
|
||||
@ -508,7 +507,6 @@ startrtclock()
|
||||
void
|
||||
cpu_initclocks()
|
||||
{
|
||||
int diag;
|
||||
|
||||
#ifdef DEV_APIC
|
||||
using_lapic_timer = lapic_setup_clock();
|
||||
@ -542,21 +540,17 @@ cpu_initclocks()
|
||||
* kernel clocks, then setup the RTC to periodically interrupt to
|
||||
* drive statclock() and profclock().
|
||||
*/
|
||||
if (!statclock_disable && !using_lapic_timer) {
|
||||
diag = rtcin(RTC_DIAG);
|
||||
if (diag != 0)
|
||||
printf("RTC BIOS diagnostic error %b\n",
|
||||
diag, RTCDG_BITS);
|
||||
|
||||
/* Setting stathz to nonzero early helps avoid races. */
|
||||
stathz = RTC_NOPROFRATE;
|
||||
profhz = RTC_PROFRATE;
|
||||
|
||||
/* Enable periodic interrupts from the RTC. */
|
||||
intr_add_handler("rtc", 8,
|
||||
(driver_filter_t *)rtcintr, NULL, NULL,
|
||||
INTR_TYPE_CLK, NULL);
|
||||
atrtc_enable_intr();
|
||||
if (!using_lapic_timer) {
|
||||
using_atrtc_timer = atrtc_setup_clock();
|
||||
if (using_atrtc_timer) {
|
||||
/* Enable periodic interrupts from the RTC. */
|
||||
intr_add_handler("rtc", 8,
|
||||
(driver_filter_t *)rtcintr, NULL, NULL,
|
||||
INTR_TYPE_CLK, NULL);
|
||||
atrtc_enable_intr();
|
||||
} else {
|
||||
profhz = stathz = hz;
|
||||
}
|
||||
}
|
||||
|
||||
init_TSC_tc();
|
||||
|
@ -120,7 +120,6 @@ int adjkerntz; /* local offset from GMT in seconds */
|
||||
int clkintr_pending;
|
||||
int pscnt = 1;
|
||||
int psdiv = 1;
|
||||
int statclock_disable;
|
||||
int wall_cmos_clock;
|
||||
u_int timer_freq = TIMER_FREQ;
|
||||
static int independent_wallclock;
|
||||
|
@ -49,6 +49,8 @@ __FBSDID("$FreeBSD$");
|
||||
#define RTC_LOCK mtx_lock_spin(&clock_lock)
|
||||
#define RTC_UNLOCK mtx_unlock_spin(&clock_lock)
|
||||
|
||||
int atrtcclock_disable = 0;
|
||||
|
||||
static int rtc_reg = -1;
|
||||
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
|
||||
static u_char rtc_statusb = RTCSB_24HR;
|
||||
@ -133,6 +135,27 @@ atrtc_restore(void)
|
||||
rtcin(RTC_INTR);
|
||||
}
|
||||
|
||||
int
|
||||
atrtc_setup_clock(void)
|
||||
{
|
||||
int diag;
|
||||
|
||||
if (atrtcclock_disable)
|
||||
return (0);
|
||||
|
||||
diag = rtcin(RTC_DIAG);
|
||||
if (diag != 0) {
|
||||
printf("RTC BIOS diagnostic error %b\n",
|
||||
diag, RTCDG_BITS);
|
||||
return (0);
|
||||
}
|
||||
|
||||
stathz = RTC_NOPROFRATE;
|
||||
profhz = RTC_PROFRATE;
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* RTC driver for subr_rtc
|
||||
*/
|
||||
@ -173,6 +196,7 @@ static int
|
||||
atrtc_attach(device_t dev)
|
||||
{
|
||||
struct atrtc_softc *sc;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Not that we need them or anything, but grab our resources
|
||||
@ -187,6 +211,8 @@ atrtc_attach(device_t dev)
|
||||
&sc->intr_rid, 8, 8, 1, RF_ACTIVE)))
|
||||
device_printf(dev,"Warning: Couldn't map Interrupt.\n");
|
||||
clock_register(dev, 1000000);
|
||||
if (resource_int_value("atrtc", 0, "clock", &i) == 0 && i == 0)
|
||||
atrtcclock_disable = 1;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
@ -113,6 +113,8 @@
|
||||
|
||||
#ifdef _KERNEL
|
||||
extern struct mtx clock_lock;
|
||||
extern int atrtcclock_disable;
|
||||
int atrtc_setup_clock(void);
|
||||
int rtcin(int reg);
|
||||
void atrtc_start(void);
|
||||
void atrtc_rate(unsigned rate);
|
||||
|
@ -87,7 +87,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define TIMER_DIV(x) ((i8254_freq + (x) / 2) / (x))
|
||||
|
||||
int clkintr_pending;
|
||||
int statclock_disable;
|
||||
#ifndef TIMER_FREQ
|
||||
#define TIMER_FREQ 2457600
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user