diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-19 20:44:40 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-19 20:44:40 -0400 |
| commit | 7e6628e4bcb3b3546c625ec63ca724f28ab14f0c (patch) | |
| tree | 111a94cefa9d800ec5c5e59520f4b5d1880965d0 | |
| parent | 0f1bdc1815c4cb29b3cd71a7091b478e426faa0b (diff) | |
| parent | ab0e08f15d23628dd8d50bf6ce1a935a8840c7dc (diff) | |
Merge branch 'timers-clockevents-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'timers-clockevents-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
x86: hpet: Cleanup the clockevents init and register code
x86: Convert PIT to clockevents_config_and_register()
clockevents: Provide interface to reconfigure an active clock event device
clockevents: Provide combined configure and register function
clockevents: Restructure clock_event_device members
clocksource: Get rid of the hardcoded 5 seconds sleep time limit
clocksource: Restructure clocksource struct members
| -rw-r--r-- | arch/x86/kernel/hpet.c | 72 | ||||
| -rw-r--r-- | arch/x86/kernel/i8253.c | 6 | ||||
| -rw-r--r-- | include/linux/clockchips.h | 56 | ||||
| -rw-r--r-- | include/linux/clocksource.h | 32 | ||||
| -rw-r--r-- | kernel/time/clockevents.c | 64 | ||||
| -rw-r--r-- | kernel/time/clocksource.c | 38 |
6 files changed, 148 insertions, 120 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index bfe8f729e086..6781765b3a0d 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c | |||
| @@ -217,7 +217,7 @@ static void hpet_reserve_platform_timers(unsigned int id) { } | |||
| 217 | /* | 217 | /* |
| 218 | * Common hpet info | 218 | * Common hpet info |
| 219 | */ | 219 | */ |
| 220 | static unsigned long hpet_period; | 220 | static unsigned long hpet_freq; |
| 221 | 221 | ||
| 222 | static void hpet_legacy_set_mode(enum clock_event_mode mode, | 222 | static void hpet_legacy_set_mode(enum clock_event_mode mode, |
| 223 | struct clock_event_device *evt); | 223 | struct clock_event_device *evt); |
| @@ -232,7 +232,6 @@ static struct clock_event_device hpet_clockevent = { | |||
| 232 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 232 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
| 233 | .set_mode = hpet_legacy_set_mode, | 233 | .set_mode = hpet_legacy_set_mode, |
| 234 | .set_next_event = hpet_legacy_next_event, | 234 | .set_next_event = hpet_legacy_next_event, |
| 235 | .shift = 32, | ||
| 236 | .irq = 0, | 235 | .irq = 0, |
| 237 | .rating = 50, | 236 | .rating = 50, |
| 238 | }; | 237 | }; |
| @@ -290,28 +289,12 @@ static void hpet_legacy_clockevent_register(void) | |||
| 290 | hpet_enable_legacy_int(); | 289 | hpet_enable_legacy_int(); |
| 291 | 290 | ||
| 292 | /* | 291 | /* |
| 293 | * The mult factor is defined as (include/linux/clockchips.h) | ||
| 294 | * mult/2^shift = cyc/ns (in contrast to ns/cyc in clocksource.h) | ||
| 295 | * hpet_period is in units of femtoseconds (per cycle), so | ||
| 296 | * mult/2^shift = cyc/ns = 10^6/hpet_period | ||
| 297 | * mult = (10^6 * 2^shift)/hpet_period | ||
| 298 | * mult = (FSEC_PER_NSEC << hpet_clockevent.shift)/hpet_period | ||
| 299 | */ | ||
| 300 | hpet_clockevent.mult = div_sc((unsigned long) FSEC_PER_NSEC, | ||
| 301 | hpet_period, hpet_clockevent.shift); | ||
| 302 | /* Calculate the min / max delta */ | ||
| 303 | hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, | ||
| 304 | &hpet_clockevent); | ||
| 305 | /* Setup minimum reprogramming delta. */ | ||
| 306 | hpet_clockevent.min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA, | ||
| 307 | &hpet_clockevent); | ||
| 308 | |||
| 309 | /* | ||
| 310 | * Start hpet with the boot cpu mask and make it | 292 | * Start hpet with the boot cpu mask and make it |
| 311 | * global after the IO_APIC has been initialized. | 293 | * global after the IO_APIC has been initialized. |
| 312 | */ | 294 | */ |
| 313 | hpet_clockevent.cpumask = cpumask_of(smp_processor_id()); | 295 | hpet_clockevent.cpumask = cpumask_of(smp_processor_id()); |
| 314 | clockevents_register_device(&hpet_clockevent); | 296 | clockevents_config_and_register(&hpet_clockevent, hpet_freq, |
| 297 | HPET_MIN_PROG_DELTA, 0x7FFFFFFF); | ||
| 315 | global_clock_event = &hpet_clockevent; | 298 | global_clock_event = &hpet_clockevent; |
| 316 | printk(KERN_DEBUG "hpet clockevent registered\n"); | 299 | printk(KERN_DEBUG "hpet clockevent registered\n"); |
| 317 | } | 300 | } |
| @@ -549,7 +532,6 @@ static int hpet_setup_irq(struct hpet_dev *dev) | |||
| 549 | static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu) | 532 | static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu) |
| 550 | { | 533 | { |
| 551 | struct clock_event_device *evt = &hdev->evt; | 534 | struct clock_event_device *evt = &hdev->evt; |
| 552 | uint64_t hpet_freq; | ||
| 553 | 535 | ||
| 554 | WARN_ON(cpu != smp_processor_id()); | 536 | WARN_ON(cpu != smp_processor_id()); |
| 555 | if (!(hdev->flags & HPET_DEV_VALID)) | 537 | if (!(hdev->flags & HPET_DEV_VALID)) |
| @@ -571,24 +553,10 @@ static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu) | |||
| 571 | 553 | ||
| 572 | evt->set_mode = hpet_msi_set_mode; | 554 | evt->set_mode = hpet_msi_set_mode; |
| 573 | evt->set_next_event = hpet_msi_next_event; | 555 | evt->set_next_event = hpet_msi_next_event; |
| 574 | evt->shift = 32; | ||
| 575 | |||
| 576 | /* | ||
| 577 | * The period is a femto seconds value. We need to calculate the | ||
| 578 | * scaled math multiplication factor for nanosecond to hpet tick | ||
| 579 | * conversion. | ||
| 580 | */ | ||
| 581 | hpet_freq = FSEC_PER_SEC; | ||
| 582 | do_div(hpet_freq, hpet_period); | ||
| 583 | evt->mult = div_sc((unsigned long) hpet_freq, | ||
| 584 | NSEC_PER_SEC, evt->shift); | ||
| 585 | /* Calculate the max delta */ | ||
| 586 | evt->max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, evt); | ||
| 587 | /* 5 usec minimum reprogramming delta. */ | ||
| 588 | evt->min_delta_ns = 5000; | ||
| 589 | |||
| 590 | evt->cpumask = cpumask_of(hdev->cpu); | 556 | evt->cpumask = cpumask_of(hdev->cpu); |
| 591 | clockevents_register_device(evt); | 557 | |
| 558 | clockevents_config_and_register(evt, hpet_freq, HPET_MIN_PROG_DELTA, | ||
| 559 | 0x7FFFFFFF); | ||
| 592 | } | 560 | } |
| 593 | 561 | ||
| 594 | #ifdef CONFIG_HPET | 562 | #ifdef CONFIG_HPET |
| @@ -792,7 +760,6 @@ static struct clocksource clocksource_hpet = { | |||
| 792 | static int hpet_clocksource_register(void) | 760 | static int hpet_clocksource_register(void) |
| 793 | { | 761 | { |
| 794 | u64 start, now; | 762 | u64 start, now; |
| 795 | u64 hpet_freq; | ||
| 796 | cycle_t t1; | 763 | cycle_t t1; |
| 797 | 764 | ||
| 798 | /* Start the counter */ | 765 | /* Start the counter */ |
| @@ -819,24 +786,7 @@ static int hpet_clocksource_register(void) | |||
| 819 | return -ENODEV; | 786 | return -ENODEV; |
| 820 | } | 787 | } |
| 821 | 788 | ||
| 822 | /* | ||
| 823 | * The definition of mult is (include/linux/clocksource.h) | ||
| 824 | * mult/2^shift = ns/cyc and hpet_period is in units of fsec/cyc | ||
| 825 | * so we first need to convert hpet_period to ns/cyc units: | ||
| 826 | * mult/2^shift = ns/cyc = hpet_period/10^6 | ||
| 827 | * mult = (hpet_period * 2^shift)/10^6 | ||
| 828 | * mult = (hpet_period << shift)/FSEC_PER_NSEC | ||
| 829 | */ | ||
| 830 | |||
| 831 | /* Need to convert hpet_period (fsec/cyc) to cyc/sec: | ||
| 832 | * | ||
| 833 | * cyc/sec = FSEC_PER_SEC/hpet_period(fsec/cyc) | ||
| 834 | * cyc/sec = (FSEC_PER_NSEC * NSEC_PER_SEC)/hpet_period | ||
| 835 | */ | ||
| 836 | hpet_freq = FSEC_PER_SEC; | ||
| 837 | do_div(hpet_freq, hpet_period); | ||
| 838 | clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq); | 789 | clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq); |
| 839 | |||
| 840 | return 0; | 790 | return 0; |
| 841 | } | 791 | } |
| 842 | 792 | ||
| @@ -845,7 +795,9 @@ static int hpet_clocksource_register(void) | |||
| 845 | */ | 795 | */ |
| 846 | int __init hpet_enable(void) | 796 | int __init hpet_enable(void) |
| 847 | { | 797 | { |
| 798 | unsigned long hpet_period; | ||
| 848 | unsigned int id; | 799 | unsigned int id; |
| 800 | u64 freq; | ||
| 849 | int i; | 801 | int i; |
| 850 | 802 | ||
| 851 | if (!is_hpet_capable()) | 803 | if (!is_hpet_capable()) |
| @@ -884,6 +836,14 @@ int __init hpet_enable(void) | |||
| 884 | goto out_nohpet; | 836 | goto out_nohpet; |
| 885 | 837 | ||
| 886 | /* | 838 | /* |
| 839 | * The period is a femto seconds value. Convert it to a | ||
| 840 | * frequency. | ||
| 841 | */ | ||
| 842 | freq = FSEC_PER_SEC; | ||
| 843 | do_div(freq, hpet_period); | ||
| 844 | hpet_freq = freq; | ||
| 845 | |||
| 846 | /* | ||
| 887 | * Read the HPET ID register to retrieve the IRQ routing | 847 | * Read the HPET ID register to retrieve the IRQ routing |
| 888 | * information and the number of channels | 848 | * information and the number of channels |
| 889 | */ | 849 | */ |
diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c index 577e90cadaeb..fb66dc9e36cb 100644 --- a/arch/x86/kernel/i8253.c +++ b/arch/x86/kernel/i8253.c | |||
| @@ -93,7 +93,6 @@ static struct clock_event_device pit_ce = { | |||
| 93 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 93 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
| 94 | .set_mode = init_pit_timer, | 94 | .set_mode = init_pit_timer, |
| 95 | .set_next_event = pit_next_event, | 95 | .set_next_event = pit_next_event, |
| 96 | .shift = 32, | ||
| 97 | .irq = 0, | 96 | .irq = 0, |
| 98 | }; | 97 | }; |
| 99 | 98 | ||
| @@ -108,11 +107,8 @@ void __init setup_pit_timer(void) | |||
| 108 | * IO_APIC has been initialized. | 107 | * IO_APIC has been initialized. |
| 109 | */ | 108 | */ |
| 110 | pit_ce.cpumask = cpumask_of(smp_processor_id()); | 109 | pit_ce.cpumask = cpumask_of(smp_processor_id()); |
| 111 | pit_ce.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, pit_ce.shift); | ||
| 112 | pit_ce.max_delta_ns = clockevent_delta2ns(0x7FFF, &pit_ce); | ||
| 113 | pit_ce.min_delta_ns = clockevent_delta2ns(0xF, &pit_ce); | ||
| 114 | 110 | ||
| 115 | clockevents_register_device(&pit_ce); | 111 | clockevents_config_and_register(&pit_ce, CLOCK_TICK_RATE, 0xF, 0x7FFF); |
| 116 | global_clock_event = &pit_ce; | 112 | global_clock_event = &pit_ce; |
| 117 | } | 113 | } |
| 118 | 114 | ||
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index fc53492b6ad7..d6733e27af34 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h | |||
| @@ -56,46 +56,52 @@ enum clock_event_nofitiers { | |||
| 56 | 56 | ||
| 57 | /** | 57 | /** |
| 58 | * struct clock_event_device - clock event device descriptor | 58 | * struct clock_event_device - clock event device descriptor |
| 59 | * @name: ptr to clock event name | 59 | * @event_handler: Assigned by the framework to be called by the low |
| 60 | * @features: features | 60 | * level handler of the event source |
| 61 | * @set_next_event: set next event function | ||
| 62 | * @next_event: local storage for the next event in oneshot mode | ||
| 61 | * @max_delta_ns: maximum delta value in ns | 63 | * @max_delta_ns: maximum delta value in ns |
| 62 | * @min_delta_ns: minimum delta value in ns | 64 | * @min_delta_ns: minimum delta value in ns |
| 63 | * @mult: nanosecond to cycles multiplier | 65 | * @mult: nanosecond to cycles multiplier |
| 64 | * @shift: nanoseconds to cycles divisor (power of two) | 66 | * @shift: nanoseconds to cycles divisor (power of two) |
| 67 | * @mode: operating mode assigned by the management code | ||
| 68 | * @features: features | ||
| 69 | * @retries: number of forced programming retries | ||
| 70 | * @set_mode: set mode function | ||
| 71 | * @broadcast: function to broadcast events | ||
| 72 | * @min_delta_ticks: minimum delta value in ticks stored for reconfiguration | ||
| 73 | * @max_delta_ticks: maximum delta value in ticks stored for reconfiguration | ||
| 74 | * @name: ptr to clock event name | ||
| 65 | * @rating: variable to rate clock event devices | 75 | * @rating: variable to rate clock event devices |
| 66 | * @irq: IRQ number (only for non CPU local devices) | 76 | * @irq: IRQ number (only for non CPU local devices) |
| 67 | * @cpumask: cpumask to indicate for which CPUs this device works | 77 | * @cpumask: cpumask to indicate for which CPUs this device works |
| 68 | * @set_next_event: set next event function | ||
| 69 | * @set_mode: set mode function | ||
| 70 | * @event_handler: Assigned by the framework to be called by the low | ||
| 71 | * level handler of the event source | ||
| 72 | * @broadcast: function to broadcast events | ||
| 73 | * @list: list head for the management code | 78 | * @list: list head for the management code |
| 74 | * @mode: operating mode assigned by the management code | ||
| 75 | * @next_event: local storage for the next event in oneshot mode | ||
| 76 | * @retries: number of forced programming retries | ||
| 77 | */ | 79 | */ |
| 78 | struct clock_event_device { | 80 | struct clock_event_device { |
| 79 | const char *name; | 81 | void (*event_handler)(struct clock_event_device *); |
| 80 | unsigned int features; | 82 | int (*set_next_event)(unsigned long evt, |
| 83 | struct clock_event_device *); | ||
| 84 | ktime_t next_event; | ||
| 81 | u64 max_delta_ns; | 85 | u64 max_delta_ns; |
| 82 | u64 min_delta_ns; | 86 | u64 min_delta_ns; |
| 83 | u32 mult; | 87 | u32 mult; |
| 84 | u32 shift; | 88 | u32 shift; |
| 89 | enum clock_event_mode mode; | ||
| 90 | unsigned int features; | ||
| 91 | unsigned long retries; | ||
| 92 | |||
| 93 | void (*broadcast)(const struct cpumask *mask); | ||
| 94 | void (*set_mode)(enum clock_event_mode mode, | ||
| 95 | struct clock_event_device *); | ||
| 96 | unsigned long min_delta_ticks; | ||
| 97 | unsigned long max_delta_ticks; | ||
| 98 | |||
| 99 | const char *name; | ||
| 85 | int rating; | 100 | int rating; |
| 86 | int irq; | 101 | int irq; |
| 87 | const struct cpumask *cpumask; | 102 | const struct cpumask *cpumask; |
| 88 | int (*set_next_event)(unsigned long evt, | ||
| 89 | struct clock_event_device *); | ||
| 90 | void (*set_mode)(enum clock_event_mode mode, | ||
| 91 | struct clock_event_device *); | ||
| 92 | void (*event_handler)(struct clock_event_device *); | ||
| 93 | void (*broadcast)(const struct cpumask *mask); | ||
| 94 | struct list_head list; | 103 | struct list_head list; |
| 95 | enum clock_event_mode mode; | 104 | } ____cacheline_aligned; |
| 96 | ktime_t next_event; | ||
| 97 | unsigned long retries; | ||
| 98 | }; | ||
| 99 | 105 | ||
| 100 | /* | 106 | /* |
| 101 | * Calculate a multiplication factor for scaled math, which is used to convert | 107 | * Calculate a multiplication factor for scaled math, which is used to convert |
| @@ -122,6 +128,12 @@ extern u64 clockevent_delta2ns(unsigned long latch, | |||
| 122 | struct clock_event_device *evt); | 128 | struct clock_event_device *evt); |
| 123 | extern void clockevents_register_device(struct clock_event_device *dev); | 129 | extern void clockevents_register_device(struct clock_event_device *dev); |
| 124 | 130 | ||
| 131 | extern void clockevents_config_and_register(struct clock_event_device *dev, | ||
| 132 | u32 freq, unsigned long min_delta, | ||
| 133 | unsigned long max_delta); | ||
| 134 | |||
| 135 | extern int clockevents_update_freq(struct clock_event_device *ce, u32 freq); | ||
| 136 | |||
| 125 | extern void clockevents_exchange_device(struct clock_event_device *old, | 137 | extern void clockevents_exchange_device(struct clock_event_device *old, |
| 126 | struct clock_event_device *new); | 138 | struct clock_event_device *new); |
| 127 | extern void clockevents_set_mode(struct clock_event_device *dev, | 139 | extern void clockevents_set_mode(struct clock_event_device *dev, |
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 0fb0b7e79394..c918fbd33ee5 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h | |||
| @@ -159,42 +159,38 @@ extern u64 timecounter_cyc2time(struct timecounter *tc, | |||
| 159 | */ | 159 | */ |
| 160 | struct clocksource { | 160 | struct clocksource { |
| 161 | /* | 161 | /* |
| 162 | * First part of structure is read mostly | 162 | * Hotpath data, fits in a single cache line when the |
| 163 | * clocksource itself is cacheline aligned. | ||
| 163 | */ | 164 | */ |
| 164 | const char *name; | ||
| 165 | struct list_head list; | ||
| 166 | int rating; | ||
| 167 | cycle_t (*read)(struct clocksource *cs); | 165 | cycle_t (*read)(struct clocksource *cs); |
| 168 | int (*enable)(struct clocksource *cs); | 166 | cycle_t cycle_last; |
| 169 | void (*disable)(struct clocksource *cs); | ||
| 170 | cycle_t mask; | 167 | cycle_t mask; |
| 171 | u32 mult; | 168 | u32 mult; |
| 172 | u32 shift; | 169 | u32 shift; |
| 173 | u64 max_idle_ns; | 170 | u64 max_idle_ns; |
| 174 | unsigned long flags; | 171 | |
| 175 | cycle_t (*vread)(void); | ||
| 176 | void (*suspend)(struct clocksource *cs); | ||
| 177 | void (*resume)(struct clocksource *cs); | ||
| 178 | #ifdef CONFIG_IA64 | 172 | #ifdef CONFIG_IA64 |
| 179 | void *fsys_mmio; /* used by fsyscall asm code */ | 173 | void *fsys_mmio; /* used by fsyscall asm code */ |
| 180 | #define CLKSRC_FSYS_MMIO_SET(mmio, addr) ((mmio) = (addr)) | 174 | #define CLKSRC_FSYS_MMIO_SET(mmio, addr) ((mmio) = (addr)) |
| 181 | #else | 175 | #else |
| 182 | #define CLKSRC_FSYS_MMIO_SET(mmio, addr) do { } while (0) | 176 | #define CLKSRC_FSYS_MMIO_SET(mmio, addr) do { } while (0) |
| 183 | #endif | 177 | #endif |
| 184 | 178 | const char *name; | |
| 185 | /* | 179 | struct list_head list; |
| 186 | * Second part is written at each timer interrupt | 180 | int rating; |
| 187 | * Keep it in a different cache line to dirty no | 181 | cycle_t (*vread)(void); |
| 188 | * more than one cache line. | 182 | int (*enable)(struct clocksource *cs); |
| 189 | */ | 183 | void (*disable)(struct clocksource *cs); |
| 190 | cycle_t cycle_last ____cacheline_aligned_in_smp; | 184 | unsigned long flags; |
| 185 | void (*suspend)(struct clocksource *cs); | ||
| 186 | void (*resume)(struct clocksource *cs); | ||
| 191 | 187 | ||
| 192 | #ifdef CONFIG_CLOCKSOURCE_WATCHDOG | 188 | #ifdef CONFIG_CLOCKSOURCE_WATCHDOG |
| 193 | /* Watchdog related data, used by the framework */ | 189 | /* Watchdog related data, used by the framework */ |
| 194 | struct list_head wd_list; | 190 | struct list_head wd_list; |
| 195 | cycle_t wd_last; | 191 | cycle_t wd_last; |
| 196 | #endif | 192 | #endif |
| 197 | }; | 193 | } ____cacheline_aligned; |
| 198 | 194 | ||
| 199 | /* | 195 | /* |
| 200 | * Clock source flags bits:: | 196 | * Clock source flags bits:: |
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 0d74b9ba90c8..22a9da9a9c96 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c | |||
| @@ -194,6 +194,70 @@ void clockevents_register_device(struct clock_event_device *dev) | |||
| 194 | } | 194 | } |
| 195 | EXPORT_SYMBOL_GPL(clockevents_register_device); | 195 | EXPORT_SYMBOL_GPL(clockevents_register_device); |
| 196 | 196 | ||
| 197 | static void clockevents_config(struct clock_event_device *dev, | ||
| 198 | u32 freq) | ||
| 199 | { | ||
| 200 | unsigned long sec; | ||
| 201 | |||
| 202 | if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT)) | ||
| 203 | return; | ||
| 204 | |||
| 205 | /* | ||
| 206 | * Calculate the maximum number of seconds we can sleep. Limit | ||
| 207 | * to 10 minutes for hardware which can program more than | ||
| 208 | * 32bit ticks so we still get reasonable conversion values. | ||
| 209 | */ | ||
| 210 | sec = dev->max_delta_ticks; | ||
| 211 | do_div(sec, freq); | ||
| 212 | if (!sec) | ||
| 213 | sec = 1; | ||
| 214 | else if (sec > 600 && dev->max_delta_ticks > UINT_MAX) | ||
| 215 | sec = 600; | ||
| 216 | |||
| 217 | clockevents_calc_mult_shift(dev, freq, sec); | ||
| 218 | dev->min_delta_ns = clockevent_delta2ns(dev->min_delta_ticks, dev); | ||
| 219 | dev->max_delta_ns = clockevent_delta2ns(dev->max_delta_ticks, dev); | ||
| 220 | } | ||
| 221 | |||
| 222 | /** | ||
| 223 | * clockevents_config_and_register - Configure and register a clock event device | ||
| 224 | * @dev: device to register | ||
| 225 | * @freq: The clock frequency | ||
| 226 | * @min_delta: The minimum clock ticks to program in oneshot mode | ||
| 227 | * @max_delta: The maximum clock ticks to program in oneshot mode | ||
| 228 | * | ||
| 229 | * min/max_delta can be 0 for devices which do not support oneshot mode. | ||
| 230 | */ | ||
| 231 | void clockevents_config_and_register(struct clock_event_device *dev, | ||
| 232 | u32 freq, unsigned long min_delta, | ||
| 233 | unsigned long max_delta) | ||
| 234 | { | ||
| 235 | dev->min_delta_ticks = min_delta; | ||
| 236 | dev->max_delta_ticks = max_delta; | ||
| 237 | clockevents_config(dev, freq); | ||
| 238 | clockevents_register_device(dev); | ||
| 239 | } | ||
| 240 | |||
| 241 | /** | ||
| 242 | * clockevents_update_freq - Update frequency and reprogram a clock event device. | ||
| 243 | * @dev: device to modify | ||
| 244 | * @freq: new device frequency | ||
| 245 | * | ||
| 246 | * Reconfigure and reprogram a clock event device in oneshot | ||
| 247 | * mode. Must be called on the cpu for which the device delivers per | ||
| 248 | * cpu timer events with interrupts disabled! Returns 0 on success, | ||
| 249 | * -ETIME when the event is in the past. | ||
| 250 | */ | ||
| 251 | int clockevents_update_freq(struct clock_event_device *dev, u32 freq) | ||
| 252 | { | ||
| 253 | clockevents_config(dev, freq); | ||
| 254 | |||
| 255 | if (dev->mode != CLOCK_EVT_MODE_ONESHOT) | ||
| 256 | return 0; | ||
| 257 | |||
| 258 | return clockevents_program_event(dev, dev->next_event, ktime_get()); | ||
| 259 | } | ||
| 260 | |||
| 197 | /* | 261 | /* |
| 198 | * Noop handler when we shut down an event device | 262 | * Noop handler when we shut down an event device |
| 199 | */ | 263 | */ |
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 0e17c10f8a9d..d9d5f8c885f6 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c | |||
| @@ -626,19 +626,6 @@ static void clocksource_enqueue(struct clocksource *cs) | |||
| 626 | list_add(&cs->list, entry); | 626 | list_add(&cs->list, entry); |
| 627 | } | 627 | } |
| 628 | 628 | ||
| 629 | |||
| 630 | /* | ||
| 631 | * Maximum time we expect to go between ticks. This includes idle | ||
| 632 | * tickless time. It provides the trade off between selecting a | ||
| 633 | * mult/shift pair that is very precise but can only handle a short | ||
| 634 | * period of time, vs. a mult/shift pair that can handle long periods | ||
| 635 | * of time but isn't as precise. | ||
| 636 | * | ||
| 637 | * This is a subsystem constant, and actual hardware limitations | ||
| 638 | * may override it (ie: clocksources that wrap every 3 seconds). | ||
| 639 | */ | ||
| 640 | #define MAX_UPDATE_LENGTH 5 /* Seconds */ | ||
| 641 | |||
| 642 | /** | 629 | /** |
| 643 | * __clocksource_updatefreq_scale - Used update clocksource with new freq | 630 | * __clocksource_updatefreq_scale - Used update clocksource with new freq |
| 644 | * @t: clocksource to be registered | 631 | * @t: clocksource to be registered |
| @@ -652,15 +639,28 @@ static void clocksource_enqueue(struct clocksource *cs) | |||
| 652 | */ | 639 | */ |
| 653 | void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq) | 640 | void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq) |
| 654 | { | 641 | { |
| 642 | unsigned long sec; | ||
| 643 | |||
| 655 | /* | 644 | /* |
| 656 | * Ideally we want to use some of the limits used in | 645 | * Calc the maximum number of seconds which we can run before |
| 657 | * clocksource_max_deferment, to provide a more informed | 646 | * wrapping around. For clocksources which have a mask > 32bit |
| 658 | * MAX_UPDATE_LENGTH. But for now this just gets the | 647 | * we need to limit the max sleep time to have a good |
| 659 | * register interface working properly. | 648 | * conversion precision. 10 minutes is still a reasonable |
| 649 | * amount. That results in a shift value of 24 for a | ||
| 650 | * clocksource with mask >= 40bit and f >= 4GHz. That maps to | ||
| 651 | * ~ 0.06ppm granularity for NTP. We apply the same 12.5% | ||
| 652 | * margin as we do in clocksource_max_deferment() | ||
| 660 | */ | 653 | */ |
| 654 | sec = (cs->mask - (cs->mask >> 5)); | ||
| 655 | do_div(sec, freq); | ||
| 656 | do_div(sec, scale); | ||
| 657 | if (!sec) | ||
| 658 | sec = 1; | ||
| 659 | else if (sec > 600 && cs->mask > UINT_MAX) | ||
| 660 | sec = 600; | ||
| 661 | |||
| 661 | clocks_calc_mult_shift(&cs->mult, &cs->shift, freq, | 662 | clocks_calc_mult_shift(&cs->mult, &cs->shift, freq, |
| 662 | NSEC_PER_SEC/scale, | 663 | NSEC_PER_SEC / scale, sec * scale); |
| 663 | MAX_UPDATE_LENGTH*scale); | ||
| 664 | cs->max_idle_ns = clocksource_max_deferment(cs); | 664 | cs->max_idle_ns = clocksource_max_deferment(cs); |
| 665 | } | 665 | } |
| 666 | EXPORT_SYMBOL_GPL(__clocksource_updatefreq_scale); | 666 | EXPORT_SYMBOL_GPL(__clocksource_updatefreq_scale); |
