summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/clock.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2000-10-06 02:20:21 +0000
committerjhb <jhb@FreeBSD.org>2000-10-06 02:20:21 +0000
commitfd275a78bd168fffc26552c4b2debf6f105a43ed (patch)
tree4da054c14beb1594089f5d38bd0b743156b65897 /sys/i386/isa/clock.c
parente638f1a0983968d7993bba04b23cd203d45680ce (diff)
downloadFreeBSD-src-fd275a78bd168fffc26552c4b2debf6f105a43ed.zip
FreeBSD-src-fd275a78bd168fffc26552c4b2debf6f105a43ed.tar.gz
- Change fast interrupts on x86 to push a full interrupt frame and to
return through doreti to handle ast's. This is necessary for the clock interrupts to work properly. - Change the clock interrupts on the x86 to be fast instead of threaded. This is needed because both hardclock() and statclock() need to run in the context of the current process, not in a separate thread context. - Kill the prevproc hack as it is no longer needed. - We really need Giant when we call psignal(), but we don't want to block during the clock interrupt. Instead, use two p_flag's in the proc struct to mark the current process as having a pending SIGVTALRM or a SIGPROF and let them be delivered during ast() when hardclock() has finished running. - Remove CLKF_BASEPRI, which was #ifdef'd out on the x86 anyways. It was broken on the x86 if it was turned on since cpl is gone. It's only use was to bogusly run softclock() directly during hardclock() rather than scheduling an SWI. - Remove the COM_LOCK simplelock and replace it with a clock_lock spin mutex. Since the spin mutex already handles disabling/restoring interrupts appropriately, this also lets us axe all the *_intr() fu. - Back out the hacks in the APIC_IO x86 cpu_initclocks() code to use temporary fast interrupts for the APIC trial. - Add two new process flags P_ALRMPEND and P_PROFPEND to mark the pending signals in hardclock() that are to be delivered in ast(). Submitted by: jakeb (making statclock safe in a fast interrupt) Submitted by: cp (concept of delaying signals until ast())
Diffstat (limited to 'sys/i386/isa/clock.c')
-rw-r--r--sys/i386/isa/clock.c157
1 files changed, 51 insertions, 106 deletions
diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c
index 0e630d9..a164288 100644
--- a/sys/i386/isa/clock.c
+++ b/sys/i386/isa/clock.c
@@ -72,6 +72,7 @@
#include <machine/ipl.h>
#include <machine/limits.h>
#include <machine/md_var.h>
+#include <machine/mutex.h>
#include <machine/psl.h>
#ifdef APIC_IO
#include <machine/segments.h>
@@ -139,6 +140,7 @@ int timer0_max_count;
u_int tsc_freq;
int tsc_is_broken;
int wall_cmos_clock; /* wall CMOS clock assumed if != 0 */
+struct mtx clock_lock;
static int beeping = 0;
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
@@ -198,12 +200,9 @@ SYSCTL_OPAQUE(_debug, OID_AUTO, i8254_timecounter, CTLFLAG_RD,
static void
clkintr(struct clockframe frame)
{
- int intrsave;
if (timecounter->tc_get_timecount == i8254_get_timecount) {
- intrsave = save_intr();
- disable_intr();
- CLOCK_LOCK();
+ mtx_enter(&clock_lock, MTX_SPIN);
if (i8254_ticked)
i8254_ticked = 0;
else {
@@ -211,8 +210,7 @@ clkintr(struct clockframe frame)
i8254_lastcount = 0;
}
clkintr_pending = 0;
- CLOCK_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&clock_lock, MTX_SPIN);
}
timer_func(&frame);
switch (timer0_state) {
@@ -231,17 +229,14 @@ clkintr(struct clockframe frame)
break;
case ACQUIRE_PENDING:
- intrsave = save_intr();
- disable_intr();
- CLOCK_LOCK();
+ mtx_enter(&clock_lock, MTX_SPIN);
i8254_offset = i8254_get_timecount(NULL);
i8254_lastcount = 0;
timer0_max_count = TIMER_DIV(new_rate);
outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, timer0_max_count >> 8);
- CLOCK_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&clock_lock, MTX_SPIN);
timer_func = new_function;
timer0_state = ACQUIRED;
setdelayed();
@@ -250,9 +245,7 @@ clkintr(struct clockframe frame)
case RELEASE_PENDING:
if ((timer0_prescaler_count += timer0_max_count)
>= hardclock_max_count) {
- intrsave = save_intr();
- disable_intr();
- CLOCK_LOCK();
+ mtx_enter(&clock_lock, MTX_SPIN);
i8254_offset = i8254_get_timecount(NULL);
i8254_lastcount = 0;
timer0_max_count = hardclock_max_count;
@@ -260,8 +253,7 @@ clkintr(struct clockframe frame)
TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, timer0_max_count >> 8);
- CLOCK_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&clock_lock, MTX_SPIN);
timer0_prescaler_count = 0;
timer_func = hardclock;
timer0_state = RELEASED;
@@ -408,11 +400,9 @@ DB_SHOW_COMMAND(rtc, rtc)
static int
getit(void)
{
- int high, low, intrsave;
+ int high, low;
- intrsave = save_intr();
- disable_intr();
- CLOCK_LOCK();
+ mtx_enter(&clock_lock, MTX_SPIN);
/* Select timer0 and latch counter value. */
outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
@@ -420,8 +410,7 @@ getit(void)
low = inb(TIMER_CNTR0);
high = inb(TIMER_CNTR0);
- CLOCK_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&clock_lock, MTX_SPIN);
return ((high << 8) | low);
}
@@ -527,7 +516,6 @@ sysbeepstop(void *chan)
int
sysbeep(int pitch, int period)
{
- int intrsave;
int x = splclock();
if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
@@ -536,13 +524,10 @@ sysbeep(int pitch, int period)
splx(x);
return (-1); /* XXX Should be EBUSY, but nobody cares anyway. */
}
- intrsave = save_intr();
- disable_intr();
- CLOCK_LOCK();
+ mtx_enter(&clock_lock, MTX_SPIN);
outb(TIMER_CNTR2, pitch);
outb(TIMER_CNTR2, (pitch>>8));
- CLOCK_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&clock_lock, MTX_SPIN);
if (!beeping) {
/* enable counter2 output to speaker */
outb(IO_PPI, inb(IO_PPI) | 3);
@@ -691,12 +676,9 @@ fail:
static void
set_timer_freq(u_int freq, int intr_freq)
{
- int intrsave;
int new_timer0_max_count;
- intrsave = save_intr();
- disable_intr();
- CLOCK_LOCK();
+ mtx_enter(&clock_lock, MTX_SPIN);
timer_freq = freq;
new_timer0_max_count = hardclock_max_count = TIMER_DIV(intr_freq);
if (new_timer0_max_count != timer0_max_count) {
@@ -705,8 +687,7 @@ set_timer_freq(u_int freq, int intr_freq)
outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, timer0_max_count >> 8);
}
- CLOCK_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&clock_lock, MTX_SPIN);
}
/*
@@ -720,16 +701,12 @@ set_timer_freq(u_int freq, int intr_freq)
void
i8254_restore(void)
{
- int intrsave;
- intrsave = save_intr();
- disable_intr();
- CLOCK_LOCK();
+ mtx_enter(&clock_lock, MTX_SPIN);
outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
outb(TIMER_CNTR0, timer0_max_count & 0xff);
outb(TIMER_CNTR0, timer0_max_count >> 8);
- CLOCK_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&clock_lock, MTX_SPIN);
}
/*
@@ -989,8 +966,8 @@ cpu_initclocks()
{
int diag;
#ifdef APIC_IO
- int apic_8254_trial, num_8254_ticks;
- struct intrec *clkdesc, *rtcdesc;
+ int apic_8254_trial;
+ struct intrec *clkdesc;
#endif /* APIC_IO */
if (statclock_disable) {
@@ -1023,6 +1000,11 @@ cpu_initclocks()
} else
panic("APIC_IO: Cannot route 8254 interrupt to CPU");
}
+
+ clkdesc = inthand_add("clk", apic_8254_intr, (driver_intr_t *)clkintr,
+ NULL, PI_REALTIME, INTR_FAST);
+ INTREN(1 << apic_8254_intr);
+
#else /* APIC_IO */
/*
@@ -1030,9 +1012,8 @@ cpu_initclocks()
* couldn't find anything suitable in the BSD/OS code (grog,
* 19 July 2000).
*/
- /* Setup the PIC clk handler. The APIC handler is setup later */
inthand_add("clk", 0, (driver_intr_t *)clkintr, NULL, PI_REALTIME,
- INTR_EXCL);
+ INTR_FAST);
INTREN(IRQ0);
#endif /* APIC_IO */
@@ -1042,18 +1023,8 @@ cpu_initclocks()
writertc(RTC_STATUSB, RTCSB_24HR);
/* Don't bother enabling the statistics clock. */
- if (statclock_disable) {
-#ifdef APIC_IO
- /*
- * XXX - if statclock is disabled, don't attempt the APIC
- * trial. Not sure this is sane for APIC_IO.
- */
- inthand_add("clk", apic_8254_intr, (driver_intr_t *)clkintr,
- NULL, PI_REALTIME, INTR_EXCL);
- INTREN(1 << apic_8254_intr);
-#endif /* APIC_IO */
+ if (statclock_disable)
return;
- }
diag = rtcin(RTC_DIAG);
if (diag != 0)
printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS);
@@ -1061,44 +1032,34 @@ cpu_initclocks()
#ifdef APIC_IO
if (isa_apic_irq(8) != 8)
panic("APIC RTC != 8");
+#endif /* APIC_IO */
- if (apic_8254_trial) {
- /*
- * XXX - We use fast interrupts for clk and rtc long enough to
- * perform the APIC probe and then revert to exclusive
- * interrupts.
- */
- clkdesc = inthand_add("clk", apic_8254_intr,
- (driver_intr_t *)clkintr, NULL, PI_REALTIME, INTR_FAST);
- INTREN(1 << apic_8254_intr);
+ inthand_add("rtc", 8, (driver_intr_t *)rtcintr, NULL, PI_REALTIME,
+ INTR_FAST);
- rtcdesc = inthand_add("rtc", 8, (driver_intr_t *)rtcintr, NULL,
- PI_REALTIME, INTR_FAST); /* XXX */
- INTREN(APIC_IRQ8);
- writertc(RTC_STATUSB, rtc_statusb);
+#ifdef APIC_IO
+ INTREN(APIC_IRQ8);
+#else
+ INTREN(IRQ8);
+#endif /* APIC_IO */
+
+ writertc(RTC_STATUSB, rtc_statusb);
+
+#ifdef APIC_IO
+ if (apic_8254_trial) {
printf("APIC_IO: Testing 8254 interrupt delivery\n");
while (read_intr_count(8) < 6)
; /* nothing */
- num_8254_ticks = read_intr_count(apic_8254_intr);
-
- /* disable and remove our fake handlers */
- INTRDIS(1 << apic_8254_intr);
- inthand_remove(clkdesc);
-
- writertc(RTC_STATUSA, rtc_statusa);
- writertc(RTC_STATUSB, RTCSB_24HR);
-
- INTRDIS(APIC_IRQ8);
- inthand_remove(rtcdesc);
-
- if (num_8254_ticks < 3) {
+ if (read_intr_count(apic_8254_intr) < 3) {
/*
* The MP table is broken.
* The 8254 was not connected to the specified pin
* on the IO APIC.
* Workaround: Limited variant of mixed mode.
*/
+ INTRDIS(1 << apic_8254_intr);
+ inthand_remove(clkdesc);
printf("APIC_IO: Broken MP table detected: "
"8254 is not connected to "
"IOAPIC #%d intpin %d\n",
@@ -1117,27 +1078,13 @@ cpu_initclocks()
}
apic_8254_intr = apic_irq(0, 0);
setup_8254_mixed_mode();
+ inthand_add("clk", apic_8254_intr,
+ (driver_intr_t *)clkintr, NULL,
+ PI_REALTIME, INTR_FAST);
+ INTREN(1 << apic_8254_intr);
}
}
-
- /* Finally, setup the real clock handlers */
- inthand_add("clk", apic_8254_intr, (driver_intr_t *)clkintr, NULL,
- PI_REALTIME, INTR_EXCL);
- INTREN(1 << apic_8254_intr);
-#endif
-
- inthand_add("rtc", 8, (driver_intr_t *)rtcintr, NULL, PI_REALTIME,
- INTR_EXCL);
-#ifdef APIC_IO
- INTREN(APIC_IRQ8);
-#else
- INTREN(IRQ8);
-#endif
-
- writertc(RTC_STATUSB, rtc_statusb);
-
-#ifdef APIC_IO
if (apic_int_type(0, 0) != 3 ||
int_to_apicintpin[apic_8254_intr].ioapic != 0 ||
int_to_apicintpin[apic_8254_intr].int_pin != 0)
@@ -1242,12 +1189,11 @@ static unsigned
i8254_get_timecount(struct timecounter *tc)
{
u_int count;
- int intrsave;
u_int high, low;
+ u_int eflags;
- intrsave = save_intr();
- disable_intr();
- CLOCK_LOCK();
+ eflags = read_eflags();
+ mtx_enter(&clock_lock, MTX_SPIN);
/* Select timer0 and latch counter value. */
outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
@@ -1257,7 +1203,7 @@ i8254_get_timecount(struct timecounter *tc)
count = timer0_max_count - ((high << 8) | low);
if (count < i8254_lastcount ||
(!i8254_ticked && (clkintr_pending ||
- ((count < 20 || (!(intrsave & PSL_I) && count < timer0_max_count / 2u)) &&
+ ((count < 20 || (!(eflags & PSL_I) && count < timer0_max_count / 2u)) &&
#ifdef APIC_IO
#define lapic_irr1 ((volatile u_int *)&lapic)[0x210 / 4] /* XXX XXX */
/* XXX this assumes that apic_8254_intr is < 24. */
@@ -1271,8 +1217,7 @@ i8254_get_timecount(struct timecounter *tc)
}
i8254_lastcount = count;
count += i8254_offset;
- CLOCK_UNLOCK();
- restore_intr(intrsave);
+ mtx_exit(&clock_lock, MTX_SPIN);
return (count);
}
OpenPOWER on IntegriCloud