diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/auditfilter.c | 13 | ||||
| -rw-r--r-- | kernel/auditsc.c | 51 | ||||
| -rw-r--r-- | kernel/hrtimer.c | 15 | ||||
| -rw-r--r-- | kernel/irq/proc.c | 10 | ||||
| -rw-r--r-- | kernel/power/Kconfig | 2 | ||||
| -rw-r--r-- | kernel/signal.c | 10 | ||||
| -rw-r--r-- | kernel/sysctl.c | 10 | ||||
| -rw-r--r-- | kernel/time/ntp.c | 59 | ||||
| -rw-r--r-- | kernel/time/tick-broadcast.c | 35 | ||||
| -rw-r--r-- | kernel/time/tick-common.c | 16 | ||||
| -rw-r--r-- | kernel/time/tick-oneshot.c | 15 | ||||
| -rw-r--r-- | kernel/time/tick-sched.c | 7 |
12 files changed, 172 insertions, 71 deletions
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 1bf093dcffe0..359645cff5b2 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c | |||
| @@ -304,7 +304,7 @@ int __init audit_register_class(int class, unsigned *list) | |||
| 304 | 304 | ||
| 305 | int audit_match_class(int class, unsigned syscall) | 305 | int audit_match_class(int class, unsigned syscall) |
| 306 | { | 306 | { |
| 307 | if (unlikely(syscall >= AUDIT_BITMASK_SIZE * sizeof(__u32))) | 307 | if (unlikely(syscall >= AUDIT_BITMASK_SIZE * 32)) |
| 308 | return 0; | 308 | return 0; |
| 309 | if (unlikely(class >= AUDIT_SYSCALL_CLASSES || !classes[class])) | 309 | if (unlikely(class >= AUDIT_SYSCALL_CLASSES || !classes[class])) |
| 310 | return 0; | 310 | return 0; |
| @@ -456,6 +456,13 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule) | |||
| 456 | case AUDIT_DEVMINOR: | 456 | case AUDIT_DEVMINOR: |
| 457 | case AUDIT_EXIT: | 457 | case AUDIT_EXIT: |
| 458 | case AUDIT_SUCCESS: | 458 | case AUDIT_SUCCESS: |
| 459 | /* bit ops are only useful on syscall args */ | ||
| 460 | if (f->op == AUDIT_BIT_MASK || | ||
| 461 | f->op == AUDIT_BIT_TEST) { | ||
| 462 | err = -EINVAL; | ||
| 463 | goto exit_free; | ||
| 464 | } | ||
| 465 | break; | ||
| 459 | case AUDIT_ARG0: | 466 | case AUDIT_ARG0: |
| 460 | case AUDIT_ARG1: | 467 | case AUDIT_ARG1: |
| 461 | case AUDIT_ARG2: | 468 | case AUDIT_ARG2: |
| @@ -1566,6 +1573,10 @@ int audit_comparator(const u32 left, const u32 op, const u32 right) | |||
| 1566 | return (left > right); | 1573 | return (left > right); |
| 1567 | case AUDIT_GREATER_THAN_OR_EQUAL: | 1574 | case AUDIT_GREATER_THAN_OR_EQUAL: |
| 1568 | return (left >= right); | 1575 | return (left >= right); |
| 1576 | case AUDIT_BIT_MASK: | ||
| 1577 | return (left & right); | ||
| 1578 | case AUDIT_BIT_TEST: | ||
| 1579 | return ((left & right) == right); | ||
| 1569 | } | 1580 | } |
| 1570 | BUG(); | 1581 | BUG(); |
| 1571 | return 0; | 1582 | return 0; |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 145cbb79c4b9..bde1124d5908 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
| @@ -173,12 +173,6 @@ struct audit_aux_data_fd_pair { | |||
| 173 | int fd[2]; | 173 | int fd[2]; |
| 174 | }; | 174 | }; |
| 175 | 175 | ||
| 176 | struct audit_aux_data_path { | ||
| 177 | struct audit_aux_data d; | ||
| 178 | struct dentry *dentry; | ||
| 179 | struct vfsmount *mnt; | ||
| 180 | }; | ||
| 181 | |||
| 182 | struct audit_aux_data_pids { | 176 | struct audit_aux_data_pids { |
| 183 | struct audit_aux_data d; | 177 | struct audit_aux_data d; |
| 184 | pid_t target_pid[AUDIT_AUX_PIDS]; | 178 | pid_t target_pid[AUDIT_AUX_PIDS]; |
| @@ -654,12 +648,6 @@ static inline void audit_free_aux(struct audit_context *context) | |||
| 654 | struct audit_aux_data *aux; | 648 | struct audit_aux_data *aux; |
| 655 | 649 | ||
| 656 | while ((aux = context->aux)) { | 650 | while ((aux = context->aux)) { |
| 657 | if (aux->type == AUDIT_AVC_PATH) { | ||
| 658 | struct audit_aux_data_path *axi = (void *)aux; | ||
| 659 | dput(axi->dentry); | ||
| 660 | mntput(axi->mnt); | ||
| 661 | } | ||
| 662 | |||
| 663 | context->aux = aux->next; | 651 | context->aux = aux->next; |
| 664 | kfree(aux); | 652 | kfree(aux); |
| 665 | } | 653 | } |
| @@ -995,7 +983,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
| 995 | case AUDIT_IPC: { | 983 | case AUDIT_IPC: { |
| 996 | struct audit_aux_data_ipcctl *axi = (void *)aux; | 984 | struct audit_aux_data_ipcctl *axi = (void *)aux; |
| 997 | audit_log_format(ab, | 985 | audit_log_format(ab, |
| 998 | "ouid=%u ogid=%u mode=%x", | 986 | "ouid=%u ogid=%u mode=%#o", |
| 999 | axi->uid, axi->gid, axi->mode); | 987 | axi->uid, axi->gid, axi->mode); |
| 1000 | if (axi->osid != 0) { | 988 | if (axi->osid != 0) { |
| 1001 | char *ctx = NULL; | 989 | char *ctx = NULL; |
| @@ -1014,7 +1002,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
| 1014 | case AUDIT_IPC_SET_PERM: { | 1002 | case AUDIT_IPC_SET_PERM: { |
| 1015 | struct audit_aux_data_ipcctl *axi = (void *)aux; | 1003 | struct audit_aux_data_ipcctl *axi = (void *)aux; |
| 1016 | audit_log_format(ab, | 1004 | audit_log_format(ab, |
| 1017 | "qbytes=%lx ouid=%u ogid=%u mode=%x", | 1005 | "qbytes=%lx ouid=%u ogid=%u mode=%#o", |
| 1018 | axi->qbytes, axi->uid, axi->gid, axi->mode); | 1006 | axi->qbytes, axi->uid, axi->gid, axi->mode); |
| 1019 | break; } | 1007 | break; } |
| 1020 | 1008 | ||
| @@ -1038,11 +1026,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
| 1038 | audit_log_hex(ab, axs->a, axs->len); | 1026 | audit_log_hex(ab, axs->a, axs->len); |
| 1039 | break; } | 1027 | break; } |
| 1040 | 1028 | ||
| 1041 | case AUDIT_AVC_PATH: { | ||
| 1042 | struct audit_aux_data_path *axi = (void *)aux; | ||
| 1043 | audit_log_d_path(ab, "path=", axi->dentry, axi->mnt); | ||
| 1044 | break; } | ||
| 1045 | |||
| 1046 | case AUDIT_FD_PAIR: { | 1029 | case AUDIT_FD_PAIR: { |
| 1047 | struct audit_aux_data_fd_pair *axs = (void *)aux; | 1030 | struct audit_aux_data_fd_pair *axs = (void *)aux; |
| 1048 | audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]); | 1031 | audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]); |
| @@ -1991,36 +1974,6 @@ void __audit_ptrace(struct task_struct *t) | |||
| 1991 | } | 1974 | } |
| 1992 | 1975 | ||
| 1993 | /** | 1976 | /** |
| 1994 | * audit_avc_path - record the granting or denial of permissions | ||
| 1995 | * @dentry: dentry to record | ||
| 1996 | * @mnt: mnt to record | ||
| 1997 | * | ||
| 1998 | * Returns 0 for success or NULL context or < 0 on error. | ||
| 1999 | * | ||
| 2000 | * Called from security/selinux/avc.c::avc_audit() | ||
| 2001 | */ | ||
| 2002 | int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt) | ||
| 2003 | { | ||
| 2004 | struct audit_aux_data_path *ax; | ||
| 2005 | struct audit_context *context = current->audit_context; | ||
| 2006 | |||
| 2007 | if (likely(!context)) | ||
| 2008 | return 0; | ||
| 2009 | |||
| 2010 | ax = kmalloc(sizeof(*ax), GFP_ATOMIC); | ||
| 2011 | if (!ax) | ||
| 2012 | return -ENOMEM; | ||
| 2013 | |||
| 2014 | ax->dentry = dget(dentry); | ||
| 2015 | ax->mnt = mntget(mnt); | ||
| 2016 | |||
| 2017 | ax->d.type = AUDIT_AVC_PATH; | ||
| 2018 | ax->d.next = context->aux; | ||
| 2019 | context->aux = (void *)ax; | ||
| 2020 | return 0; | ||
| 2021 | } | ||
| 2022 | |||
| 2023 | /** | ||
| 2024 | * audit_signal_info - record signal info for shutting down audit subsystem | 1977 | * audit_signal_info - record signal info for shutting down audit subsystem |
| 2025 | * @sig: signal value | 1978 | * @sig: signal value |
| 2026 | * @t: task being signaled | 1979 | * @t: task being signaled |
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 72d034258ba1..eb1ddebd2c04 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
| @@ -558,7 +558,8 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, | |||
| 558 | */ | 558 | */ |
| 559 | static int hrtimer_switch_to_hres(void) | 559 | static int hrtimer_switch_to_hres(void) |
| 560 | { | 560 | { |
| 561 | struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases); | 561 | int cpu = smp_processor_id(); |
| 562 | struct hrtimer_cpu_base *base = &per_cpu(hrtimer_bases, cpu); | ||
| 562 | unsigned long flags; | 563 | unsigned long flags; |
| 563 | 564 | ||
| 564 | if (base->hres_active) | 565 | if (base->hres_active) |
| @@ -568,6 +569,8 @@ static int hrtimer_switch_to_hres(void) | |||
| 568 | 569 | ||
| 569 | if (tick_init_highres()) { | 570 | if (tick_init_highres()) { |
| 570 | local_irq_restore(flags); | 571 | local_irq_restore(flags); |
| 572 | printk(KERN_WARNING "Could not switch to high resolution " | ||
| 573 | "mode on CPU %d\n", cpu); | ||
| 571 | return 0; | 574 | return 0; |
| 572 | } | 575 | } |
| 573 | base->hres_active = 1; | 576 | base->hres_active = 1; |
| @@ -683,6 +686,7 @@ static void enqueue_hrtimer(struct hrtimer *timer, | |||
| 683 | struct rb_node **link = &base->active.rb_node; | 686 | struct rb_node **link = &base->active.rb_node; |
| 684 | struct rb_node *parent = NULL; | 687 | struct rb_node *parent = NULL; |
| 685 | struct hrtimer *entry; | 688 | struct hrtimer *entry; |
| 689 | int leftmost = 1; | ||
| 686 | 690 | ||
| 687 | /* | 691 | /* |
| 688 | * Find the right place in the rbtree: | 692 | * Find the right place in the rbtree: |
| @@ -694,18 +698,19 @@ static void enqueue_hrtimer(struct hrtimer *timer, | |||
| 694 | * We dont care about collisions. Nodes with | 698 | * We dont care about collisions. Nodes with |
| 695 | * the same expiry time stay together. | 699 | * the same expiry time stay together. |
| 696 | */ | 700 | */ |
| 697 | if (timer->expires.tv64 < entry->expires.tv64) | 701 | if (timer->expires.tv64 < entry->expires.tv64) { |
| 698 | link = &(*link)->rb_left; | 702 | link = &(*link)->rb_left; |
| 699 | else | 703 | } else { |
| 700 | link = &(*link)->rb_right; | 704 | link = &(*link)->rb_right; |
| 705 | leftmost = 0; | ||
| 706 | } | ||
| 701 | } | 707 | } |
| 702 | 708 | ||
| 703 | /* | 709 | /* |
| 704 | * Insert the timer to the rbtree and check whether it | 710 | * Insert the timer to the rbtree and check whether it |
| 705 | * replaces the first pending timer | 711 | * replaces the first pending timer |
| 706 | */ | 712 | */ |
| 707 | if (!base->first || timer->expires.tv64 < | 713 | if (leftmost) { |
| 708 | rb_entry(base->first, struct hrtimer, node)->expires.tv64) { | ||
| 709 | /* | 714 | /* |
| 710 | * Reprogram the clock event device. When the timer is already | 715 | * Reprogram the clock event device. When the timer is already |
| 711 | * expired hrtimer_enqueue_reprogram has either called the | 716 | * expired hrtimer_enqueue_reprogram has either called the |
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index b4f1674fca79..50b81b98046a 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c | |||
| @@ -19,7 +19,15 @@ static struct proc_dir_entry *root_irq_dir; | |||
| 19 | static int irq_affinity_read_proc(char *page, char **start, off_t off, | 19 | static int irq_affinity_read_proc(char *page, char **start, off_t off, |
| 20 | int count, int *eof, void *data) | 20 | int count, int *eof, void *data) |
| 21 | { | 21 | { |
| 22 | int len = cpumask_scnprintf(page, count, irq_desc[(long)data].affinity); | 22 | struct irq_desc *desc = irq_desc + (long)data; |
| 23 | cpumask_t *mask = &desc->affinity; | ||
| 24 | int len; | ||
| 25 | |||
| 26 | #ifdef CONFIG_GENERIC_PENDING_IRQ | ||
| 27 | if (desc->status & IRQ_MOVE_PENDING) | ||
| 28 | mask = &desc->pending_mask; | ||
| 29 | #endif | ||
| 30 | len = cpumask_scnprintf(page, count, *mask); | ||
| 23 | 31 | ||
| 24 | if (count - len < 2) | 32 | if (count - len < 2) |
| 25 | return -EINVAL; | 33 | return -EINVAL; |
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 7358609e4735..c1a106d87d90 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig | |||
| @@ -57,7 +57,7 @@ config DISABLE_CONSOLE_SUSPEND | |||
| 57 | 57 | ||
| 58 | config PM_TRACE | 58 | config PM_TRACE |
| 59 | bool "Suspend/resume event tracing" | 59 | bool "Suspend/resume event tracing" |
| 60 | depends on PM_DEBUG && X86_32 && EXPERIMENTAL | 60 | depends on PM_DEBUG && X86 && EXPERIMENTAL |
| 61 | default n | 61 | default n |
| 62 | ---help--- | 62 | ---help--- |
| 63 | This enables some cheesy code to save the last PM event point in the | 63 | This enables some cheesy code to save the last PM event point in the |
diff --git a/kernel/signal.c b/kernel/signal.c index 39d122753bac..ef8156a6aad5 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
| @@ -255,6 +255,16 @@ flush_signal_handlers(struct task_struct *t, int force_default) | |||
| 255 | } | 255 | } |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | int unhandled_signal(struct task_struct *tsk, int sig) | ||
| 259 | { | ||
| 260 | if (is_init(tsk)) | ||
| 261 | return 1; | ||
| 262 | if (tsk->ptrace & PT_PTRACED) | ||
| 263 | return 0; | ||
| 264 | return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) || | ||
| 265 | (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL); | ||
| 266 | } | ||
| 267 | |||
| 258 | 268 | ||
| 259 | /* Notify the system that a driver wants to block all signals for this | 269 | /* Notify the system that a driver wants to block all signals for this |
| 260 | * process, and wants to be notified if any signals at all were to be | 270 | * process, and wants to be notified if any signals at all were to be |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 222299844ad1..ddebf3f2affe 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -1203,6 +1203,16 @@ static ctl_table fs_table[] = { | |||
| 1203 | }; | 1203 | }; |
| 1204 | 1204 | ||
| 1205 | static ctl_table debug_table[] = { | 1205 | static ctl_table debug_table[] = { |
| 1206 | #ifdef CONFIG_X86 | ||
| 1207 | { | ||
| 1208 | .ctl_name = CTL_UNNUMBERED, | ||
| 1209 | .procname = "exception-trace", | ||
| 1210 | .data = &show_unhandled_signals, | ||
| 1211 | .maxlen = sizeof(int), | ||
| 1212 | .mode = 0644, | ||
| 1213 | .proc_handler = proc_dointvec | ||
| 1214 | }, | ||
| 1215 | #endif | ||
| 1206 | { .ctl_name = 0 } | 1216 | { .ctl_name = 0 } |
| 1207 | }; | 1217 | }; |
| 1208 | 1218 | ||
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index b5e352597cbb..cd91237dbfe3 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | 10 | ||
| 11 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
| 12 | #include <linux/time.h> | 12 | #include <linux/time.h> |
| 13 | #include <linux/timer.h> | ||
| 13 | #include <linux/timex.h> | 14 | #include <linux/timex.h> |
| 14 | #include <linux/jiffies.h> | 15 | #include <linux/jiffies.h> |
| 15 | #include <linux/hrtimer.h> | 16 | #include <linux/hrtimer.h> |
| @@ -175,12 +176,64 @@ u64 current_tick_length(void) | |||
| 175 | return tick_length; | 176 | return tick_length; |
| 176 | } | 177 | } |
| 177 | 178 | ||
| 179 | #ifdef CONFIG_GENERIC_CMOS_UPDATE | ||
| 178 | 180 | ||
| 179 | void __attribute__ ((weak)) notify_arch_cmos_timer(void) | 181 | /* Disable the cmos update - used by virtualization and embedded */ |
| 182 | int no_sync_cmos_clock __read_mostly; | ||
| 183 | |||
| 184 | static void sync_cmos_clock(unsigned long dummy); | ||
| 185 | |||
| 186 | static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0); | ||
| 187 | |||
| 188 | static void sync_cmos_clock(unsigned long dummy) | ||
| 189 | { | ||
| 190 | struct timespec now, next; | ||
| 191 | int fail = 1; | ||
| 192 | |||
| 193 | /* | ||
| 194 | * If we have an externally synchronized Linux clock, then update | ||
| 195 | * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be | ||
| 196 | * called as close as possible to 500 ms before the new second starts. | ||
| 197 | * This code is run on a timer. If the clock is set, that timer | ||
| 198 | * may not expire at the correct time. Thus, we adjust... | ||
| 199 | */ | ||
| 200 | if (!ntp_synced()) | ||
| 201 | /* | ||
| 202 | * Not synced, exit, do not restart a timer (if one is | ||
| 203 | * running, let it run out). | ||
| 204 | */ | ||
| 205 | return; | ||
| 206 | |||
| 207 | getnstimeofday(&now); | ||
| 208 | if (abs(xtime.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) | ||
| 209 | fail = update_persistent_clock(now); | ||
| 210 | |||
| 211 | next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec; | ||
| 212 | if (next.tv_nsec <= 0) | ||
| 213 | next.tv_nsec += NSEC_PER_SEC; | ||
| 214 | |||
| 215 | if (!fail) | ||
| 216 | next.tv_sec = 659; | ||
| 217 | else | ||
| 218 | next.tv_sec = 0; | ||
| 219 | |||
| 220 | if (next.tv_nsec >= NSEC_PER_SEC) { | ||
| 221 | next.tv_sec++; | ||
| 222 | next.tv_nsec -= NSEC_PER_SEC; | ||
| 223 | } | ||
| 224 | mod_timer(&sync_cmos_timer, jiffies + timespec_to_jiffies(&next)); | ||
| 225 | } | ||
| 226 | |||
| 227 | static void notify_cmos_timer(void) | ||
| 180 | { | 228 | { |
| 181 | return; | 229 | if (no_sync_cmos_clock) |
| 230 | mod_timer(&sync_cmos_timer, jiffies + 1); | ||
| 182 | } | 231 | } |
| 183 | 232 | ||
| 233 | #else | ||
| 234 | static inline void notify_cmos_timer(void) { } | ||
| 235 | #endif | ||
| 236 | |||
| 184 | /* adjtimex mainly allows reading (and writing, if superuser) of | 237 | /* adjtimex mainly allows reading (and writing, if superuser) of |
| 185 | * kernel time-keeping variables. used by xntpd. | 238 | * kernel time-keeping variables. used by xntpd. |
| 186 | */ | 239 | */ |
| @@ -345,6 +398,6 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0) | |||
| 345 | txc->stbcnt = 0; | 398 | txc->stbcnt = 0; |
| 346 | write_sequnlock_irq(&xtime_lock); | 399 | write_sequnlock_irq(&xtime_lock); |
| 347 | do_gettimeofday(&txc->time); | 400 | do_gettimeofday(&txc->time); |
| 348 | notify_arch_cmos_timer(); | 401 | notify_cmos_timer(); |
| 349 | return(result); | 402 | return(result); |
| 350 | } | 403 | } |
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 8001d37071f5..db8e0f3d409b 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c | |||
| @@ -31,6 +31,12 @@ struct tick_device tick_broadcast_device; | |||
| 31 | static cpumask_t tick_broadcast_mask; | 31 | static cpumask_t tick_broadcast_mask; |
| 32 | static DEFINE_SPINLOCK(tick_broadcast_lock); | 32 | static DEFINE_SPINLOCK(tick_broadcast_lock); |
| 33 | 33 | ||
| 34 | #ifdef CONFIG_TICK_ONESHOT | ||
| 35 | static void tick_broadcast_clear_oneshot(int cpu); | ||
| 36 | #else | ||
| 37 | static inline void tick_broadcast_clear_oneshot(int cpu) { } | ||
| 38 | #endif | ||
| 39 | |||
| 34 | /* | 40 | /* |
| 35 | * Debugging: see timer_list.c | 41 | * Debugging: see timer_list.c |
| 36 | */ | 42 | */ |
| @@ -49,7 +55,7 @@ cpumask_t *tick_get_broadcast_mask(void) | |||
| 49 | */ | 55 | */ |
| 50 | static void tick_broadcast_start_periodic(struct clock_event_device *bc) | 56 | static void tick_broadcast_start_periodic(struct clock_event_device *bc) |
| 51 | { | 57 | { |
| 52 | if (bc && bc->mode == CLOCK_EVT_MODE_SHUTDOWN) | 58 | if (bc) |
| 53 | tick_setup_periodic(bc, 1); | 59 | tick_setup_periodic(bc, 1); |
| 54 | } | 60 | } |
| 55 | 61 | ||
| @@ -99,8 +105,19 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) | |||
| 99 | cpu_set(cpu, tick_broadcast_mask); | 105 | cpu_set(cpu, tick_broadcast_mask); |
| 100 | tick_broadcast_start_periodic(tick_broadcast_device.evtdev); | 106 | tick_broadcast_start_periodic(tick_broadcast_device.evtdev); |
| 101 | ret = 1; | 107 | ret = 1; |
| 102 | } | 108 | } else { |
| 109 | /* | ||
| 110 | * When the new device is not affected by the stop | ||
| 111 | * feature and the cpu is marked in the broadcast mask | ||
| 112 | * then clear the broadcast bit. | ||
| 113 | */ | ||
| 114 | if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) { | ||
| 115 | int cpu = smp_processor_id(); | ||
| 103 | 116 | ||
| 117 | cpu_clear(cpu, tick_broadcast_mask); | ||
| 118 | tick_broadcast_clear_oneshot(cpu); | ||
| 119 | } | ||
| 120 | } | ||
| 104 | spin_unlock_irqrestore(&tick_broadcast_lock, flags); | 121 | spin_unlock_irqrestore(&tick_broadcast_lock, flags); |
| 105 | return ret; | 122 | return ret; |
| 106 | } | 123 | } |
| @@ -299,7 +316,7 @@ void tick_suspend_broadcast(void) | |||
| 299 | spin_lock_irqsave(&tick_broadcast_lock, flags); | 316 | spin_lock_irqsave(&tick_broadcast_lock, flags); |
| 300 | 317 | ||
| 301 | bc = tick_broadcast_device.evtdev; | 318 | bc = tick_broadcast_device.evtdev; |
| 302 | if (bc && tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) | 319 | if (bc) |
| 303 | clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); | 320 | clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN); |
| 304 | 321 | ||
| 305 | spin_unlock_irqrestore(&tick_broadcast_lock, flags); | 322 | spin_unlock_irqrestore(&tick_broadcast_lock, flags); |
| @@ -316,6 +333,8 @@ int tick_resume_broadcast(void) | |||
| 316 | bc = tick_broadcast_device.evtdev; | 333 | bc = tick_broadcast_device.evtdev; |
| 317 | 334 | ||
| 318 | if (bc) { | 335 | if (bc) { |
| 336 | clockevents_set_mode(bc, CLOCK_EVT_MODE_RESUME); | ||
| 337 | |||
| 319 | switch (tick_broadcast_device.mode) { | 338 | switch (tick_broadcast_device.mode) { |
| 320 | case TICKDEV_MODE_PERIODIC: | 339 | case TICKDEV_MODE_PERIODIC: |
| 321 | if(!cpus_empty(tick_broadcast_mask)) | 340 | if(!cpus_empty(tick_broadcast_mask)) |
| @@ -485,6 +504,16 @@ out: | |||
| 485 | spin_unlock_irqrestore(&tick_broadcast_lock, flags); | 504 | spin_unlock_irqrestore(&tick_broadcast_lock, flags); |
| 486 | } | 505 | } |
| 487 | 506 | ||
| 507 | /* | ||
| 508 | * Reset the one shot broadcast for a cpu | ||
| 509 | * | ||
| 510 | * Called with tick_broadcast_lock held | ||
| 511 | */ | ||
| 512 | static void tick_broadcast_clear_oneshot(int cpu) | ||
| 513 | { | ||
| 514 | cpu_clear(cpu, tick_broadcast_oneshot_mask); | ||
| 515 | } | ||
| 516 | |||
| 488 | /** | 517 | /** |
| 489 | * tick_broadcast_setup_highres - setup the broadcast device for highres | 518 | * tick_broadcast_setup_highres - setup the broadcast device for highres |
| 490 | */ | 519 | */ |
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c index a96ec9ab3454..77a21abc8716 100644 --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c | |||
| @@ -318,12 +318,17 @@ static void tick_resume(void) | |||
| 318 | { | 318 | { |
| 319 | struct tick_device *td = &__get_cpu_var(tick_cpu_device); | 319 | struct tick_device *td = &__get_cpu_var(tick_cpu_device); |
| 320 | unsigned long flags; | 320 | unsigned long flags; |
| 321 | int broadcast = tick_resume_broadcast(); | ||
| 321 | 322 | ||
| 322 | spin_lock_irqsave(&tick_device_lock, flags); | 323 | spin_lock_irqsave(&tick_device_lock, flags); |
| 323 | if (td->mode == TICKDEV_MODE_PERIODIC) | 324 | clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_RESUME); |
| 324 | tick_setup_periodic(td->evtdev, 0); | 325 | |
| 325 | else | 326 | if (!broadcast) { |
| 326 | tick_resume_oneshot(); | 327 | if (td->mode == TICKDEV_MODE_PERIODIC) |
| 328 | tick_setup_periodic(td->evtdev, 0); | ||
| 329 | else | ||
| 330 | tick_resume_oneshot(); | ||
| 331 | } | ||
| 327 | spin_unlock_irqrestore(&tick_device_lock, flags); | 332 | spin_unlock_irqrestore(&tick_device_lock, flags); |
| 328 | } | 333 | } |
| 329 | 334 | ||
| @@ -360,8 +365,7 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason, | |||
| 360 | break; | 365 | break; |
| 361 | 366 | ||
| 362 | case CLOCK_EVT_NOTIFY_RESUME: | 367 | case CLOCK_EVT_NOTIFY_RESUME: |
| 363 | if (!tick_resume_broadcast()) | 368 | tick_resume(); |
| 364 | tick_resume(); | ||
| 365 | break; | 369 | break; |
| 366 | 370 | ||
| 367 | default: | 371 | default: |
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c index f6997ab0c3c9..0258d3115d54 100644 --- a/kernel/time/tick-oneshot.c +++ b/kernel/time/tick-oneshot.c | |||
| @@ -73,8 +73,21 @@ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)) | |||
| 73 | struct clock_event_device *dev = td->evtdev; | 73 | struct clock_event_device *dev = td->evtdev; |
| 74 | 74 | ||
| 75 | if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) || | 75 | if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) || |
| 76 | !tick_device_is_functional(dev)) | 76 | !tick_device_is_functional(dev)) { |
| 77 | |||
| 78 | printk(KERN_INFO "Clockevents: " | ||
| 79 | "could not switch to one-shot mode:"); | ||
| 80 | if (!dev) { | ||
| 81 | printk(" no tick device\n"); | ||
| 82 | } else { | ||
| 83 | if (!tick_device_is_functional(dev)) | ||
| 84 | printk(" %s is not functional.\n", dev->name); | ||
| 85 | else | ||
| 86 | printk(" %s does not support one-shot mode.\n", | ||
| 87 | dev->name); | ||
| 88 | } | ||
| 77 | return -EINVAL; | 89 | return -EINVAL; |
| 90 | } | ||
| 78 | 91 | ||
| 79 | td->mode = TICKDEV_MODE_ONESHOT; | 92 | td->mode = TICKDEV_MODE_ONESHOT; |
| 80 | dev->event_handler = handler; | 93 | dev->event_handler = handler; |
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 52db9e3c526e..b416995b9757 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c | |||
| @@ -546,6 +546,7 @@ void tick_setup_sched_timer(void) | |||
| 546 | { | 546 | { |
| 547 | struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); | 547 | struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); |
| 548 | ktime_t now = ktime_get(); | 548 | ktime_t now = ktime_get(); |
| 549 | u64 offset; | ||
| 549 | 550 | ||
| 550 | /* | 551 | /* |
| 551 | * Emulate tick processing via per-CPU hrtimers: | 552 | * Emulate tick processing via per-CPU hrtimers: |
| @@ -554,8 +555,12 @@ void tick_setup_sched_timer(void) | |||
| 554 | ts->sched_timer.function = tick_sched_timer; | 555 | ts->sched_timer.function = tick_sched_timer; |
| 555 | ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ; | 556 | ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ; |
| 556 | 557 | ||
| 557 | /* Get the next period */ | 558 | /* Get the next period (per cpu) */ |
| 558 | ts->sched_timer.expires = tick_init_jiffy_update(); | 559 | ts->sched_timer.expires = tick_init_jiffy_update(); |
| 560 | offset = ktime_to_ns(tick_period) >> 1; | ||
| 561 | do_div(offset, NR_CPUS); | ||
| 562 | offset *= smp_processor_id(); | ||
| 563 | ts->sched_timer.expires = ktime_add_ns(ts->sched_timer.expires, offset); | ||
| 559 | 564 | ||
| 560 | for (;;) { | 565 | for (;;) { |
| 561 | hrtimer_forward(&ts->sched_timer, now, tick_period); | 566 | hrtimer_forward(&ts->sched_timer, now, tick_period); |
