Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 30214
b: refs/heads/master
c: 5d0cf41
h: refs/heads/master
v: v3
  • Loading branch information
john stultz authored and Linus Torvalds committed Jun 26, 2006
1 parent 85d6abc commit 5a6593c
Show file tree
Hide file tree
Showing 12 changed files with 595 additions and 7 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 61743fe445213b87fb55a389c8d073785323ca3e
refs/heads/master: 5d0cf410e94b1f1ff852c3f210d22cc6c5a27ffa
5 changes: 5 additions & 0 deletions trunk/Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ running once the system is up.
override platform specific driver.
See also Documentation/acpi-hotkey.txt.

acpi_pm_good [IA-32,X86-64]
Override the pmtimer bug detection: force the kernel
to assume that this machine's pmtimer latches its value
and always returns good values.

enable_timer_pin_1 [i386,x86-64]
Enable PIN 1 of APIC timer
Can be useful to work around chipset bugs
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/i386/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ obj-$(CONFIG_EFI) += efi.o efi_stub.o
obj-$(CONFIG_DOUBLEFAULT) += doublefault.o
obj-$(CONFIG_VM86) += vm86.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_HPET_TIMER) += hpet.o

EXTRA_AFLAGS := -traditional

Expand Down
67 changes: 67 additions & 0 deletions trunk/arch/i386/kernel/hpet.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include <linux/clocksource.h>
#include <linux/errno.h>
#include <linux/hpet.h>
#include <linux/init.h>

#include <asm/hpet.h>
#include <asm/io.h>

#define HPET_MASK 0xFFFFFFFF
#define HPET_SHIFT 22

/* FSEC = 10^-15 NSEC = 10^-9 */
#define FSEC_PER_NSEC 1000000

static void *hpet_ptr;

static cycle_t read_hpet(void)
{
return (cycle_t)readl(hpet_ptr);
}

static struct clocksource clocksource_hpet = {
.name = "hpet",
.rating = 250,
.read = read_hpet,
.mask = (cycle_t)HPET_MASK,
.mult = 0, /* set below */
.shift = HPET_SHIFT,
.is_continuous = 1,
};

static int __init init_hpet_clocksource(void)
{
unsigned long hpet_period;
void __iomem* hpet_base;
u64 tmp;

if (!hpet_address)
return -ENODEV;

/* calculate the hpet address: */
hpet_base =
(void __iomem*)ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
hpet_ptr = hpet_base + HPET_COUNTER;

/* calculate the frequency: */
hpet_period = readl(hpet_base + HPET_PERIOD);

/*
* hpet period is in femto seconds per cycle
* so we need to convert this to ns/cyc units
* aproximated by mult/2^shift
*
* fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
* fsec/cyc * 1ns/1000000fsec * 2^shift = mult
* fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
* (fsec/cyc << shift)/1000000 = mult
* (hpet_period << shift)/FSEC_PER_NSEC = mult
*/
tmp = (u64)hpet_period << HPET_SHIFT;
do_div(tmp, FSEC_PER_NSEC);
clocksource_hpet.mult = (u32)tmp;

return register_clocksource(&clocksource_hpet);
}

module_init(init_hpet_clocksource);
53 changes: 53 additions & 0 deletions trunk/arch/i386/kernel/i8253.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* i8253.c 8253/PIT functions
*
*/
#include <linux/clocksource.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
#include <linux/sysdev.h>
Expand Down Expand Up @@ -30,3 +31,55 @@ void setup_pit_timer(void)
outb(LATCH >> 8 , PIT_CH0); /* MSB */
spin_unlock_irqrestore(&i8253_lock, flags);
}

/*
* Since the PIT overflows every tick, its not very useful
* to just read by itself. So use jiffies to emulate a free
* running counter:
*/
static cycle_t pit_read(void)
{
unsigned long flags;
int count;
u64 jifs;

spin_lock_irqsave(&i8253_lock, flags);
outb_p(0x00, PIT_MODE); /* latch the count ASAP */
count = inb_p(PIT_CH0); /* read the latched count */
count |= inb_p(PIT_CH0) << 8;

/* VIA686a test code... reset the latch if count > max + 1 */
if (count > LATCH) {
outb_p(0x34, PIT_MODE);
outb_p(LATCH & 0xff, PIT_CH0);
outb(LATCH >> 8, PIT_CH0);
count = LATCH - 1;
}
spin_unlock_irqrestore(&i8253_lock, flags);

jifs = jiffies_64;

jifs -= INITIAL_JIFFIES;
count = (LATCH-1) - count;

return (cycle_t)(jifs * LATCH) + count;
}

static struct clocksource clocksource_pit = {
.name = "pit",
.rating = 110,
.read = pit_read,
.mask = (cycle_t)-1,
.mult = 0,
.shift = 20,
};

static int __init init_pit_clocksource(void)
{
if (num_possible_cpus() > 4) /* PIT does not scale! */
return 0;

clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20);
return register_clocksource(&clocksource_pit);
}
module_init(init_pit_clocksource);
3 changes: 0 additions & 3 deletions trunk/arch/i386/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,6 @@ extern unsigned long wall_jiffies;
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);

/* XXX - necessary to keep things compiling. to be removed later */
u32 pmtmr_ioport;

/*
* This is a special lock that is owned by the CPU and holds the index
* register we are working with. It is required for NMI access to the
Expand Down
161 changes: 161 additions & 0 deletions trunk/arch/i386/kernel/tsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
* See comments there for proper credits.
*/

#include <linux/clocksource.h>
#include <linux/workqueue.h>
#include <linux/cpufreq.h>
#include <linux/jiffies.h>
#include <linux/init.h>
#include <linux/dmi.h>

#include <asm/delay.h>
#include <asm/tsc.h>
#include <asm/delay.h>
#include <asm/io.h>
Expand Down Expand Up @@ -315,3 +318,161 @@ static int __init cpufreq_tsc(void)
core_initcall(cpufreq_tsc);

#endif

/* clock source code */

static unsigned long current_tsc_khz = 0;
static int tsc_update_callback(void);

static cycle_t read_tsc(void)
{
cycle_t ret;

rdtscll(ret);

return ret;
}

static struct clocksource clocksource_tsc = {
.name = "tsc",
.rating = 300,
.read = read_tsc,
.mask = (cycle_t)-1,
.mult = 0, /* to be set */
.shift = 22,
.update_callback = tsc_update_callback,
.is_continuous = 1,
};

static int tsc_update_callback(void)
{
int change = 0;

/* check to see if we should switch to the safe clocksource: */
if (clocksource_tsc.rating != 50 && check_tsc_unstable()) {
clocksource_tsc.rating = 50;
reselect_clocksource();
change = 1;
}

/* only update if tsc_khz has changed: */
if (current_tsc_khz != tsc_khz) {
current_tsc_khz = tsc_khz;
clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz,
clocksource_tsc.shift);
change = 1;
}

return change;
}

static int __init dmi_mark_tsc_unstable(struct dmi_system_id *d)
{
printk(KERN_NOTICE "%s detected: marking TSC unstable.\n",
d->ident);
mark_tsc_unstable();
return 0;
}

/* List of systems that have known TSC problems */
static struct dmi_system_id __initdata bad_tsc_dmi_table[] = {
{
.callback = dmi_mark_tsc_unstable,
.ident = "IBM Thinkpad 380XD",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
DMI_MATCH(DMI_BOARD_NAME, "2635FA0"),
},
},
{}
};

#define TSC_FREQ_CHECK_INTERVAL (10*MSEC_PER_SEC) /* 10sec in MS */
static struct timer_list verify_tsc_freq_timer;

/* XXX - Probably should add locking */
static void verify_tsc_freq(unsigned long unused)
{
static u64 last_tsc;
static unsigned long last_jiffies;

u64 now_tsc, interval_tsc;
unsigned long now_jiffies, interval_jiffies;


if (check_tsc_unstable())
return;

rdtscll(now_tsc);
now_jiffies = jiffies;

if (!last_jiffies) {
goto out;
}

interval_jiffies = now_jiffies - last_jiffies;
interval_tsc = now_tsc - last_tsc;
interval_tsc *= HZ;
do_div(interval_tsc, cpu_khz*1000);

if (interval_tsc < (interval_jiffies * 3 / 4)) {
printk("TSC appears to be running slowly. "
"Marking it as unstable\n");
mark_tsc_unstable();
return;
}

out:
last_tsc = now_tsc;
last_jiffies = now_jiffies;
/* set us up to go off on the next interval: */
mod_timer(&verify_tsc_freq_timer,
jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL));
}

/*
* Make an educated guess if the TSC is trustworthy and synchronized
* over all CPUs.
*/
static __init int unsynchronized_tsc(void)
{
/*
* Intel systems are normally all synchronized.
* Exceptions must mark TSC as unstable:
*/
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
return 0;

/* assume multi socket systems are not synchronized: */
return num_possible_cpus() > 1;
}

static int __init init_tsc_clocksource(void)
{

if (cpu_has_tsc && tsc_khz && !tsc_disable) {
/* check blacklist */
dmi_check_system(bad_tsc_dmi_table);

if (unsynchronized_tsc()) /* mark unstable if unsynced */
mark_tsc_unstable();
current_tsc_khz = tsc_khz;
clocksource_tsc.mult = clocksource_khz2mult(current_tsc_khz,
clocksource_tsc.shift);
/* lower the rating if we already know its unstable: */
if (check_tsc_unstable())
clocksource_tsc.rating = 50;

init_timer(&verify_tsc_freq_timer);
verify_tsc_freq_timer.function = verify_tsc_freq;
verify_tsc_freq_timer.expires =
jiffies + msecs_to_jiffies(TSC_FREQ_CHECK_INTERVAL);
add_timer(&verify_tsc_freq_timer);

return register_clocksource(&clocksource_tsc);
}

return 0;
}

module_init(init_tsc_clocksource);
1 change: 1 addition & 0 deletions trunk/drivers/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,5 @@ obj-$(CONFIG_SGI_SN) += sn/
obj-y += firmware/
obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
obj-$(CONFIG_GENERIC_TIME) += clocksource/
obj-$(CONFIG_DMA_ENGINE) += dma/
2 changes: 2 additions & 0 deletions trunk/drivers/clocksource/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o
obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
Loading

0 comments on commit 5a6593c

Please sign in to comment.