diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/atags.c | 83 | ||||
-rw-r--r-- | arch/arm/kernel/ecard.c | 13 | ||||
-rw-r--r-- | arch/arm/kernel/ecard.h | 13 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/stacktrace.c | 34 | ||||
-rw-r--r-- | arch/arm/kernel/time.c | 120 |
6 files changed, 90 insertions, 177 deletions
diff --git a/arch/arm/kernel/atags.c b/arch/arm/kernel/atags.c index 64c420805e6f..42a1a1415fa6 100644 --- a/arch/arm/kernel/atags.c +++ b/arch/arm/kernel/atags.c | |||
@@ -1,5 +1,4 @@ | |||
1 | #include <linux/slab.h> | 1 | #include <linux/slab.h> |
2 | #include <linux/kexec.h> | ||
3 | #include <linux/proc_fs.h> | 2 | #include <linux/proc_fs.h> |
4 | #include <asm/setup.h> | 3 | #include <asm/setup.h> |
5 | #include <asm/types.h> | 4 | #include <asm/types.h> |
@@ -7,9 +6,8 @@ | |||
7 | 6 | ||
8 | struct buffer { | 7 | struct buffer { |
9 | size_t size; | 8 | size_t size; |
10 | char *data; | 9 | char data[]; |
11 | }; | 10 | }; |
12 | static struct buffer tags_buffer; | ||
13 | 11 | ||
14 | static int | 12 | static int |
15 | read_buffer(char* page, char** start, off_t off, int count, | 13 | read_buffer(char* page, char** start, off_t off, int count, |
@@ -29,58 +27,57 @@ read_buffer(char* page, char** start, off_t off, int count, | |||
29 | return count; | 27 | return count; |
30 | } | 28 | } |
31 | 29 | ||
32 | 30 | #define BOOT_PARAMS_SIZE 1536 | |
33 | static int | 31 | static char __initdata atags_copy[BOOT_PARAMS_SIZE]; |
34 | create_proc_entries(void) | ||
35 | { | ||
36 | struct proc_dir_entry* tags_entry; | ||
37 | |||
38 | tags_entry = create_proc_read_entry("atags", 0400, NULL, read_buffer, &tags_buffer); | ||
39 | if (!tags_entry) | ||
40 | return -ENOMEM; | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | |||
46 | static char __initdata atags_copy_buf[KEXEC_BOOT_PARAMS_SIZE]; | ||
47 | static char __initdata *atags_copy; | ||
48 | 32 | ||
49 | void __init save_atags(const struct tag *tags) | 33 | void __init save_atags(const struct tag *tags) |
50 | { | 34 | { |
51 | atags_copy = atags_copy_buf; | 35 | memcpy(atags_copy, tags, sizeof(atags_copy)); |
52 | memcpy(atags_copy, tags, KEXEC_BOOT_PARAMS_SIZE); | ||
53 | } | 36 | } |
54 | 37 | ||
55 | |||
56 | static int __init init_atags_procfs(void) | 38 | static int __init init_atags_procfs(void) |
57 | { | 39 | { |
58 | struct tag *tag; | 40 | /* |
59 | int error; | 41 | * This cannot go into save_atags() because kmalloc and proc don't work |
42 | * yet when it is called. | ||
43 | */ | ||
44 | struct proc_dir_entry *tags_entry; | ||
45 | struct tag *tag = (struct tag *)atags_copy; | ||
46 | struct buffer *b; | ||
47 | size_t size; | ||
60 | 48 | ||
61 | if (!atags_copy) { | 49 | if (tag->hdr.tag != ATAG_CORE) { |
62 | printk(KERN_WARNING "Exporting ATAGs: No saved tags found\n"); | 50 | printk(KERN_INFO "No ATAGs?"); |
63 | return -EIO; | 51 | return -EINVAL; |
64 | } | 52 | } |
65 | 53 | ||
66 | for (tag = (struct tag *) atags_copy; tag->hdr.size; tag = tag_next(tag)) | 54 | for (; tag->hdr.size; tag = tag_next(tag)) |
67 | ; | 55 | ; |
68 | 56 | ||
69 | tags_buffer.size = ((char *) tag - atags_copy) + sizeof(tag->hdr); | 57 | /* include the terminating ATAG_NONE */ |
70 | tags_buffer.data = kmalloc(tags_buffer.size, GFP_KERNEL); | 58 | size = (char *)tag - atags_copy + sizeof(struct tag_header); |
71 | if (tags_buffer.data == NULL) | ||
72 | return -ENOMEM; | ||
73 | memcpy(tags_buffer.data, atags_copy, tags_buffer.size); | ||
74 | |||
75 | error = create_proc_entries(); | ||
76 | if (error) { | ||
77 | printk(KERN_ERR "Exporting ATAGs: not enough memory\n"); | ||
78 | kfree(tags_buffer.data); | ||
79 | tags_buffer.size = 0; | ||
80 | tags_buffer.data = NULL; | ||
81 | } | ||
82 | 59 | ||
83 | return error; | 60 | WARN_ON(tag->hdr.tag != ATAG_NONE); |
84 | } | 61 | |
62 | b = kmalloc(sizeof(*b) + size, GFP_KERNEL); | ||
63 | if (!b) | ||
64 | goto nomem; | ||
85 | 65 | ||
66 | b->size = size; | ||
67 | memcpy(b->data, atags_copy, size); | ||
68 | |||
69 | tags_entry = create_proc_read_entry("atags", 0400, | ||
70 | NULL, read_buffer, b); | ||
71 | |||
72 | if (!tags_entry) | ||
73 | goto nomem; | ||
74 | |||
75 | return 0; | ||
76 | |||
77 | nomem: | ||
78 | kfree(b); | ||
79 | printk(KERN_ERR "Exporting ATAGs: not enough memory\n"); | ||
80 | |||
81 | return -ENOMEM; | ||
82 | } | ||
86 | arch_initcall(init_atags_procfs); | 83 | arch_initcall(init_atags_procfs); |
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index a53c0aba5c14..8bfd299bfe77 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c | |||
@@ -680,7 +680,7 @@ static int __init ecard_probeirqhw(void) | |||
680 | #define IO_EC_MEMC8_BASE 0 | 680 | #define IO_EC_MEMC8_BASE 0 |
681 | #endif | 681 | #endif |
682 | 682 | ||
683 | unsigned int __ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) | 683 | static unsigned int __ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) |
684 | { | 684 | { |
685 | unsigned long address = 0; | 685 | unsigned long address = 0; |
686 | int slot = ec->slot_no; | 686 | int slot = ec->slot_no; |
@@ -1002,7 +1002,7 @@ ecard_probe(int slot, card_type_t type) | |||
1002 | } | 1002 | } |
1003 | 1003 | ||
1004 | rc = -ENODEV; | 1004 | rc = -ENODEV; |
1005 | if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0) | 1005 | if ((ec->podaddr = __ecard_address(ec, type, ECARD_SYNC)) == 0) |
1006 | goto nodev; | 1006 | goto nodev; |
1007 | 1007 | ||
1008 | cid.r_zero = 1; | 1008 | cid.r_zero = 1; |
@@ -1141,10 +1141,10 @@ static int ecard_drv_probe(struct device *dev) | |||
1141 | 1141 | ||
1142 | id = ecard_match_device(drv->id_table, ec); | 1142 | id = ecard_match_device(drv->id_table, ec); |
1143 | 1143 | ||
1144 | ecard_claim(ec); | 1144 | ec->claimed = 1; |
1145 | ret = drv->probe(ec, id); | 1145 | ret = drv->probe(ec, id); |
1146 | if (ret) | 1146 | if (ret) |
1147 | ecard_release(ec); | 1147 | ec->claimed = 0; |
1148 | return ret; | 1148 | return ret; |
1149 | } | 1149 | } |
1150 | 1150 | ||
@@ -1154,7 +1154,7 @@ static int ecard_drv_remove(struct device *dev) | |||
1154 | struct ecard_driver *drv = ECARD_DRV(dev->driver); | 1154 | struct ecard_driver *drv = ECARD_DRV(dev->driver); |
1155 | 1155 | ||
1156 | drv->remove(ec); | 1156 | drv->remove(ec); |
1157 | ecard_release(ec); | 1157 | ec->claimed = 0; |
1158 | 1158 | ||
1159 | /* | 1159 | /* |
1160 | * Restore the default operations. We ensure that the | 1160 | * Restore the default operations. We ensure that the |
@@ -1182,7 +1182,7 @@ static void ecard_drv_shutdown(struct device *dev) | |||
1182 | if (dev->driver) { | 1182 | if (dev->driver) { |
1183 | if (drv->shutdown) | 1183 | if (drv->shutdown) |
1184 | drv->shutdown(ec); | 1184 | drv->shutdown(ec); |
1185 | ecard_release(ec); | 1185 | ec->claimed = 0; |
1186 | } | 1186 | } |
1187 | 1187 | ||
1188 | /* | 1188 | /* |
@@ -1239,7 +1239,6 @@ static int ecard_bus_init(void) | |||
1239 | postcore_initcall(ecard_bus_init); | 1239 | postcore_initcall(ecard_bus_init); |
1240 | 1240 | ||
1241 | EXPORT_SYMBOL(ecard_readchunk); | 1241 | EXPORT_SYMBOL(ecard_readchunk); |
1242 | EXPORT_SYMBOL(__ecard_address); | ||
1243 | EXPORT_SYMBOL(ecard_register_driver); | 1242 | EXPORT_SYMBOL(ecard_register_driver); |
1244 | EXPORT_SYMBOL(ecard_remove_driver); | 1243 | EXPORT_SYMBOL(ecard_remove_driver); |
1245 | EXPORT_SYMBOL(ecard_bus_type); | 1244 | EXPORT_SYMBOL(ecard_bus_type); |
diff --git a/arch/arm/kernel/ecard.h b/arch/arm/kernel/ecard.h index d7c2dacf935d..4642d436be2a 100644 --- a/arch/arm/kernel/ecard.h +++ b/arch/arm/kernel/ecard.h | |||
@@ -54,3 +54,16 @@ struct ex_chunk_dir { | |||
54 | #define c_len(x) ((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16)) | 54 | #define c_len(x) ((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16)) |
55 | #define c_start(x) ((x)->r_start) | 55 | #define c_start(x) ((x)->r_start) |
56 | }; | 56 | }; |
57 | |||
58 | typedef enum ecard_type { /* Cards address space */ | ||
59 | ECARD_IOC, | ||
60 | ECARD_MEMC, | ||
61 | ECARD_EASI | ||
62 | } card_type_t; | ||
63 | |||
64 | typedef enum { /* Speed for ECARD_IOC space */ | ||
65 | ECARD_SLOW = 0, | ||
66 | ECARD_MEDIUM = 1, | ||
67 | ECARD_FAST = 2, | ||
68 | ECARD_SYNC = 3 | ||
69 | } card_speed_t; | ||
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 46bf2ede6128..199b3680118b 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -133,10 +133,8 @@ static void default_idle(void) | |||
133 | cpu_relax(); | 133 | cpu_relax(); |
134 | else { | 134 | else { |
135 | local_irq_disable(); | 135 | local_irq_disable(); |
136 | if (!need_resched()) { | 136 | if (!need_resched()) |
137 | timer_dyn_reprogram(); | ||
138 | arch_idle(); | 137 | arch_idle(); |
139 | } | ||
140 | local_irq_enable(); | 138 | local_irq_enable(); |
141 | } | 139 | } |
142 | } | 140 | } |
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c index ae31deb2d065..90e0c35ae60d 100644 --- a/arch/arm/kernel/stacktrace.c +++ b/arch/arm/kernel/stacktrace.c | |||
@@ -36,6 +36,7 @@ EXPORT_SYMBOL(walk_stackframe); | |||
36 | #ifdef CONFIG_STACKTRACE | 36 | #ifdef CONFIG_STACKTRACE |
37 | struct stack_trace_data { | 37 | struct stack_trace_data { |
38 | struct stack_trace *trace; | 38 | struct stack_trace *trace; |
39 | unsigned int no_sched_functions; | ||
39 | unsigned int skip; | 40 | unsigned int skip; |
40 | }; | 41 | }; |
41 | 42 | ||
@@ -43,27 +44,52 @@ static int save_trace(struct stackframe *frame, void *d) | |||
43 | { | 44 | { |
44 | struct stack_trace_data *data = d; | 45 | struct stack_trace_data *data = d; |
45 | struct stack_trace *trace = data->trace; | 46 | struct stack_trace *trace = data->trace; |
47 | unsigned long addr = frame->lr; | ||
46 | 48 | ||
49 | if (data->no_sched_functions && in_sched_functions(addr)) | ||
50 | return 0; | ||
47 | if (data->skip) { | 51 | if (data->skip) { |
48 | data->skip--; | 52 | data->skip--; |
49 | return 0; | 53 | return 0; |
50 | } | 54 | } |
51 | 55 | ||
52 | trace->entries[trace->nr_entries++] = frame->lr; | 56 | trace->entries[trace->nr_entries++] = addr; |
53 | 57 | ||
54 | return trace->nr_entries >= trace->max_entries; | 58 | return trace->nr_entries >= trace->max_entries; |
55 | } | 59 | } |
56 | 60 | ||
57 | void save_stack_trace(struct stack_trace *trace) | 61 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
58 | { | 62 | { |
59 | struct stack_trace_data data; | 63 | struct stack_trace_data data; |
60 | unsigned long fp, base; | 64 | unsigned long fp, base; |
61 | 65 | ||
62 | data.trace = trace; | 66 | data.trace = trace; |
63 | data.skip = trace->skip; | 67 | data.skip = trace->skip; |
64 | base = (unsigned long)task_stack_page(current); | 68 | base = (unsigned long)task_stack_page(tsk); |
65 | asm("mov %0, fp" : "=r" (fp)); | 69 | |
70 | if (tsk != current) { | ||
71 | #ifdef CONFIG_SMP | ||
72 | /* | ||
73 | * What guarantees do we have here that 'tsk' | ||
74 | * is not running on another CPU? | ||
75 | */ | ||
76 | BUG(); | ||
77 | #else | ||
78 | data.no_sched_functions = 1; | ||
79 | fp = thread_saved_fp(tsk); | ||
80 | #endif | ||
81 | } else { | ||
82 | data.no_sched_functions = 0; | ||
83 | asm("mov %0, fp" : "=r" (fp)); | ||
84 | } | ||
66 | 85 | ||
67 | walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data); | 86 | walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data); |
87 | if (trace->nr_entries < trace->max_entries) | ||
88 | trace->entries[trace->nr_entries++] = ULONG_MAX; | ||
89 | } | ||
90 | |||
91 | void save_stack_trace(struct stack_trace *trace) | ||
92 | { | ||
93 | save_stack_trace_tsk(current, trace); | ||
68 | } | 94 | } |
69 | #endif | 95 | #endif |
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index b5867eca1d0b..cc5145b28e7f 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c | |||
@@ -365,108 +365,6 @@ static struct sysdev_class timer_sysclass = { | |||
365 | .resume = timer_resume, | 365 | .resume = timer_resume, |
366 | }; | 366 | }; |
367 | 367 | ||
368 | #ifdef CONFIG_NO_IDLE_HZ | ||
369 | static int timer_dyn_tick_enable(void) | ||
370 | { | ||
371 | struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick; | ||
372 | unsigned long flags; | ||
373 | int ret = -ENODEV; | ||
374 | |||
375 | if (dyn_tick) { | ||
376 | spin_lock_irqsave(&dyn_tick->lock, flags); | ||
377 | ret = 0; | ||
378 | if (!(dyn_tick->state & DYN_TICK_ENABLED)) { | ||
379 | ret = dyn_tick->enable(); | ||
380 | |||
381 | if (ret == 0) | ||
382 | dyn_tick->state |= DYN_TICK_ENABLED; | ||
383 | } | ||
384 | spin_unlock_irqrestore(&dyn_tick->lock, flags); | ||
385 | } | ||
386 | |||
387 | return ret; | ||
388 | } | ||
389 | |||
390 | static int timer_dyn_tick_disable(void) | ||
391 | { | ||
392 | struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick; | ||
393 | unsigned long flags; | ||
394 | int ret = -ENODEV; | ||
395 | |||
396 | if (dyn_tick) { | ||
397 | spin_lock_irqsave(&dyn_tick->lock, flags); | ||
398 | ret = 0; | ||
399 | if (dyn_tick->state & DYN_TICK_ENABLED) { | ||
400 | ret = dyn_tick->disable(); | ||
401 | |||
402 | if (ret == 0) | ||
403 | dyn_tick->state &= ~DYN_TICK_ENABLED; | ||
404 | } | ||
405 | spin_unlock_irqrestore(&dyn_tick->lock, flags); | ||
406 | } | ||
407 | |||
408 | return ret; | ||
409 | } | ||
410 | |||
411 | /* | ||
412 | * Reprogram the system timer for at least the calculated time interval. | ||
413 | * This function should be called from the idle thread with IRQs disabled, | ||
414 | * immediately before sleeping. | ||
415 | */ | ||
416 | void timer_dyn_reprogram(void) | ||
417 | { | ||
418 | struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick; | ||
419 | unsigned long next, seq, flags; | ||
420 | |||
421 | if (!dyn_tick) | ||
422 | return; | ||
423 | |||
424 | spin_lock_irqsave(&dyn_tick->lock, flags); | ||
425 | if (dyn_tick->state & DYN_TICK_ENABLED) { | ||
426 | next = next_timer_interrupt(); | ||
427 | do { | ||
428 | seq = read_seqbegin(&xtime_lock); | ||
429 | dyn_tick->reprogram(next - jiffies); | ||
430 | } while (read_seqretry(&xtime_lock, seq)); | ||
431 | } | ||
432 | spin_unlock_irqrestore(&dyn_tick->lock, flags); | ||
433 | } | ||
434 | |||
435 | static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf) | ||
436 | { | ||
437 | return sprintf(buf, "%i\n", | ||
438 | (system_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1); | ||
439 | } | ||
440 | |||
441 | static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf, | ||
442 | size_t count) | ||
443 | { | ||
444 | unsigned int enable = simple_strtoul(buf, NULL, 2); | ||
445 | |||
446 | if (enable) | ||
447 | timer_dyn_tick_enable(); | ||
448 | else | ||
449 | timer_dyn_tick_disable(); | ||
450 | |||
451 | return count; | ||
452 | } | ||
453 | static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick); | ||
454 | |||
455 | /* | ||
456 | * dyntick=enable|disable | ||
457 | */ | ||
458 | static char dyntick_str[4] __initdata = ""; | ||
459 | |||
460 | static int __init dyntick_setup(char *str) | ||
461 | { | ||
462 | if (str) | ||
463 | strlcpy(dyntick_str, str, sizeof(dyntick_str)); | ||
464 | return 1; | ||
465 | } | ||
466 | |||
467 | __setup("dyntick=", dyntick_setup); | ||
468 | #endif | ||
469 | |||
470 | static int __init timer_init_sysfs(void) | 368 | static int __init timer_init_sysfs(void) |
471 | { | 369 | { |
472 | int ret = sysdev_class_register(&timer_sysclass); | 370 | int ret = sysdev_class_register(&timer_sysclass); |
@@ -475,19 +373,6 @@ static int __init timer_init_sysfs(void) | |||
475 | ret = sysdev_register(&system_timer->dev); | 373 | ret = sysdev_register(&system_timer->dev); |
476 | } | 374 | } |
477 | 375 | ||
478 | #ifdef CONFIG_NO_IDLE_HZ | ||
479 | if (ret == 0 && system_timer->dyn_tick) { | ||
480 | ret = sysdev_create_file(&system_timer->dev, &attr_dyn_tick); | ||
481 | |||
482 | /* | ||
483 | * Turn on dynamic tick after calibrate delay | ||
484 | * for correct bogomips | ||
485 | */ | ||
486 | if (ret == 0 && dyntick_str[0] == 'e') | ||
487 | ret = timer_dyn_tick_enable(); | ||
488 | } | ||
489 | #endif | ||
490 | |||
491 | return ret; | 376 | return ret; |
492 | } | 377 | } |
493 | 378 | ||
@@ -500,10 +385,5 @@ void __init time_init(void) | |||
500 | system_timer->offset = dummy_gettimeoffset; | 385 | system_timer->offset = dummy_gettimeoffset; |
501 | #endif | 386 | #endif |
502 | system_timer->init(); | 387 | system_timer->init(); |
503 | |||
504 | #ifdef CONFIG_NO_IDLE_HZ | ||
505 | if (system_timer->dyn_tick) | ||
506 | spin_lock_init(&system_timer->dyn_tick->lock); | ||
507 | #endif | ||
508 | } | 388 | } |
509 | 389 | ||