1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/config.h>
21#include <linux/errno.h>
22#include <linux/module.h>
23#include <linux/signal.h>
24#include <linux/sched.h>
25#include <linux/ioport.h>
26#include <linux/interrupt.h>
27#include <linux/timex.h>
28#include <linux/slab.h>
29#include <linux/random.h>
30#include <linux/smp_lock.h>
31#include <linux/init.h>
32#include <linux/kernel_stat.h>
33#include <linux/irq.h>
34#include <linux/proc_fs.h>
35#include <linux/seq_file.h>
36#include <linux/kallsyms.h>
37
38#include <asm/atomic.h>
39#include <asm/io.h>
40#include <asm/smp.h>
41#include <asm/system.h>
42#include <asm/bitops.h>
43#include <asm/uaccess.h>
44#include <asm/delay.h>
45#include <asm/desc.h>
46#include <asm/irq.h>
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
68 [0 ... NR_IRQS-1] = {
69 .handler = &no_irq_type,
70 .lock = SPIN_LOCK_UNLOCKED
71 }
72};
73
74static void register_irq_proc (unsigned int irq);
75
76
77
78
79#ifdef CONFIG_4KSTACKS
80union irq_ctx *hardirq_ctx[NR_CPUS];
81union irq_ctx *softirq_ctx[NR_CPUS];
82#endif
83
84
85
86
87
88irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
89{ return IRQ_NONE; }
90
91
92
93
94
95static void enable_none(unsigned int irq) { }
96static unsigned int startup_none(unsigned int irq) { return 0; }
97static void disable_none(unsigned int irq) { }
98static void ack_none(unsigned int irq)
99{
100
101
102
103
104
105#ifdef CONFIG_X86
106 printk("unexpected IRQ trap at vector %02x\n", irq);
107#ifdef CONFIG_X86_LOCAL_APIC
108
109
110
111
112
113
114
115
116 ack_APIC_irq();
117#endif
118#endif
119}
120
121
122#define shutdown_none disable_none
123#define end_none enable_none
124
125struct hw_interrupt_type no_irq_type = {
126 "none",
127 startup_none,
128 shutdown_none,
129 enable_none,
130 disable_none,
131 ack_none,
132 end_none
133};
134
135atomic_t irq_err_count;
136#if defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG)
137atomic_t irq_mis_count;
138#endif
139
140
141
142
143
144int show_interrupts(struct seq_file *p, void *v)
145{
146 int i = *(loff_t *) v, j;
147 struct irqaction * action;
148 unsigned long flags;
149
150 if (i == 0) {
151 seq_printf(p, " ");
152 for (j=0; j<NR_CPUS; j++)
153 if (cpu_online(j))
154 seq_printf(p, "CPU%d ",j);
155 seq_putc(p, '\n');
156 }
157
158 if (i < NR_IRQS) {
159 spin_lock_irqsave(&irq_desc[i].lock, flags);
160 action = irq_desc[i].action;
161 if (!action)
162 goto skip;
163 seq_printf(p, "%3d: ",i);
164#ifndef CONFIG_SMP
165 seq_printf(p, "%10u ", kstat_irqs(i));
166#else
167 for (j = 0; j < NR_CPUS; j++)
168 if (cpu_online(j))
169 seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
170#endif
171 seq_printf(p, " %14s", irq_desc[i].handler->typename);
172 seq_printf(p, " %s", action->name);
173
174 for (action=action->next; action; action = action->next)
175 seq_printf(p, ", %s", action->name);
176
177 seq_putc(p, '\n');
178skip:
179 spin_unlock_irqrestore(&irq_desc[i].lock, flags);
180 } else if (i == NR_IRQS) {
181 seq_printf(p, "NMI: ");
182 for (j = 0; j < NR_CPUS; j++)
183 if (cpu_online(j))
184 seq_printf(p, "%10u ", nmi_count(j));
185 seq_putc(p, '\n');
186#ifdef CONFIG_X86_LOCAL_APIC
187 seq_printf(p, "LOC: ");
188 for (j = 0; j < NR_CPUS; j++)
189 if (cpu_online(j))
190 seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs);
191 seq_putc(p, '\n');
192#endif
193 seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
194#if defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG)
195 seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
196#endif
197 }
198 return 0;
199}
200
201
202
203
204#ifdef CONFIG_SMP
205inline void synchronize_irq(unsigned int irq)
206{
207 while (irq_desc[irq].status & IRQ_INPROGRESS)
208 cpu_relax();
209}
210#endif
211
212
213
214
215
216
217
218
219asmlinkage int handle_IRQ_event(unsigned int irq,
220 struct pt_regs *regs, struct irqaction *action)
221{
222 int status = 1;
223 int ret, retval = 0;
224
225 if (!(action->flags & SA_INTERRUPT))
226 local_irq_enable();
227
228 do {
229 ret = action->handler(irq, action->dev_id, regs);
230 if (ret == IRQ_HANDLED)
231 status |= action->flags;
232 retval |= ret;
233 action = action->next;
234 } while (action);
235 if (status & SA_SAMPLE_RANDOM)
236 add_interrupt_randomness(irq);
237 local_irq_disable();
238 return retval;
239}
240
241static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
242{
243 struct irqaction *action;
244
245 if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
246 printk(KERN_ERR "irq event %d: bogus return value %x\n",
247 irq, action_ret);
248 } else {
249 printk(KERN_ERR "irq %d: nobody cared!\n", irq);
250 }
251 dump_stack();
252 printk(KERN_ERR "handlers:\n");
253 action = desc->action;
254 do {
255 printk(KERN_ERR "[<%p>]", action->handler);
256 print_symbol(" (%s)",
257 (unsigned long)action->handler);
258 printk("\n");
259 action = action->next;
260 } while (action);
261}
262
263static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret)
264{
265 static int count = 100;
266
267 if (count) {
268 count--;
269 __report_bad_irq(irq, desc, action_ret);
270 }
271}
272
273static int noirqdebug;
274
275static int __init noirqdebug_setup(char *str)
276{
277 noirqdebug = 1;
278 printk("IRQ lockup detection disabled\n");
279 return 1;
280}
281
282__setup("noirqdebug", noirqdebug_setup);
283
284
285
286
287
288
289
290
291
292
293
294static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret)
295{
296 if (action_ret != IRQ_HANDLED) {
297 desc->irqs_unhandled++;
298 if (action_ret != IRQ_NONE)
299 report_bad_irq(irq, desc, action_ret);
300 }
301
302 desc->irq_count++;
303 if (desc->irq_count < 100000)
304 return;
305
306 desc->irq_count = 0;
307 if (desc->irqs_unhandled > 99900) {
308
309
310
311 __report_bad_irq(irq, desc, action_ret);
312
313
314
315 printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
316 desc->status |= IRQ_DISABLED;
317 desc->handler->disable(irq);
318 }
319 desc->irqs_unhandled = 0;
320}
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341inline void disable_irq_nosync(unsigned int irq)
342{
343 irq_desc_t *desc = irq_desc + irq;
344 unsigned long flags;
345
346 spin_lock_irqsave(&desc->lock, flags);
347 if (!desc->depth++) {
348 desc->status |= IRQ_DISABLED;
349 desc->handler->disable(irq);
350 }
351 spin_unlock_irqrestore(&desc->lock, flags);
352}
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367void disable_irq(unsigned int irq)
368{
369 irq_desc_t *desc = irq_desc + irq;
370 disable_irq_nosync(irq);
371 if (desc->action)
372 synchronize_irq(irq);
373}
374
375
376
377
378
379
380
381
382
383
384
385
386void enable_irq(unsigned int irq)
387{
388 irq_desc_t *desc = irq_desc + irq;
389 unsigned long flags;
390
391 spin_lock_irqsave(&desc->lock, flags);
392 switch (desc->depth) {
393 case 1: {
394 unsigned int status = desc->status & ~IRQ_DISABLED;
395 desc->status = status;
396 if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
397 desc->status = status | IRQ_REPLAY;
398 hw_resend_irq(desc->handler,irq);
399 }
400 desc->handler->enable(irq);
401
402 }
403 default:
404 desc->depth--;
405 break;
406 case 0:
407 printk("enable_irq(%u) unbalanced from %p\n", irq,
408 __builtin_return_address(0));
409 }
410 spin_unlock_irqrestore(&desc->lock, flags);
411}
412
413
414
415
416
417
418asmlinkage unsigned int do_IRQ(struct pt_regs regs)
419{
420
421
422
423
424
425
426
427
428
429
430 int irq = regs.orig_eax & 0xff;
431 irq_desc_t *desc = irq_desc + irq;
432 struct irqaction * action;
433 unsigned int status;
434
435 irq_enter();
436
437#ifdef CONFIG_DEBUG_STACKOVERFLOW
438
439 {
440 long esp;
441
442 __asm__ __volatile__("andl %%esp,%0" :
443 "=r" (esp) : "0" (THREAD_SIZE - 1));
444 if (unlikely(esp < (sizeof(struct thread_info) + STACK_WARN))) {
445 printk("do_IRQ: stack overflow: %ld\n",
446 esp - sizeof(struct thread_info));
447 dump_stack();
448 }
449 }
450#endif
451 kstat_this_cpu.irqs[irq]++;
452 spin_lock(&desc->lock);
453 desc->handler->ack(irq);
454
455
456
457
458 status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
459 status |= IRQ_PENDING;
460
461
462
463
464
465 action = NULL;
466 if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
467 action = desc->action;
468 status &= ~IRQ_PENDING;
469 status |= IRQ_INPROGRESS;
470 }
471 desc->status = status;
472
473
474
475
476
477
478
479 if (unlikely(!action))
480 goto out;
481
482
483
484
485
486
487
488
489
490
491
492#ifdef CONFIG_4KSTACKS
493
494 for (;;) {
495 irqreturn_t action_ret;
496 u32 *isp;
497 union irq_ctx * curctx;
498 union irq_ctx * irqctx;
499
500 curctx = (union irq_ctx *) current_thread_info();
501 irqctx = hardirq_ctx[smp_processor_id()];
502
503 spin_unlock(&desc->lock);
504
505
506
507
508
509
510
511
512 if (curctx == irqctx)
513 action_ret = handle_IRQ_event(irq, ®s, action);
514 else {
515
516 isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
517 irqctx->tinfo.task = curctx->tinfo.task;
518 irqctx->tinfo.previous_esp = current_stack_pointer();
519
520 *--isp = (u32) action;
521 *--isp = (u32) ®s;
522 *--isp = (u32) irq;
523
524 asm volatile(
525 " xchgl %%ebx,%%esp \n"
526 " call handle_IRQ_event \n"
527 " xchgl %%ebx,%%esp \n"
528 : "=a"(action_ret)
529 : "b"(isp)
530 : "memory", "cc", "edx", "ecx"
531 );
532
533
534 }
535 spin_lock(&desc->lock);
536 if (!noirqdebug)
537 note_interrupt(irq, desc, action_ret);
538 if (curctx != irqctx)
539 irqctx->tinfo.task = NULL;
540 if (likely(!(desc->status & IRQ_PENDING)))
541 break;
542 desc->status &= ~IRQ_PENDING;
543 }
544
545#else
546
547 for (;;) {
548 irqreturn_t action_ret;
549
550 spin_unlock(&desc->lock);
551
552 action_ret = handle_IRQ_event(irq, ®s, action);
553
554 spin_lock(&desc->lock);
555 if (!noirqdebug)
556 note_interrupt(irq, desc, action_ret);
557 if (likely(!(desc->status & IRQ_PENDING)))
558 break;
559 desc->status &= ~IRQ_PENDING;
560 }
561#endif
562 desc->status &= ~IRQ_INPROGRESS;
563
564out:
565
566
567
568
569 desc->handler->end(irq);
570 spin_unlock(&desc->lock);
571
572 irq_exit();
573
574 return 1;
575}
576
577int can_request_irq(unsigned int irq, unsigned long irqflags)
578{
579 struct irqaction *action;
580
581 if (irq >= NR_IRQS)
582 return 0;
583 action = irq_desc[irq].action;
584 if (action) {
585 if (irqflags & action->flags & SA_SHIRQ)
586 action = NULL;
587 }
588 return !action;
589}
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623int request_irq(unsigned int irq,
624 irqreturn_t (*handler)(int, void *, struct pt_regs *),
625 unsigned long irqflags,
626 const char * devname,
627 void *dev_id)
628{
629 int retval;
630 struct irqaction * action;
631
632#if 1
633
634
635
636
637
638
639 if (irqflags & SA_SHIRQ) {
640 if (!dev_id)
641 printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]);
642 }
643#endif
644
645 if (irq >= NR_IRQS)
646 return -EINVAL;
647 if (!handler)
648 return -EINVAL;
649
650 action = (struct irqaction *)
651 kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
652 if (!action)
653 return -ENOMEM;
654
655 action->handler = handler;
656 action->flags = irqflags;
657 cpus_clear(action->mask);
658 action->name = devname;
659 action->next = NULL;
660 action->dev_id = dev_id;
661
662 retval = setup_irq(irq, action);
663 if (retval)
664 kfree(action);
665 return retval;
666}
667
668EXPORT_SYMBOL(request_irq);
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685void free_irq(unsigned int irq, void *dev_id)
686{
687 irq_desc_t *desc;
688 struct irqaction **p;
689 unsigned long flags;
690
691 if (irq >= NR_IRQS)
692 return;
693
694 desc = irq_desc + irq;
695 spin_lock_irqsave(&desc->lock,flags);
696 p = &desc->action;
697 for (;;) {
698 struct irqaction * action = *p;
699 if (action) {
700 struct irqaction **pp = p;
701 p = &action->next;
702 if (action->dev_id != dev_id)
703 continue;
704
705
706 *pp = action->next;
707 if (!desc->action) {
708 desc->status |= IRQ_DISABLED;
709 desc->handler->shutdown(irq);
710 }
711 spin_unlock_irqrestore(&desc->lock,flags);
712
713
714 synchronize_irq(irq);
715 kfree(action);
716 return;
717 }
718 printk("Trying to free free IRQ%d\n",irq);
719 spin_unlock_irqrestore(&desc->lock,flags);
720 return;
721 }
722}
723
724EXPORT_SYMBOL(free_irq);
725
726
727
728
729
730
731
732
733
734
735static DECLARE_MUTEX(probe_sem);
736
737
738
739
740
741
742
743
744
745unsigned long probe_irq_on(void)
746{
747 unsigned int i;
748 irq_desc_t *desc;
749 unsigned long val;
750 unsigned long delay;
751
752 down(&probe_sem);
753
754
755
756
757 for (i = NR_IRQS-1; i > 0; i--) {
758 desc = irq_desc + i;
759
760 spin_lock_irq(&desc->lock);
761 if (!irq_desc[i].action)
762 irq_desc[i].handler->startup(i);
763 spin_unlock_irq(&desc->lock);
764 }
765
766
767 for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
768 barrier();
769
770
771
772
773
774
775 for (i = NR_IRQS-1; i > 0; i--) {
776 desc = irq_desc + i;
777
778 spin_lock_irq(&desc->lock);
779 if (!desc->action) {
780 desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
781 if (desc->handler->startup(i))
782 desc->status |= IRQ_PENDING;
783 }
784 spin_unlock_irq(&desc->lock);
785 }
786
787
788
789
790 for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
791 barrier();
792
793
794
795
796 val = 0;
797 for (i = 0; i < NR_IRQS; i++) {
798 irq_desc_t *desc = irq_desc + i;
799 unsigned int status;
800
801 spin_lock_irq(&desc->lock);
802 status = desc->status;
803
804 if (status & IRQ_AUTODETECT) {
805
806 if (!(status & IRQ_WAITING)) {
807 desc->status = status & ~IRQ_AUTODETECT;
808 desc->handler->shutdown(i);
809 } else
810 if (i < 32)
811 val |= 1 << i;
812 }
813 spin_unlock_irq(&desc->lock);
814 }
815
816 return val;
817}
818
819EXPORT_SYMBOL(probe_irq_on);
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838unsigned int probe_irq_mask(unsigned long val)
839{
840 int i;
841 unsigned int mask;
842
843 mask = 0;
844 for (i = 0; i < NR_IRQS; i++) {
845 irq_desc_t *desc = irq_desc + i;
846 unsigned int status;
847
848 spin_lock_irq(&desc->lock);
849 status = desc->status;
850
851 if (status & IRQ_AUTODETECT) {
852 if (i < 16 && !(status & IRQ_WAITING))
853 mask |= 1 << i;
854
855 desc->status = status & ~IRQ_AUTODETECT;
856 desc->handler->shutdown(i);
857 }
858 spin_unlock_irq(&desc->lock);
859 }
860 up(&probe_sem);
861
862 return mask & val;
863}
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888int probe_irq_off(unsigned long val)
889{
890 int i, irq_found, nr_irqs;
891
892 nr_irqs = 0;
893 irq_found = 0;
894 for (i = 0; i < NR_IRQS; i++) {
895 irq_desc_t *desc = irq_desc + i;
896 unsigned int status;
897
898 spin_lock_irq(&desc->lock);
899 status = desc->status;
900
901 if (status & IRQ_AUTODETECT) {
902 if (!(status & IRQ_WAITING)) {
903 if (!nr_irqs)
904 irq_found = i;
905 nr_irqs++;
906 }
907 desc->status = status & ~IRQ_AUTODETECT;
908 desc->handler->shutdown(i);
909 }
910 spin_unlock_irq(&desc->lock);
911 }
912 up(&probe_sem);
913
914 if (nr_irqs > 1)
915 irq_found = -irq_found;
916 return irq_found;
917}
918
919EXPORT_SYMBOL(probe_irq_off);
920
921
922int setup_irq(unsigned int irq, struct irqaction * new)
923{
924 int shared = 0;
925 unsigned long flags;
926 struct irqaction *old, **p;
927 irq_desc_t *desc = irq_desc + irq;
928
929 if (desc->handler == &no_irq_type)
930 return -ENOSYS;
931
932
933
934
935
936 if (new->flags & SA_SAMPLE_RANDOM) {
937
938
939
940
941
942
943
944
945 rand_initialize_irq(irq);
946 }
947
948
949
950
951 spin_lock_irqsave(&desc->lock,flags);
952 p = &desc->action;
953 if ((old = *p) != NULL) {
954
955 if (!(old->flags & new->flags & SA_SHIRQ)) {
956 spin_unlock_irqrestore(&desc->lock,flags);
957 return -EBUSY;
958 }
959
960
961 do {
962 p = &old->next;
963 old = *p;
964 } while (old);
965 shared = 1;
966 }
967
968 *p = new;
969
970 if (!shared) {
971 desc->depth = 0;
972 desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
973 desc->handler->startup(irq);
974 }
975 spin_unlock_irqrestore(&desc->lock,flags);
976
977 register_irq_proc(irq);
978 return 0;
979}
980
981static struct proc_dir_entry * root_irq_dir;
982static struct proc_dir_entry * irq_dir [NR_IRQS];
983
984#ifdef CONFIG_SMP
985
986static struct proc_dir_entry *smp_affinity_entry[NR_IRQS];
987
988cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
989
990static int irq_affinity_read_proc(char *page, char **start, off_t off,
991 int count, int *eof, void *data)
992{
993 int len = cpumask_scnprintf(page, count, irq_affinity[(long)data]);
994 if (count - len < 2)
995 return -EINVAL;
996 len += sprintf(page + len, "\n");
997 return len;
998}
999
1000static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
1001 unsigned long count, void *data)
1002{
1003 int irq = (long)data, full_count = count, err;
1004 cpumask_t new_value, tmp;
1005
1006 if (!irq_desc[irq].handler->set_affinity)
1007 return -EIO;
1008
1009 err = cpumask_parse(buffer, count, new_value);
1010 if (err)
1011 return err;
1012
1013
1014
1015
1016
1017
1018 cpus_and(tmp, new_value, cpu_online_map);
1019 if (cpus_empty(tmp))
1020 return -EINVAL;
1021
1022 irq_affinity[irq] = new_value;
1023 irq_desc[irq].handler->set_affinity(irq,
1024 cpumask_of_cpu(first_cpu(new_value)));
1025
1026 return full_count;
1027}
1028
1029#endif
1030#define MAX_NAMELEN 10
1031
1032static void register_irq_proc (unsigned int irq)
1033{
1034 char name [MAX_NAMELEN];
1035
1036 if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) ||
1037 irq_dir[irq])
1038 return;
1039
1040 memset(name, 0, MAX_NAMELEN);
1041 sprintf(name, "%d", irq);
1042
1043
1044 irq_dir[irq] = proc_mkdir(name, root_irq_dir);
1045
1046#ifdef CONFIG_SMP
1047 {
1048 struct proc_dir_entry *entry;
1049
1050
1051 entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
1052
1053 if (entry) {
1054 entry->nlink = 1;
1055 entry->data = (void *)(long)irq;
1056 entry->read_proc = irq_affinity_read_proc;
1057 entry->write_proc = irq_affinity_write_proc;
1058 }
1059
1060 smp_affinity_entry[irq] = entry;
1061 }
1062#endif
1063}
1064
1065void init_irq_proc (void)
1066{
1067 int i;
1068
1069
1070 root_irq_dir = proc_mkdir("irq", NULL);
1071 create_prof_cpu_mask(root_irq_dir);
1072
1073
1074
1075 for (i = 0; i < NR_IRQS; i++)
1076 register_irq_proc(i);
1077}
1078
1079
1080#ifdef CONFIG_4KSTACKS
1081
1082
1083
1084
1085static char softirq_stack[NR_CPUS * THREAD_SIZE] __attribute__((__aligned__(THREAD_SIZE)));
1086static char hardirq_stack[NR_CPUS * THREAD_SIZE] __attribute__((__aligned__(THREAD_SIZE)));
1087
1088
1089
1090
1091void irq_ctx_init(int cpu)
1092{
1093 union irq_ctx *irqctx;
1094
1095 if (hardirq_ctx[cpu])
1096 return;
1097
1098 irqctx = (union irq_ctx*) &hardirq_stack[cpu*THREAD_SIZE];
1099 irqctx->tinfo.task = NULL;
1100 irqctx->tinfo.exec_domain = NULL;
1101 irqctx->tinfo.cpu = cpu;
1102 irqctx->tinfo.preempt_count = HARDIRQ_OFFSET;
1103 irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
1104
1105 hardirq_ctx[cpu] = irqctx;
1106
1107 irqctx = (union irq_ctx*) &softirq_stack[cpu*THREAD_SIZE];
1108 irqctx->tinfo.task = NULL;
1109 irqctx->tinfo.exec_domain = NULL;
1110 irqctx->tinfo.cpu = cpu;
1111 irqctx->tinfo.preempt_count = SOFTIRQ_OFFSET;
1112 irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
1113
1114 softirq_ctx[cpu] = irqctx;
1115
1116 printk("CPU %u irqstacks, hard=%p soft=%p\n",
1117 cpu,hardirq_ctx[cpu],softirq_ctx[cpu]);
1118}
1119
1120extern asmlinkage void __do_softirq(void);
1121
1122asmlinkage void do_softirq(void)
1123{
1124 unsigned long flags;
1125 struct thread_info *curctx;
1126 union irq_ctx *irqctx;
1127 u32 *isp;
1128
1129 if (in_interrupt())
1130 return;
1131
1132 local_irq_save(flags);
1133
1134 if (local_softirq_pending()) {
1135 curctx = current_thread_info();
1136 irqctx = softirq_ctx[smp_processor_id()];
1137 irqctx->tinfo.task = curctx->task;
1138 irqctx->tinfo.previous_esp = current_stack_pointer();
1139
1140
1141 isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
1142
1143
1144 asm volatile(
1145 " xchgl %%ebx,%%esp \n"
1146 " call __do_softirq \n"
1147 " movl %%ebx,%%esp \n"
1148 : "=b"(isp)
1149 : "0"(isp)
1150 : "memory", "cc", "edx", "ecx", "eax"
1151 );
1152 }
1153
1154 local_irq_restore(flags);
1155}
1156
1157EXPORT_SYMBOL(do_softirq);
1158#endif
1159