diff options
Diffstat (limited to 'arch/cris/arch-v10')
-rw-r--r-- | arch/cris/arch-v10/drivers/Kconfig | 1 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/entry.S | 41 | ||||
-rw-r--r-- | arch/cris/arch-v10/kernel/irq.c | 59 |
3 files changed, 78 insertions, 23 deletions
diff --git a/arch/cris/arch-v10/drivers/Kconfig b/arch/cris/arch-v10/drivers/Kconfig index 03e2e68f947d..e6fc8455a372 100644 --- a/arch/cris/arch-v10/drivers/Kconfig +++ b/arch/cris/arch-v10/drivers/Kconfig | |||
@@ -2,6 +2,7 @@ config ETRAX_ETHERNET | |||
2 | bool "Ethernet support" | 2 | bool "Ethernet support" |
3 | depends on ETRAX_ARCH_V10 | 3 | depends on ETRAX_ARCH_V10 |
4 | select NET_ETHERNET | 4 | select NET_ETHERNET |
5 | select MII | ||
5 | help | 6 | help |
6 | This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet | 7 | This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet |
7 | controller. | 8 | controller. |
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S index bc9bed97f225..ec62c951fa3c 100644 --- a/arch/cris/arch-v10/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S | |||
@@ -500,9 +500,8 @@ _work_notifysig: | |||
500 | ;; deal with pending signals and notify-resume requests | 500 | ;; deal with pending signals and notify-resume requests |
501 | 501 | ||
502 | move.d $r9, $r10 ; do_notify_resume syscall/irq param | 502 | move.d $r9, $r10 ; do_notify_resume syscall/irq param |
503 | moveq 0, $r11 ; oldset param - 0 in this case | 503 | move.d $sp, $r11 ; the regs param |
504 | move.d $sp, $r12 ; the regs param | 504 | move.d $r1, $r12 ; the thread_info_flags parameter |
505 | move.d $r1, $r13 ; the thread_info_flags parameter | ||
506 | jsr do_notify_resume | 505 | jsr do_notify_resume |
507 | 506 | ||
508 | ba _Rexit | 507 | ba _Rexit |
@@ -678,13 +677,19 @@ IRQ1_interrupt: | |||
678 | push $r10 ; push orig_r10 | 677 | push $r10 ; push orig_r10 |
679 | clear.d [$sp=$sp-4] ; frametype == 0, normal frame | 678 | clear.d [$sp=$sp-4] ; frametype == 0, normal frame |
680 | 679 | ||
680 | ;; If there is a glitch on the NMI pin shorter than ~100ns | ||
681 | ;; (i.e. non-active by the time we get here) then the nmi_pin bit | ||
682 | ;; in R_IRQ_MASK0_RD will already be cleared. The watchdog_nmi bit | ||
683 | ;; is cleared by us however (when feeding the watchdog), which is why | ||
684 | ;; we use that bit to determine what brought us here. | ||
685 | |||
681 | move.d [R_IRQ_MASK0_RD], $r1 ; External NMI or watchdog? | 686 | move.d [R_IRQ_MASK0_RD], $r1 ; External NMI or watchdog? |
682 | and.d 0x80000000, $r1 | 687 | and.d (1<<30), $r1 |
683 | beq wdog | 688 | bne wdog |
684 | move.d $sp, $r10 | 689 | move.d $sp, $r10 |
685 | jsr handle_nmi | 690 | jsr handle_nmi |
686 | setf m ; Enable NMI again | 691 | setf m ; Enable NMI again |
687 | retb ; Return from NMI | 692 | ba _Rexit ; Return the standard way |
688 | nop | 693 | nop |
689 | wdog: | 694 | wdog: |
690 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | 695 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) |
@@ -775,22 +780,9 @@ multiple_interrupt: | |||
775 | push $r10 ; push orig_r10 | 780 | push $r10 ; push orig_r10 |
776 | clear.d [$sp=$sp-4] ; frametype == 0, normal frame | 781 | clear.d [$sp=$sp-4] ; frametype == 0, normal frame |
777 | 782 | ||
778 | moveq 2, $r2 ; first bit we care about is the timer0 irq | 783 | move.d $sp, $r10 |
779 | move.d [R_VECT_MASK_RD], $r0; read the irq bits that triggered the multiple irq | 784 | jsr do_multiple_IRQ |
780 | move.d $r0, [R_VECT_MASK_CLR] ; Block all active IRQs | ||
781 | 1: | ||
782 | btst $r2, $r0 ; check for the irq given by bit r2 | ||
783 | bpl 2f | ||
784 | move.d $r2, $r10 ; First argument to do_IRQ | ||
785 | move.d $sp, $r11 ; second argument to do_IRQ | ||
786 | jsr do_IRQ | ||
787 | 2: | ||
788 | addq 1, $r2 ; next vector bit | ||
789 | cmp.b 32, $r2 | ||
790 | bne 1b ; process all irq's up to and including number 31 | ||
791 | moveq 0, $r9 ; make ret_from_intr realise we came from an ir | ||
792 | 785 | ||
793 | move.d $r0, [R_VECT_MASK_SET] ; Unblock all the IRQs | ||
794 | jump ret_from_intr | 786 | jump ret_from_intr |
795 | 787 | ||
796 | do_sigtrap: | 788 | do_sigtrap: |
@@ -837,6 +829,13 @@ _ugdb_handle_breakpoint: | |||
837 | ba do_sigtrap ; SIGTRAP the offending process. | 829 | ba do_sigtrap ; SIGTRAP the offending process. |
838 | pop $dccr ; Restore dccr in delay slot. | 830 | pop $dccr ; Restore dccr in delay slot. |
839 | 831 | ||
832 | .global kernel_execve | ||
833 | kernel_execve: | ||
834 | move.d __NR_execve, $r9 | ||
835 | break 13 | ||
836 | ret | ||
837 | nop | ||
838 | |||
840 | .data | 839 | .data |
841 | 840 | ||
842 | hw_bp_trigs: | 841 | hw_bp_trigs: |
diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c index 845c95f6e871..e06ab0050d37 100644 --- a/arch/cris/arch-v10/kernel/irq.c +++ b/arch/cris/arch-v10/kernel/irq.c | |||
@@ -12,10 +12,16 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <asm/irq.h> | 14 | #include <asm/irq.h> |
15 | #include <asm/current.h> | ||
15 | #include <linux/irq.h> | 16 | #include <linux/irq.h> |
17 | #include <linux/interrupt.h> | ||
16 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
17 | #include <linux/init.h> | 19 | #include <linux/init.h> |
18 | 20 | ||
21 | /* From kgdb.c. */ | ||
22 | extern void kgdb_init(void); | ||
23 | extern void breakpoint(void); | ||
24 | |||
19 | #define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr)); | 25 | #define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr)); |
20 | #define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr)); | 26 | #define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr)); |
21 | 27 | ||
@@ -75,8 +81,8 @@ BUILD_IRQ(12, 0x1000) | |||
75 | BUILD_IRQ(13, 0x2000) | 81 | BUILD_IRQ(13, 0x2000) |
76 | void mmu_bus_fault(void); /* IRQ 14 is the bus fault interrupt */ | 82 | void mmu_bus_fault(void); /* IRQ 14 is the bus fault interrupt */ |
77 | void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */ | 83 | void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */ |
78 | BUILD_IRQ(16, 0x10000) | 84 | BUILD_IRQ(16, 0x10000 | 0x20000) /* ethernet tx interrupt needs to block rx */ |
79 | BUILD_IRQ(17, 0x20000) | 85 | BUILD_IRQ(17, 0x20000 | 0x10000) /* ...and vice versa */ |
80 | BUILD_IRQ(18, 0x40000) | 86 | BUILD_IRQ(18, 0x40000) |
81 | BUILD_IRQ(19, 0x80000) | 87 | BUILD_IRQ(19, 0x80000) |
82 | BUILD_IRQ(20, 0x100000) | 88 | BUILD_IRQ(20, 0x100000) |
@@ -147,6 +153,55 @@ void system_call(void); /* from entry.S */ | |||
147 | void do_sigtrap(void); /* from entry.S */ | 153 | void do_sigtrap(void); /* from entry.S */ |
148 | void gdb_handle_breakpoint(void); /* from entry.S */ | 154 | void gdb_handle_breakpoint(void); /* from entry.S */ |
149 | 155 | ||
156 | extern void do_IRQ(int irq, struct pt_regs * regs); | ||
157 | |||
158 | /* Handle multiple IRQs */ | ||
159 | void do_multiple_IRQ(struct pt_regs* regs) | ||
160 | { | ||
161 | int bit; | ||
162 | unsigned masked; | ||
163 | unsigned mask; | ||
164 | unsigned ethmask = 0; | ||
165 | |||
166 | /* Get interrupts to mask and handle */ | ||
167 | mask = masked = *R_VECT_MASK_RD; | ||
168 | |||
169 | /* Never mask timer IRQ */ | ||
170 | mask &= ~(IO_MASK(R_VECT_MASK_RD, timer0)); | ||
171 | |||
172 | /* | ||
173 | * If either ethernet interrupt (rx or tx) is active then block | ||
174 | * the other one too. Unblock afterwards also. | ||
175 | */ | ||
176 | if (mask & | ||
177 | (IO_STATE(R_VECT_MASK_RD, dma0, active) | | ||
178 | IO_STATE(R_VECT_MASK_RD, dma1, active))) { | ||
179 | ethmask = (IO_MASK(R_VECT_MASK_RD, dma0) | | ||
180 | IO_MASK(R_VECT_MASK_RD, dma1)); | ||
181 | } | ||
182 | |||
183 | /* Block them */ | ||
184 | *R_VECT_MASK_CLR = (mask | ethmask); | ||
185 | |||
186 | /* An extra irq_enter here to prevent softIRQs to run after | ||
187 | * each do_IRQ. This will decrease the interrupt latency. | ||
188 | */ | ||
189 | irq_enter(); | ||
190 | |||
191 | /* Handle all IRQs */ | ||
192 | for (bit = 2; bit < 32; bit++) { | ||
193 | if (masked & (1 << bit)) { | ||
194 | do_IRQ(bit, regs); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /* This irq_exit() will trigger the soft IRQs. */ | ||
199 | irq_exit(); | ||
200 | |||
201 | /* Unblock the IRQs again */ | ||
202 | *R_VECT_MASK_SET = (masked | ethmask); | ||
203 | } | ||
204 | |||
150 | /* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and | 205 | /* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and |
151 | setting the irq vector table. | 206 | setting the irq vector table. |
152 | */ | 207 | */ |