From 377692412f4e352c7c8457a05f8795a3f017cf61 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Fri, 30 Aug 2002 01:56:22 -0700 Subject: ACPI trivial cleanups (Kochi Takayoshi) --- include/linux/acpi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 9c619036dfb6..1bdcda4d36c8 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -354,11 +354,11 @@ void acpi_numa_arch_fixup(void); extern int acpi_mp_config; -#else /*!CONFIG_ACPI_BOOT*/ +#else #define acpi_mp_config 0 -#endif /*CONFIG_ACPI_BOOT*/ +#endif #ifdef CONFIG_ACPI_PCI -- cgit v1.2.3 From d9a2636316ef9695df0e7089b4f79f7a2661477c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 9 Sep 2002 00:34:37 -0700 Subject: PCI: hotplug core cleanup to get pci hotplug working again - removed pci_announce_device_to_drivers() prototype as the function is long gone - always call /sbin/hotplug when pci devices are added to the system if so configured (this includes during the system bring up.) --- drivers/pci/Makefile | 4 +--- drivers/pci/hotplug.c | 22 ++++++++++++++-------- drivers/pci/probe.c | 6 +++--- drivers/pci/proc.c | 9 +++++++++ include/linux/pci.h | 1 - 5 files changed, 27 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 579edc49e82a..14b5dcb183bf 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -6,10 +6,8 @@ export-objs := access.o hotplug.o pci-driver.o pci.o pool.o \ probe.o proc.o search.o compat.o obj-y += access.o probe.o pci.o pool.o quirks.o \ - compat.o names.o pci-driver.o search.o + compat.o names.o pci-driver.o search.o hotplug.o obj-$(CONFIG_PM) += power.o -obj-$(CONFIG_HOTPLUG) += hotplug.o - obj-$(CONFIG_PROC_FS) += proc.o ifndef CONFIG_SPARC64 diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 63dc49410dbc..c493d2f0216f 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -7,8 +7,8 @@ #define TRUE (!FALSE) #endif -static void -run_sbin_hotplug(struct pci_dev *pdev, int insert) +#ifdef CONFIG_HOTPLUG +static void run_sbin_hotplug(struct pci_dev *pdev, int insert) { int i; char *argv[3], *envp[8]; @@ -45,13 +45,18 @@ run_sbin_hotplug(struct pci_dev *pdev, int insert) call_usermodehelper (argv [0], argv, envp); } +#else +static void run_sbin_hotplug(struct pci_dev *pdev, int insert) { } +#endif /** - * pci_insert_device - insert a hotplug device + * pci_insert_device - insert a pci device * @dev: the device to insert * @bus: where to insert it * - * Add a new device to the device lists and notify userspace (/sbin/hotplug). + * Link the device to both the global PCI device chain and the + * per-bus list of devices, add the /proc entry, and notify + * userspace (/sbin/hotplug). */ void pci_insert_device(struct pci_dev *dev, struct pci_bus *bus) @@ -78,11 +83,11 @@ pci_free_resources(struct pci_dev *dev) } /** - * pci_remove_device - remove a hotplug device + * pci_remove_device - remove a pci device * @dev: the device to remove * - * Delete the device structure from the device lists and - * notify userspace (/sbin/hotplug). + * Delete the device structure from the device lists, + * remove the /proc entry, and notify userspace (/sbin/hotplug). */ void pci_remove_device(struct pci_dev *dev) @@ -94,10 +99,11 @@ pci_remove_device(struct pci_dev *dev) #ifdef CONFIG_PROC_FS pci_proc_detach_device(dev); #endif - /* notify userspace of hotplug device removal */ run_sbin_hotplug(dev, FALSE); } +#ifdef CONFIG_HOTPLUG EXPORT_SYMBOL(pci_insert_device); EXPORT_SYMBOL(pci_remove_device); +#endif diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 6460e5f08eda..ffc65af0c438 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -479,10 +479,10 @@ struct pci_dev * __devinit pci_scan_slot(struct pci_dev *temp) /* * Link the device to both the global PCI device chain and - * the per-bus list of devices. + * the per-bus list of devices and call /sbin/hotplug if we + * should. */ - list_add_tail(&dev->global_list, &pci_devices); - list_add_tail(&dev->bus_list, &bus->devices); + pci_insert_device (dev, bus); /* Fix up broken headers */ pci_fixup_device(PCI_FIXUP_HEADER, dev); diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 67c7e1feb732..582fac9f16f7 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -18,6 +18,8 @@ #define PCI_CFG_SPACE_SIZE 256 +static int proc_initialized; /* = 0 */ + static loff_t proc_bus_pci_lseek(struct file *file, loff_t off, int whence) { @@ -410,6 +412,9 @@ int pci_proc_attach_device(struct pci_dev *dev) struct proc_dir_entry *de, *e; char name[16]; + if (!proc_initialized) + return -EACCES; + if (!(de = bus->procdir)) { sprintf(name, "%02x", bus->number); de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir); @@ -446,6 +451,9 @@ int pci_proc_attach_bus(struct pci_bus* bus) { struct proc_dir_entry *de = bus->procdir; + if (!proc_initialized) + return -EACCES; + if (!de) { char name[16]; sprintf(name, "%02x", bus->number); @@ -595,6 +603,7 @@ static int __init pci_proc_init(void) entry = create_proc_entry("devices", 0, proc_bus_pci_dir); if (entry) entry->proc_fops = &proc_bus_pci_dev_operations; + proc_initialized = 1; pci_for_each_dev(dev) { pci_proc_attach_device(dev); } diff --git a/include/linux/pci.h b/include/linux/pci.h index b82ec8e41174..79d909a8643a 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -634,7 +634,6 @@ void pci_insert_device(struct pci_dev *, struct pci_bus *); void pci_remove_device(struct pci_dev *); struct pci_driver *pci_dev_driver(const struct pci_dev *); const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev); -void pci_announce_device_to_drivers(struct pci_dev *); unsigned int pci_do_scan_bus(struct pci_bus *bus); struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); -- cgit v1.2.3 From b6a3d01fdefc8455289b963999a2a21c9e28c2ec Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 9 Sep 2002 02:09:42 -0700 Subject: Reorganize the mtrr init sequence a bit. All mtrr init now happens during the initcall sequence, after all CPUs have been brought up. mtrr_init() calls a static init_other_cpus(), which fires off a function on all other cpus to replicate the state across all of them. arch/i386/kernel/smpboot.c::smp_callin() had the following: #ifdef CONFIG_MTRR /* * Must be done before calibration delay is computed */ mtrr_init_secondary_cpu (); #endif I couldn't figure this one out. The P4 manual says nothing about this, nor find any other documentation about it. The P4 manual says only that state must be synchronized across all CPUs, which it is. And, it happens before anything else is executed on the other CPUs, and before any devices or drivers have been brought up. The cyrix mtrr code was also updated to handle this style of SMP initialization. --- arch/i386/kernel/cpu/mtrr/cyrix.c | 117 +++++++--------- arch/i386/kernel/cpu/mtrr/generic.c | 263 ++++++++++++++++++++++++++++++++---- arch/i386/kernel/cpu/mtrr/main.c | 47 +++++-- arch/i386/kernel/cpu/mtrr/mtrr.h | 3 +- arch/i386/kernel/cpu/mtrr/state.c | 260 ----------------------------------- arch/i386/kernel/smpboot.c | 7 - include/asm-i386/mtrr.h | 7 - init/main.c | 13 -- 8 files changed, 321 insertions(+), 396 deletions(-) (limited to 'include') diff --git a/arch/i386/kernel/cpu/mtrr/cyrix.c b/arch/i386/kernel/cpu/mtrr/cyrix.c index ace423c0a83c..30e1d3aac5bc 100644 --- a/arch/i386/kernel/cpu/mtrr/cyrix.c +++ b/arch/i386/kernel/cpu/mtrr/cyrix.c @@ -110,12 +110,54 @@ cyrix_get_free_region(unsigned long base, unsigned long size) return -ENOSPC; } +static u32 cr4 = 0; +static u32 ccr3; + +static void prepare_set(void) +{ + u32 cr0; + + /* Save value of CR4 and clear Page Global Enable (bit 7) */ + if ( cpu_has_pge ) { + cr4 = read_cr4(); + write_cr4(cr4 & (unsigned char) ~(1 << 7)); + } + + /* Disable and flush caches. Note that wbinvd flushes the TLBs as + a side-effect */ + cr0 = read_cr0() | 0x40000000; + wbinvd(); + write_cr0(cr0); + wbinvd(); + + /* Cyrix ARRs - everything else were excluded at the top */ + ccr3 = getCx86(CX86_CCR3); + + /* Cyrix ARRs - everything else were excluded at the top */ + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); + +} + +static void post_set(void) +{ + /* Flush caches and TLBs */ + wbinvd(); + + /* Cyrix ARRs - everything else was excluded at the top */ + setCx86(CX86_CCR3, ccr3); + + /* Enable caches */ + write_cr0(read_cr0() & 0xbfffffff); + + /* Restore value of CR4 */ + if ( cpu_has_pge ) + write_cr4(cr4); +} + static void cyrix_set_arr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type) { unsigned char arr, arr_type, arr_size; - u32 cr0, ccr3; - u32 cr4 = 0; arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */ @@ -158,24 +200,7 @@ static void cyrix_set_arr(unsigned int reg, unsigned long base, } } - /* Save value of CR4 and clear Page Global Enable (bit 7) */ - if ( cpu_has_pge ) { - cr4 = read_cr4(); - write_cr4(cr4 & (unsigned char) ~(1 << 7)); - } - - /* Disable and flush caches. Note that wbinvd flushes the TLBs as - a side-effect */ - cr0 = read_cr0() | 0x40000000; - wbinvd(); - write_cr0(cr0); - wbinvd(); - - /* Cyrix ARRs - everything else were excluded at the top */ - ccr3 = getCx86(CX86_CCR3); - - /* Cyrix ARRs - everything else were excluded at the top */ - setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); + prepare_set(); base <<= PAGE_SHIFT; setCx86(arr, ((unsigned char *) &base)[3]); @@ -183,18 +208,7 @@ static void cyrix_set_arr(unsigned int reg, unsigned long base, setCx86(arr + 2, (((unsigned char *) &base)[1]) | arr_size); setCx86(CX86_RCR_BASE + reg, arr_type); - /* Flush caches and TLBs */ - wbinvd(); - - /* Cyrix ARRs - everything else was excluded at the top */ - setCx86(CX86_CCR3, ccr3); - - /* Enable caches */ - write_cr0(read_cr0() & 0xbfffffff); - - /* Restore value of CR4 */ - if ( cpu_has_pge ) - write_cr4(cr4); + post_set(); } typedef struct { @@ -210,31 +224,11 @@ arr_state_t arr_state[8] __initdata = { unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 }; -static void __init -cyrix_arr_init_secondary(void) +static void cyrix_set_all(void) { int i; - u32 cr0, ccr3, cr4 = 0; - - /* flush cache and enable MAPEN */ - /* Save value of CR4 and clear Page Global Enable (bit 7) */ - if ( cpu_has_pge ) { - cr4 = read_cr4(); - write_cr4(cr4 & (unsigned char) ~(1 << 7)); - } - /* Disable and flush caches. Note that wbinvd flushes the TLBs as - a side-effect */ - cr0 = read_cr0() | 0x40000000; - wbinvd(); - write_cr0(cr0); - wbinvd(); - - /* Cyrix ARRs - everything else were excluded at the top */ - ccr3 = getCx86(CX86_CCR3); - - /* Cyrix ARRs - everything else were excluded at the top */ - setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); + prepare_set(); /* the CCRs are not contiguous */ for (i = 0; i < 4; i++) @@ -245,18 +239,7 @@ cyrix_arr_init_secondary(void) cyrix_set_arr(i, arr_state[i].base, arr_state[i].size, arr_state[i].type); - /* Flush caches and TLBs */ - wbinvd(); - - /* Cyrix ARRs - everything else was excluded at the top */ - setCx86(CX86_CCR3, ccr3); - - /* Enable caches */ - write_cr0(read_cr0() & 0xbfffffff); - - /* Restore value of CR4 */ - if ( cpu_has_pge ) - write_cr4(cr4); + post_set(); } /* @@ -361,7 +344,7 @@ cyrix_arr_init(void) static struct mtrr_ops cyrix_mtrr_ops = { .vendor = X86_VENDOR_CYRIX, .init = cyrix_arr_init, - .init_secondary = cyrix_arr_init_secondary, + .set_all = cyrix_set_all, .set = cyrix_set_arr, .get = cyrix_get_arr, .get_free_region = cyrix_get_free_region, diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c index e33831835119..eeefde58dcc1 100644 --- a/arch/i386/kernel/cpu/mtrr/generic.c +++ b/arch/i386/kernel/cpu/mtrr/generic.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -6,6 +8,90 @@ #include #include "mtrr.h" +struct mtrr_state { + struct mtrr_var_range *var_ranges; + mtrr_type fixed_ranges[NUM_FIXED_RANGES]; + unsigned char enabled; + mtrr_type def_type; +}; + +static unsigned long smp_changes_mask __initdata = 0; +struct mtrr_state mtrr_state = {}; + + +/* Get the MSR pair relating to a var range */ +static void __init +get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr) +{ + rdmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); + rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); +} + +static void __init +get_fixed_ranges(mtrr_type * frs) +{ + unsigned long *p = (unsigned long *) frs; + int i; + + rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]); + + for (i = 0; i < 2; i++) + rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2], p[3 + i * 2]); + for (i = 0; i < 8; i++) + rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]); +} + +/* Grab all of the MTRR state for this CPU into *state */ +void get_mtrr_state(void) +{ + unsigned int i; + struct mtrr_var_range *vrs; + unsigned long lo, dummy; + + if (!mtrr_state.var_ranges) { + mtrr_state.var_ranges = kmalloc(num_var_ranges * sizeof (struct mtrr_var_range), + GFP_KERNEL); + if (!mtrr_state.var_ranges) + return; + } + vrs = mtrr_state.var_ranges; + + for (i = 0; i < num_var_ranges; i++) + get_mtrr_var_range(i, &vrs[i]); + get_fixed_ranges(mtrr_state.fixed_ranges); + + rdmsr(MTRRdefType_MSR, lo, dummy); + mtrr_state.def_type = (lo & 0xff); + mtrr_state.enabled = (lo & 0xc00) >> 10; +} + +/* Free resources associated with a struct mtrr_state */ +void __init finalize_mtrr_state(void) +{ + if (mtrr_state.var_ranges) + kfree(mtrr_state.var_ranges); + mtrr_state.var_ranges = NULL; +} + +/* Some BIOS's are fucked and don't set all MTRRs the same! */ +void __init mtrr_state_warn(void) +{ + unsigned long mask = smp_changes_mask; + + if (!mask) + return; + if (mask & MTRR_CHANGE_MASK_FIXED) + printk + ("mtrr: your CPUs had inconsistent fixed MTRR settings\n"); + if (mask & MTRR_CHANGE_MASK_VARIABLE) + printk + ("mtrr: your CPUs had inconsistent variable MTRR settings\n"); + if (mask & MTRR_CHANGE_MASK_DEFTYPE) + printk + ("mtrr: your CPUs had inconsistent MTRRdefType settings\n"); + printk("mtrr: probably your BIOS does not setup all CPUs\n"); +} + int generic_get_free_region(unsigned long base, unsigned long size) /* [SUMMARY] Get a free MTRR. @@ -55,23 +141,104 @@ void generic_get_mtrr(unsigned int reg, unsigned long *base, *type = base_lo & 0xff; } -void generic_set_mtrr(unsigned int reg, unsigned long base, - unsigned long size, mtrr_type type) -/* [SUMMARY] Set variable MTRR register on the local CPU. - The register to set. - The base address of the region. - The size of the region. If this is 0 the region is disabled. - The type of the region. - If TRUE, do the change safely. If FALSE, safety measures should - be done externally. - [RETURNS] Nothing. +static int __init set_fixed_ranges(mtrr_type * frs) +{ + unsigned long *p = (unsigned long *) frs; + int changed = FALSE; + int i; + unsigned long lo, hi; + + rdmsr(MTRRfix64K_00000_MSR, lo, hi); + if (p[0] != lo || p[1] != hi) { + wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]); + changed = TRUE; + } + + for (i = 0; i < 2; i++) { + rdmsr(MTRRfix16K_80000_MSR + i, lo, hi); + if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) { + wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2], + p[3 + i * 2]); + changed = TRUE; + } + } + + for (i = 0; i < 8; i++) { + rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi); + if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) { + wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], + p[7 + i * 2]); + changed = TRUE; + } + } + return changed; +} + +/* Set the MSR pair relating to a var range. Returns TRUE if + changes are made */ +static int __init set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr) +{ + unsigned int lo, hi; + int changed = FALSE; + + rdmsr(MTRRphysBase_MSR(index), lo, hi); + if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) + || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) { + wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); + changed = TRUE; + } + + rdmsr(MTRRphysMask_MSR(index), lo, hi); + + if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL) + || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) { + wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); + changed = TRUE; + } + return changed; +} + +static unsigned long set_mtrr_state(u32 deftype_lo, u32 deftype_hi) +/* [SUMMARY] Set the MTRR state for this CPU. + The MTRR state information to read. + Some relevant CPU context. + [NOTE] The CPU must already be in a safe state for MTRR changes. + [RETURNS] 0 if no changes made, else a mask indication what was changed. */ { - u32 cr0, cr4 = 0; - u32 deftype_lo, deftype_hi; - static spinlock_t set_atomicity_lock = SPIN_LOCK_UNLOCKED; + unsigned int i; + unsigned long change_mask = 0; + + for (i = 0; i < num_var_ranges; i++) + if (set_mtrr_var_ranges(i, &mtrr_state.var_ranges[i])) + change_mask |= MTRR_CHANGE_MASK_VARIABLE; + + if (set_fixed_ranges(mtrr_state.fixed_ranges)) + change_mask |= MTRR_CHANGE_MASK_FIXED; + + /* Set_mtrr_restore restores the old value of MTRRdefType, + so to set it we fiddle with the saved value */ + if ((deftype_lo & 0xff) != mtrr_state.def_type + || ((deftype_lo & 0xc00) >> 10) != mtrr_state.enabled) { + deftype_lo |= (mtrr_state.def_type | mtrr_state.enabled << 10); + change_mask |= MTRR_CHANGE_MASK_DEFTYPE; + } + + return change_mask; +} + + +static u32 cr4 = 0; +static u32 deftype_lo, deftype_hi; + +static void prepare_set(void) +{ + u32 cr0; + + /* Note that this is not ideal, since the cache is only flushed/disabled + for this CPU while the MTRRs are changed, but changing this requires + more invasive changes to the way the kernel boots */ - spin_lock(&set_atomicity_lock); /* Save value of CR4 and clear Page Global Enable (bit 7) */ if ( cpu_has_pge ) { cr4 = read_cr4(); @@ -90,18 +257,10 @@ void generic_set_mtrr(unsigned int reg, unsigned long base, /* Disable MTRRs, and set the default type to uncached */ wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi); +} - if (size == 0) { - /* The invalid bit is kept in the mask, so we simply clear the - relevant mask register to disable a range. */ - wrmsr(MTRRphysMask_MSR(reg), 0, 0); - } else { - wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type, - (base & size_and_mask) >> (32 - PAGE_SHIFT)); - wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800, - (-size & size_and_mask) >> (32 - PAGE_SHIFT)); - } - +static void post_set(void) +{ /* Flush caches and TLBs */ wbinvd(); @@ -114,7 +273,57 @@ void generic_set_mtrr(unsigned int reg, unsigned long base, /* Restore value of CR4 */ if ( cpu_has_pge ) write_cr4(cr4); - spin_unlock(&set_atomicity_lock); + +} + +static void generic_set_all(void) +{ + unsigned long mask, count; + + prepare_set(); + + /* Actually set the state */ + mask = set_mtrr_state(deftype_lo,deftype_hi); + + post_set(); + + /* Use the atomic bitops to update the global mask */ + for (count = 0; count < sizeof mask * 8; ++count) { + if (mask & 0x01) + set_bit(count, &smp_changes_mask); + mask >>= 1; + } + +} + +static void generic_set_mtrr(unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type) +/* [SUMMARY] Set variable MTRR register on the local CPU. + The register to set. + The base address of the region. + The size of the region. If this is 0 the region is disabled. + The type of the region. + If TRUE, do the change safely. If FALSE, safety measures should + be done externally. + [RETURNS] Nothing. +*/ +{ + prepare_set(); + + printk("MTRR: setting reg %x\n",reg); + + if (size == 0) { + /* The invalid bit is kept in the mask, so we simply clear the + relevant mask register to disable a range. */ + wrmsr(MTRRphysMask_MSR(reg), 0, 0); + } else { + wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type, + (base & size_and_mask) >> (32 - PAGE_SHIFT)); + wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800, + (-size & size_and_mask) >> (32 - PAGE_SHIFT)); + } + + post_set(); } int generic_validate_add_page(unsigned long base, unsigned long size, unsigned int type) @@ -178,7 +387,7 @@ int positive_have_wrcomb(void) */ struct mtrr_ops generic_mtrr_ops = { .use_intel_if = 1, - .init_secondary = generic_init_secondary, + .set_all = generic_set_all, .get = generic_get_mtrr, .get_free_region = generic_get_free_region, .set = generic_set_mtrr, diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c index 8f0d8a3c8bd7..aa091d2c5db7 100644 --- a/arch/i386/kernel/cpu/mtrr/main.c +++ b/arch/i386/kernel/cpu/mtrr/main.c @@ -163,8 +163,11 @@ static void ipi_handler(void *info) } /* The master has cleared me to execute */ - mtrr_if->set(data->smp_reg, data->smp_base, - data->smp_size, data->smp_type); + if (data->smp_reg != ~0UL) + mtrr_if->set(data->smp_reg, data->smp_base, + data->smp_size, data->smp_type); + else + mtrr_if->set_all(); atomic_dec(&data->count); while(atomic_read(&data->gate)) { @@ -243,7 +246,15 @@ static void set_mtrr(unsigned int reg, unsigned long base, atomic_set(&data.gate,1); /* do our MTRR business */ - mtrr_if->set(reg,base,size,type); + + /* HACK! + * We use this same function to initialize the mtrrs on boot. + * The state of the boot cpu's mtrrs has been saved, and we want + * to replicate across all the APs. + * If we're doing that @reg is set to something special... + */ + if (reg != ~0UL) + mtrr_if->set(reg,base,size,type); /* wait for the others */ while(atomic_read(&data.count)) { @@ -530,6 +541,20 @@ static void __init init_ifs(void) centaur_init_mtrr(); } +static void init_other_cpus(void) +{ + if (use_intel()) + get_mtrr_state(); + + /* bring up the other processors */ + set_mtrr(~0UL,0,0,0); + + if (use_intel()) { + finalize_mtrr_state(); + mtrr_state_warn(); + } +} + /** * mtrr_init - initialie mtrrs on the boot CPU * @@ -537,7 +562,7 @@ static void __init init_ifs(void) * initialized (i.e. before smp_init()). * */ -int __init mtrr_init(void) +static int __init mtrr_init(void) { init_ifs(); @@ -608,21 +633,15 @@ int __init mtrr_init(void) break; } } + printk("mtrr: v%s\n",MTRR_VERSION); + if (mtrr_if) { set_num_var_ranges(); - if (use_intel()) { - /* Only for Intel MTRRs */ - get_mtrr_state(); - } init_table(); + init_other_cpus(); } -#if 0 - printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n" - "mtrr: detected mtrr type: %s\n", - MTRR_VERSION, mtrr_if_name[mtrr_if]); -#endif return mtrr_if ? -ENXIO : 0; } -//subsys_initcall(mtrr_init); +core_initcall(mtrr_init); diff --git a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h index 5c1aa8ab552e..363a5b14acdc 100644 --- a/arch/i386/kernel/cpu/mtrr/mtrr.h +++ b/arch/i386/kernel/cpu/mtrr/mtrr.h @@ -38,9 +38,10 @@ struct mtrr_ops { u32 vendor; u32 use_intel_if; void (*init)(void); - void (*init_secondary)(void); void (*set)(unsigned int reg, unsigned long base, unsigned long size, mtrr_type type); + void (*set_all)(void); + void (*get)(unsigned int reg, unsigned long *base, unsigned long *size, mtrr_type * type); int (*get_free_region) (unsigned long base, unsigned long size); diff --git a/arch/i386/kernel/cpu/mtrr/state.c b/arch/i386/kernel/cpu/mtrr/state.c index a2eef500f7bc..3d32fbf35284 100644 --- a/arch/i386/kernel/cpu/mtrr/state.c +++ b/arch/i386/kernel/cpu/mtrr/state.c @@ -1,180 +1,10 @@ #include -#include #include #include #include #include #include "mtrr.h" -struct mtrr_state { - struct mtrr_var_range *var_ranges; - mtrr_type fixed_ranges[NUM_FIXED_RANGES]; - unsigned char enabled; - mtrr_type def_type; -}; - -static unsigned long smp_changes_mask __initdata = 0; -struct mtrr_state mtrr_state = {}; - -static int __init set_fixed_ranges(mtrr_type * frs) -{ - unsigned long *p = (unsigned long *) frs; - int changed = FALSE; - int i; - unsigned long lo, hi; - - rdmsr(MTRRfix64K_00000_MSR, lo, hi); - if (p[0] != lo || p[1] != hi) { - wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]); - changed = TRUE; - } - - for (i = 0; i < 2; i++) { - rdmsr(MTRRfix16K_80000_MSR + i, lo, hi); - if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) { - wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2], - p[3 + i * 2]); - changed = TRUE; - } - } - - for (i = 0; i < 8; i++) { - rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi); - if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) { - wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], - p[7 + i * 2]); - changed = TRUE; - } - } - return changed; -} - -/* Set the MSR pair relating to a var range. Returns TRUE if - changes are made */ -static int __init set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr) -{ - unsigned int lo, hi; - int changed = FALSE; - - rdmsr(MTRRphysBase_MSR(index), lo, hi); - if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) - || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) { - wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); - changed = TRUE; - } - - rdmsr(MTRRphysMask_MSR(index), lo, hi); - - if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL) - || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) { - wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); - changed = TRUE; - } - return changed; -} - -static unsigned long set_mtrr_state(u32 deftype_lo, u32 deftype_hi) -/* [SUMMARY] Set the MTRR state for this CPU. - The MTRR state information to read. - Some relevant CPU context. - [NOTE] The CPU must already be in a safe state for MTRR changes. - [RETURNS] 0 if no changes made, else a mask indication what was changed. -*/ -{ - unsigned int i; - unsigned long change_mask = 0; - - for (i = 0; i < num_var_ranges; i++) - if (set_mtrr_var_ranges(i, &mtrr_state.var_ranges[i])) - change_mask |= MTRR_CHANGE_MASK_VARIABLE; - - if (set_fixed_ranges(mtrr_state.fixed_ranges)) - change_mask |= MTRR_CHANGE_MASK_FIXED; - - /* Set_mtrr_restore restores the old value of MTRRdefType, - so to set it we fiddle with the saved value */ - if ((deftype_lo & 0xff) != mtrr_state.def_type - || ((deftype_lo & 0xc00) >> 10) != mtrr_state.enabled) { - deftype_lo |= (mtrr_state.def_type | mtrr_state.enabled << 10); - change_mask |= MTRR_CHANGE_MASK_DEFTYPE; - } - - return change_mask; -} - - -/* Some BIOS's are fucked and don't set all MTRRs the same! */ -static void __init mtrr_state_warn(void) -{ - unsigned long mask = smp_changes_mask; - if (!mask) - return; - if (mask & MTRR_CHANGE_MASK_FIXED) - printk - ("mtrr: your CPUs had inconsistent fixed MTRR settings\n"); - if (mask & MTRR_CHANGE_MASK_VARIABLE) - printk - ("mtrr: your CPUs had inconsistent variable MTRR settings\n"); - if (mask & MTRR_CHANGE_MASK_DEFTYPE) - printk - ("mtrr: your CPUs had inconsistent MTRRdefType settings\n"); - printk("mtrr: probably your BIOS does not setup all CPUs\n"); -} - -/* Free resources associated with a struct mtrr_state */ -static void __init finalize_mtrr_state(void) -{ - if (mtrr_state.var_ranges) - kfree(mtrr_state.var_ranges); - mtrr_state.var_ranges = NULL; -} - -/* Get the MSR pair relating to a var range */ -static void __init -get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr) -{ - rdmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); - rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); -} - -static void __init -get_fixed_ranges(mtrr_type * frs) -{ - unsigned long *p = (unsigned long *) frs; - int i; - - rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]); - - for (i = 0; i < 2; i++) - rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2], p[3 + i * 2]); - for (i = 0; i < 8; i++) - rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]); -} - -/* Grab all of the MTRR state for this CPU into *state */ -void get_mtrr_state(void) -{ - unsigned int i; - struct mtrr_var_range *vrs; - unsigned long lo, dummy; - - if (!mtrr_state.var_ranges) { - mtrr_state.var_ranges = kmalloc(num_var_ranges * sizeof (struct mtrr_var_range), - GFP_KERNEL); - if (!mtrr_state.var_ranges) - return; - } - vrs = mtrr_state.var_ranges; - - for (i = 0; i < num_var_ranges; i++) - get_mtrr_var_range(i, &vrs[i]); - get_fixed_ranges(mtrr_state.fixed_ranges); - - rdmsr(MTRRdefType_MSR, lo, dummy); - mtrr_state.def_type = (lo & 0xff); - mtrr_state.enabled = (lo & 0xc00) >> 10; -} - /* Put the processor into a state where MTRRs can be safely set */ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt) @@ -246,93 +76,3 @@ void set_mtrr_done(struct set_mtrr_context *ctxt) local_irq_restore(ctxt->flags); } -void __init generic_init_secondary(void) -{ - u32 cr0, cr4 = 0; - u32 deftype_lo, deftype_hi; - unsigned long mask, count; - - /* Note that this is not ideal, since the cache is only flushed/disabled - for this CPU while the MTRRs are changed, but changing this requires - more invasive changes to the way the kernel boots */ - - /* Save value of CR4 and clear Page Global Enable (bit 7) */ - if ( cpu_has_pge ) { - cr4 = read_cr4(); - write_cr4(cr4 & (unsigned char) ~(1 << 7)); - } - - /* Disable and flush caches. Note that wbinvd flushes the TLBs as - a side-effect */ - cr0 = read_cr0() | 0x40000000; - wbinvd(); - write_cr0(cr0); - wbinvd(); - - /* Save MTRR state */ - rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi); - - /* Disable MTRRs, and set the default type to uncached */ - wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi); - - /* Actually set the state */ - mask = set_mtrr_state(deftype_lo,deftype_hi); - - /* Flush caches and TLBs */ - wbinvd(); - - /* Intel (P6) standard MTRRs */ - wrmsr(MTRRdefType_MSR, deftype_lo, deftype_hi); - - /* Enable caches */ - write_cr0(read_cr0() & 0xbfffffff); - - /* Restore value of CR4 */ - if ( cpu_has_pge ) - write_cr4(cr4); - - /* Use the atomic bitops to update the global mask */ - for (count = 0; count < sizeof mask * 8; ++count) { - if (mask & 0x01) - set_bit(count, &smp_changes_mask); - mask >>= 1; - } -} - -/** - * mtrr_init_secondary - setup AP MTRR state - * - * Yes, this code is exactly the same as the set_mtrr code, except for the - * piece in the middle - you set all the ranges at once, instead of one - * register at a time. - * Shoot me. - */ -void __init mtrr_init_secondary_cpu(void) -{ - unsigned long flags; - - if (!mtrr_if || !mtrr_if->init_secondary) { - /* I see no MTRRs I can support in SMP mode... */ - printk("mtrr: SMP support incomplete for this vendor\n"); - return; - } - - local_irq_save(flags); - mtrr_if->init_secondary(); - local_irq_restore(flags); -} - -/** - * mtrr_final_init - finalize initialization sequence. - */ -static int __init mtrr_finalize_state(void) -{ - if (use_intel()) { - finalize_mtrr_state(); - mtrr_state_warn(); - } - return 0; -} - -arch_initcall(mtrr_finalize_state); - diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 936ee9e5fbb2..dc115fbe7492 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -45,7 +45,6 @@ #include #include -#include #include #include #include @@ -403,12 +402,6 @@ void __init smp_callin(void) local_irq_enable(); -#ifdef CONFIG_MTRR - /* - * Must be done before calibration delay is computed - */ - mtrr_init_secondary_cpu (); -#endif /* * Get our bogomips. */ diff --git a/include/asm-i386/mtrr.h b/include/asm-i386/mtrr.h index ff3ea870d0d6..f2727e61fe63 100644 --- a/include/asm-i386/mtrr.h +++ b/include/asm-i386/mtrr.h @@ -115,13 +115,6 @@ static __inline__ void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) {;} # endif -/* The following functions are for initialisation: don't use them! */ -extern int mtrr_init (void); -# if defined(CONFIG_SMP) && defined(CONFIG_MTRR) -extern void mtrr_init_boot_cpu (void); -extern void mtrr_init_secondary_cpu (void); -# endif - #endif #endif /* _LINUX_MTRR_H */ diff --git a/init/main.c b/init/main.c index 9aa3a0600960..b484d14df3a2 100644 --- a/init/main.c +++ b/init/main.c @@ -38,10 +38,6 @@ #include #endif -#ifdef CONFIG_MTRR -# include -#endif - #ifdef CONFIG_X86_LOCAL_APIC #include #endif @@ -536,15 +532,6 @@ static int init(void * unused) */ child_reaper = current; -#if defined(CONFIG_MTRR) /* Do this after SMP initialization */ -/* - * We should probably create some architecture-dependent "fixup after - * everything is up" style function where this would belong better - * than in init/main.c.. - */ - mtrr_init(); -#endif - /* Sets up cpus_possible() */ smp_prepare_cpus(max_cpus); -- cgit v1.2.3 From 3843e047e902b4727a7d1f59c766da3f3b2989f0 Mon Sep 17 00:00:00 2001 From: Rolf Fokkens Date: Mon, 9 Sep 2002 03:26:06 -0700 Subject: [PATCH] USER_HZ & NTP problems I've been playing with different HZ values in the 2.4 kernel for a while now, and apparantly Linus also has decided to introduce a USER_HZ constant (I used CLOCKS_PER_SEC) while raising the HZ value on x86 to 1000. On x86 timekeeping has shown to be relative fragile when raising HZ (OK, I tried HZ=2048 which is quite high) because of the way the interrupt timer is configured to fire HZ times each second. This is done by configuring a divisor in the timer chip (LATCH) which divides a certain clock (1193180) and makes the chip fire interrupts at the resulting frequency. Now comes the catch: NTP requires a clock accuracy of 500 ppm. For some HZ values the clock is not accurate enough to meet this requirement, hence NTP won't work well. An example HZ value is 1020 which exceeds the 500 ppm requirement. In this case the best approximation is 1019.8 Hz. the xtime.tv_usec value is raised with a value of 980 each tick which means that after one second the tv_usec value has increased with 999404 (should be 1000000) which is an accuracy of 596 ppm. Some more examples: HZ Accuracy (ppm) ---- -------------- 100 17 1000 151 1024 632 2000 687 2008 343 2011 18 2048 1249 What I've been doing is replace tv_usec by tv_nsec, meaning xtime is now a timespec instead of a timeval. This allows the accuracy to be improved by a factor of 1000 for any (well ... any?) HZ value. Of course all kinds of calculations had te be improved as well. The ACTHZ constantant is introduced to approximate the actual HZ value, it's used to do some approximations of other related values. --- arch/i386/kernel/time.c | 13 +++++++------ fs/udf/udfdecl.h | 2 +- include/linux/time.h | 2 +- include/linux/timex.h | 25 ++++++++++++++++++++++++- kernel/time.c | 16 ++++++---------- kernel/timer.c | 26 ++++++++++++++------------ 6 files changed, 53 insertions(+), 31 deletions(-) (limited to 'include') diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index a32314075d1d..ae3e803a5368 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -115,7 +115,7 @@ static inline unsigned long do_fast_gettimeoffset(void) return delay_at_last_interrupt + edx; } -#define TICK_SIZE tick +#define TICK_SIZE (tick_nsec / 1000) spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED; EXPORT_SYMBOL(i8253_lock); @@ -280,7 +280,7 @@ void do_gettimeofday(struct timeval *tv) usec += lost * (1000000 / HZ); } sec = xtime.tv_sec; - usec += xtime.tv_usec; + usec += (xtime.tv_nsec / 1000); read_unlock_irqrestore(&xtime_lock, flags); while (usec >= 1000000) { @@ -309,7 +309,8 @@ void do_settimeofday(struct timeval *tv) tv->tv_sec--; } - xtime = *tv; + xtime.tv_sec = tv->tv_sec; + xtime.tv_nsec = (tv->tv_usec * 1000); time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; @@ -437,8 +438,8 @@ static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *reg */ if ((time_status & STA_UNSYNC) == 0 && xtime.tv_sec > last_rtc_update + 660 && - xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 && - xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) { + (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && + (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else @@ -655,7 +656,7 @@ void __init time_init(void) extern int x86_udelay_tsc; xtime.tv_sec = get_cmos_time(); - xtime.tv_usec = 0; + xtime.tv_nsec = 0; /* * If we have APM enabled or the CPU clock speed is variable diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 4ee650d38e7c..c23edd0315b8 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -32,7 +32,7 @@ #define UDF_NAME_LEN 255 #define UDF_PATH_LEN 1023 -#define CURRENT_UTIME (xtime.tv_usec) +#define CURRENT_UTIME (xtime.tv_nsec / 1000) #define udf_file_entry_alloc_offset(inode)\ ((UDF_I_EXTENDED_FE(inode) ?\ diff --git a/include/linux/time.h b/include/linux/time.h index d9f9c6a340d8..088c52d09449 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -113,7 +113,7 @@ mktime (unsigned int year, unsigned int mon, )*60 + sec; /* finally seconds */ } -extern struct timeval xtime; +extern struct timespec xtime; #define CURRENT_TIME (xtime.tv_sec) diff --git a/include/linux/timex.h b/include/linux/timex.h index b82cbdc776f7..5b2b0ac18ae7 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -155,6 +155,28 @@ /* LATCH is used in the interval timer and ftape setup. */ #define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ +/* Suppose we want to devide two numbers NOM and DEN: NOM/DEN, the we can + * improve accuracy by shifting LSH bits, hence calculating: + * (NOM << LSH) / DEN + * This however means trouble for large NOM, because (NOM << LSH) may no + * longer fit in 32 bits. The following way of calculating this gives us + * some slack, under the following onditions: + * - (NOM / DEN) fits in (32 - LSH) bits. + * - (NOM % DEN) fits in (32 - LSH) bits. + */ +#define SH_DIV(NOM,DEN,LSH) ( ((NOM / DEN) << LSH) \ + + (((NOM % DEN) << LSH) + DEN / 2) / DEN) + +/* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */ +#define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8)) + +/* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ +#define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) + +/* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ and */ +/* a value TUSEC for TICK_USEC (can be set bij adjtimex) */ +#define TICK_NSEC(TUSEC) (SH_DIV (TUSEC * USER_HZ * 1000, ACTHZ, 8)) + /* * syscall interface - used (mainly by NTP daemon) * to discipline kernel clock oscillator @@ -251,7 +273,8 @@ struct timex { * Note: maximum error = NTP synch distance = dispersion + delay / 2; * estimated error = NTP dispersion. */ -extern long tick; /* timer interrupt period */ +extern unsigned long tick_usec; /* USER_HZ period (usec) */ +extern unsigned long tick_nsec; /* ACTHZ period (nsec) */ extern int tickadj; /* amount of adjustment per tick */ /* diff --git a/kernel/time.c b/kernel/time.c index edb7eb7b8b73..716e0bbe071a 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -82,7 +82,7 @@ asmlinkage long sys_stime(int * tptr) return -EFAULT; write_lock_irq(&xtime_lock); xtime.tv_sec = value; - xtime.tv_usec = 0; + xtime.tv_nsec = 0; last_time_offset = 0; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; @@ -231,7 +231,8 @@ int do_adjtimex(struct timex *txc) /* if the quartz is off by more than 10% something is VERY wrong ! */ if (txc->modes & ADJ_TICK) - if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ) + if (txc->tick < 900000/USER_HZ || + txc->tick > 1100000/USER_HZ) return -EINVAL; write_lock_irq(&xtime_lock); @@ -344,13 +345,8 @@ int do_adjtimex(struct timex *txc) } /* STA_PLL || STA_PPSTIME */ } /* txc->modes & ADJ_OFFSET */ if (txc->modes & ADJ_TICK) { - /* if the quartz is off by more than 10% something is - VERY wrong ! */ - if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ) { - result = -EINVAL; - goto leave; - } - tick = txc->tick; + tick_usec = txc->tick; + tick_nsec = TICK_NSEC(tick_usec); } } /* txc->modes */ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0 @@ -380,7 +376,7 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0 txc->constant = time_constant; txc->precision = time_precision; txc->tolerance = time_tolerance; - txc->tick = tick; + txc->tick = tick_usec; txc->ppsfreq = pps_freq; txc->jitter = pps_jitter >> PPS_AVG; txc->shift = pps_shift; diff --git a/kernel/timer.c b/kernel/timer.c index d4efe5823e94..3b4be840f931 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -33,10 +33,11 @@ struct kernel_stat kstat; * Timekeeping variables */ -long tick = (1000000 + HZ/2) / HZ; /* timer interrupt period */ +unsigned long tick_usec = TICK_USEC; /* ACTHZ period (usec) */ +unsigned long tick_nsec = TICK_NSEC(TICK_USEC); /* USER_HZ period (nsec) */ /* The current time */ -struct timeval xtime __attribute__ ((aligned (16))); +struct timespec xtime __attribute__ ((aligned (16))); /* Don't completely fail for HZ > 500. */ int tickadj = 500/HZ ? : 1; /* microsecs */ @@ -63,7 +64,6 @@ long time_adj; /* tick adjust (scaled 1 / HZ) */ long time_reftime; /* time at last adjustment (s) */ long time_adjust; -long time_adjust_step; unsigned long event; @@ -465,6 +465,8 @@ static void second_overflow(void) /* in the NTP reference this is called "hardclock()" */ static void update_wall_time_one_tick(void) { + long time_adjust_step; + if ( (time_adjust_step = time_adjust) != 0 ) { /* We are doing an adjtime thing. * @@ -483,21 +485,21 @@ static void update_wall_time_one_tick(void) /* Reduce by this step the amount of time left */ time_adjust -= time_adjust_step; } - xtime.tv_usec += tick + time_adjust_step; + xtime.tv_nsec += tick_nsec + time_adjust_step * 1000; /* * Advance the phase, once it gets to one microsecond, then * advance the tick more. */ time_phase += time_adj; if (time_phase <= -FINEUSEC) { - long ltemp = -time_phase >> SHIFT_SCALE; - time_phase += ltemp << SHIFT_SCALE; - xtime.tv_usec -= ltemp; + long ltemp = -time_phase >> (SHIFT_SCALE - 10); + time_phase += ltemp << (SHIFT_SCALE - 10); + xtime.tv_nsec -= ltemp; } else if (time_phase >= FINEUSEC) { - long ltemp = time_phase >> SHIFT_SCALE; - time_phase -= ltemp << SHIFT_SCALE; - xtime.tv_usec += ltemp; + long ltemp = time_phase >> (SHIFT_SCALE - 10); + time_phase -= ltemp << (SHIFT_SCALE - 10); + xtime.tv_nsec += ltemp; } } @@ -515,8 +517,8 @@ static void update_wall_time(unsigned long ticks) update_wall_time_one_tick(); } while (ticks); - if (xtime.tv_usec >= 1000000) { - xtime.tv_usec -= 1000000; + if (xtime.tv_nsec >= 1000000000) { + xtime.tv_nsec -= 1000000000; xtime.tv_sec++; second_overflow(); } -- cgit v1.2.3