diff options
Diffstat (limited to 'kernel/softirq.c')
| -rw-r--r-- | kernel/softirq.c | 85 |
1 files changed, 79 insertions, 6 deletions
diff --git a/kernel/softirq.c b/kernel/softirq.c index b525dd348511..eb5e131a0485 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c | |||
| @@ -24,7 +24,9 @@ | |||
| 24 | #include <linux/ftrace.h> | 24 | #include <linux/ftrace.h> |
| 25 | #include <linux/smp.h> | 25 | #include <linux/smp.h> |
| 26 | #include <linux/tick.h> | 26 | #include <linux/tick.h> |
| 27 | #include <trace/irq.h> | 27 | |
| 28 | #define CREATE_TRACE_POINTS | ||
| 29 | #include <trace/events/irq.h> | ||
| 28 | 30 | ||
| 29 | #include <asm/irq.h> | 31 | #include <asm/irq.h> |
| 30 | /* | 32 | /* |
| @@ -186,9 +188,6 @@ EXPORT_SYMBOL(local_bh_enable_ip); | |||
| 186 | */ | 188 | */ |
| 187 | #define MAX_SOFTIRQ_RESTART 10 | 189 | #define MAX_SOFTIRQ_RESTART 10 |
| 188 | 190 | ||
| 189 | DEFINE_TRACE(softirq_entry); | ||
| 190 | DEFINE_TRACE(softirq_exit); | ||
| 191 | |||
| 192 | asmlinkage void __do_softirq(void) | 191 | asmlinkage void __do_softirq(void) |
| 193 | { | 192 | { |
| 194 | struct softirq_action *h; | 193 | struct softirq_action *h; |
| @@ -214,6 +213,7 @@ restart: | |||
| 214 | do { | 213 | do { |
| 215 | if (pending & 1) { | 214 | if (pending & 1) { |
| 216 | int prev_count = preempt_count(); | 215 | int prev_count = preempt_count(); |
| 216 | kstat_incr_softirqs_this_cpu(h - softirq_vec); | ||
| 217 | 217 | ||
| 218 | trace_softirq_entry(h, softirq_vec); | 218 | trace_softirq_entry(h, softirq_vec); |
| 219 | h->action(h); | 219 | h->action(h); |
| @@ -345,7 +345,9 @@ void open_softirq(int nr, void (*action)(struct softirq_action *)) | |||
| 345 | softirq_vec[nr].action = action; | 345 | softirq_vec[nr].action = action; |
| 346 | } | 346 | } |
| 347 | 347 | ||
| 348 | /* Tasklets */ | 348 | /* |
| 349 | * Tasklets | ||
| 350 | */ | ||
| 349 | struct tasklet_head | 351 | struct tasklet_head |
| 350 | { | 352 | { |
| 351 | struct tasklet_struct *head; | 353 | struct tasklet_struct *head; |
| @@ -383,6 +385,17 @@ void __tasklet_hi_schedule(struct tasklet_struct *t) | |||
| 383 | 385 | ||
| 384 | EXPORT_SYMBOL(__tasklet_hi_schedule); | 386 | EXPORT_SYMBOL(__tasklet_hi_schedule); |
| 385 | 387 | ||
| 388 | void __tasklet_hi_schedule_first(struct tasklet_struct *t) | ||
| 389 | { | ||
| 390 | BUG_ON(!irqs_disabled()); | ||
| 391 | |||
| 392 | t->next = __get_cpu_var(tasklet_hi_vec).head; | ||
| 393 | __get_cpu_var(tasklet_hi_vec).head = t; | ||
| 394 | __raise_softirq_irqoff(HI_SOFTIRQ); | ||
| 395 | } | ||
| 396 | |||
| 397 | EXPORT_SYMBOL(__tasklet_hi_schedule_first); | ||
| 398 | |||
| 386 | static void tasklet_action(struct softirq_action *a) | 399 | static void tasklet_action(struct softirq_action *a) |
| 387 | { | 400 | { |
| 388 | struct tasklet_struct *list; | 401 | struct tasklet_struct *list; |
| @@ -482,6 +495,66 @@ void tasklet_kill(struct tasklet_struct *t) | |||
| 482 | 495 | ||
| 483 | EXPORT_SYMBOL(tasklet_kill); | 496 | EXPORT_SYMBOL(tasklet_kill); |
| 484 | 497 | ||
| 498 | /* | ||
| 499 | * tasklet_hrtimer | ||
| 500 | */ | ||
| 501 | |||
| 502 | /* | ||
| 503 | * The trampoline is called when the hrtimer expires. If this is | ||
| 504 | * called from the hrtimer interrupt then we schedule the tasklet as | ||
| 505 | * the timer callback function expects to run in softirq context. If | ||
| 506 | * it's called in softirq context anyway (i.e. high resolution timers | ||
| 507 | * disabled) then the hrtimer callback is called right away. | ||
| 508 | */ | ||
| 509 | static enum hrtimer_restart __hrtimer_tasklet_trampoline(struct hrtimer *timer) | ||
| 510 | { | ||
| 511 | struct tasklet_hrtimer *ttimer = | ||
| 512 | container_of(timer, struct tasklet_hrtimer, timer); | ||
| 513 | |||
| 514 | if (hrtimer_is_hres_active(timer)) { | ||
| 515 | tasklet_hi_schedule(&ttimer->tasklet); | ||
| 516 | return HRTIMER_NORESTART; | ||
| 517 | } | ||
| 518 | return ttimer->function(timer); | ||
| 519 | } | ||
| 520 | |||
| 521 | /* | ||
| 522 | * Helper function which calls the hrtimer callback from | ||
| 523 | * tasklet/softirq context | ||
| 524 | */ | ||
| 525 | static void __tasklet_hrtimer_trampoline(unsigned long data) | ||
| 526 | { | ||
| 527 | struct tasklet_hrtimer *ttimer = (void *)data; | ||
| 528 | enum hrtimer_restart restart; | ||
| 529 | |||
| 530 | restart = ttimer->function(&ttimer->timer); | ||
| 531 | if (restart != HRTIMER_NORESTART) | ||
| 532 | hrtimer_restart(&ttimer->timer); | ||
| 533 | } | ||
| 534 | |||
| 535 | /** | ||
| 536 | * tasklet_hrtimer_init - Init a tasklet/hrtimer combo for softirq callbacks | ||
| 537 | * @ttimer: tasklet_hrtimer which is initialized | ||
| 538 | * @function: hrtimer callback funtion which gets called from softirq context | ||
| 539 | * @which_clock: clock id (CLOCK_MONOTONIC/CLOCK_REALTIME) | ||
| 540 | * @mode: hrtimer mode (HRTIMER_MODE_ABS/HRTIMER_MODE_REL) | ||
| 541 | */ | ||
| 542 | void tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer, | ||
| 543 | enum hrtimer_restart (*function)(struct hrtimer *), | ||
| 544 | clockid_t which_clock, enum hrtimer_mode mode) | ||
| 545 | { | ||
| 546 | hrtimer_init(&ttimer->timer, which_clock, mode); | ||
| 547 | ttimer->timer.function = __hrtimer_tasklet_trampoline; | ||
| 548 | tasklet_init(&ttimer->tasklet, __tasklet_hrtimer_trampoline, | ||
| 549 | (unsigned long)ttimer); | ||
| 550 | ttimer->function = function; | ||
| 551 | } | ||
| 552 | EXPORT_SYMBOL_GPL(tasklet_hrtimer_init); | ||
| 553 | |||
| 554 | /* | ||
| 555 | * Remote softirq bits | ||
| 556 | */ | ||
| 557 | |||
| 485 | DEFINE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list); | 558 | DEFINE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list); |
| 486 | EXPORT_PER_CPU_SYMBOL(softirq_work_list); | 559 | EXPORT_PER_CPU_SYMBOL(softirq_work_list); |
| 487 | 560 | ||
| @@ -828,7 +901,7 @@ int __init __weak arch_early_irq_init(void) | |||
| 828 | return 0; | 901 | return 0; |
| 829 | } | 902 | } |
| 830 | 903 | ||
| 831 | int __weak arch_init_chip_data(struct irq_desc *desc, int cpu) | 904 | int __weak arch_init_chip_data(struct irq_desc *desc, int node) |
| 832 | { | 905 | { |
| 833 | return 0; | 906 | return 0; |
| 834 | } | 907 | } |
