diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/m68knommu/platform/68360 |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/m68knommu/platform/68360')
-rw-r--r-- | arch/m68knommu/platform/68360/Makefile | 10 | ||||
-rw-r--r-- | arch/m68knommu/platform/68360/commproc.c | 308 | ||||
-rw-r--r-- | arch/m68knommu/platform/68360/config.c | 208 | ||||
-rw-r--r-- | arch/m68knommu/platform/68360/entry.S | 184 | ||||
-rw-r--r-- | arch/m68knommu/platform/68360/ints.c | 335 |
5 files changed, 1045 insertions, 0 deletions
diff --git a/arch/m68knommu/platform/68360/Makefile b/arch/m68knommu/platform/68360/Makefile new file mode 100644 index 000000000000..cf5af73a5789 --- /dev/null +++ b/arch/m68knommu/platform/68360/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # Makefile for arch/m68knommu/platform/68360. | ||
3 | # | ||
4 | |||
5 | obj-y := config.o commproc.o entry.o ints.o | ||
6 | |||
7 | extra-y := head.o | ||
8 | |||
9 | $(obj)/head.o: $(obj)/head-$(MODEL).o | ||
10 | ln -sf head-$(MODEL).o $(obj)/head.o | ||
diff --git a/arch/m68knommu/platform/68360/commproc.c b/arch/m68knommu/platform/68360/commproc.c new file mode 100644 index 000000000000..6acb8d294cb6 --- /dev/null +++ b/arch/m68knommu/platform/68360/commproc.c | |||
@@ -0,0 +1,308 @@ | |||
1 | /* | ||
2 | * General Purpose functions for the global management of the | ||
3 | * Communication Processor Module. | ||
4 | * | ||
5 | * Copyright (c) 2000 Michael Leslie <mleslie@lineo.com> | ||
6 | * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) | ||
7 | * | ||
8 | * In addition to the individual control of the communication | ||
9 | * channels, there are a few functions that globally affect the | ||
10 | * communication processor. | ||
11 | * | ||
12 | * Buffer descriptors must be allocated from the dual ported memory | ||
13 | * space. The allocator for that is here. When the communication | ||
14 | * process is reset, we reclaim the memory available. There is | ||
15 | * currently no deallocator for this memory. | ||
16 | * The amount of space available is platform dependent. On the | ||
17 | * MBX, the EPPC software loads additional microcode into the | ||
18 | * communication processor, and uses some of the DP ram for this | ||
19 | * purpose. Current, the first 512 bytes and the last 256 bytes of | ||
20 | * memory are used. Right now I am conservative and only use the | ||
21 | * memory that can never be used for microcode. If there are | ||
22 | * applications that require more DP ram, we can expand the boundaries | ||
23 | * but then we have to be careful of any downloaded microcode. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | /* | ||
28 | * Michael Leslie <mleslie@lineo.com> | ||
29 | * adapted Dan Malek's ppc8xx drivers to M68360 | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | #include <linux/errno.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/param.h> | ||
37 | #include <linux/string.h> | ||
38 | #include <linux/mm.h> | ||
39 | #include <linux/interrupt.h> | ||
40 | #include <asm/irq.h> | ||
41 | #include <asm/m68360.h> | ||
42 | #include <asm/commproc.h> | ||
43 | |||
44 | /* #include <asm/page.h> */ | ||
45 | /* #include <asm/pgtable.h> */ | ||
46 | extern void *_quicc_base; | ||
47 | extern unsigned int system_clock; | ||
48 | |||
49 | |||
50 | static uint dp_alloc_base; /* Starting offset in DP ram */ | ||
51 | static uint dp_alloc_top; /* Max offset + 1 */ | ||
52 | |||
53 | #if 0 | ||
54 | static void *host_buffer; /* One page of host buffer */ | ||
55 | static void *host_end; /* end + 1 */ | ||
56 | #endif | ||
57 | |||
58 | /* struct cpm360_t *cpmp; */ /* Pointer to comm processor space */ | ||
59 | |||
60 | QUICC *pquicc; | ||
61 | /* QUICC *quicc_dpram; */ /* mleslie - temporary; use extern pquicc elsewhere instead */ | ||
62 | |||
63 | |||
64 | /* CPM interrupt vector functions. */ | ||
65 | struct cpm_action { | ||
66 | void (*handler)(void *); | ||
67 | void *dev_id; | ||
68 | }; | ||
69 | static struct cpm_action cpm_vecs[CPMVEC_NR]; | ||
70 | static void cpm_interrupt(int irq, void * dev, struct pt_regs * regs); | ||
71 | static void cpm_error_interrupt(void *); | ||
72 | |||
73 | /* prototypes: */ | ||
74 | void cpm_install_handler(int vec, void (*handler)(), void *dev_id); | ||
75 | void m360_cpm_reset(void); | ||
76 | |||
77 | |||
78 | |||
79 | |||
80 | void m360_cpm_reset() | ||
81 | { | ||
82 | /* pte_t *pte; */ | ||
83 | |||
84 | pquicc = (struct quicc *)(_quicc_base); /* initialized in crt0_rXm.S */ | ||
85 | |||
86 | /* Perform a CPM reset. */ | ||
87 | pquicc->cp_cr = (SOFTWARE_RESET | CMD_FLAG); | ||
88 | |||
89 | /* Wait for CPM to become ready (should be 2 clocks). */ | ||
90 | while (pquicc->cp_cr & CMD_FLAG); | ||
91 | |||
92 | /* On the recommendation of the 68360 manual, p. 7-60 | ||
93 | * - Set sdma interrupt service mask to 7 | ||
94 | * - Set sdma arbitration ID to 4 | ||
95 | */ | ||
96 | pquicc->sdma_sdcr = 0x0740; | ||
97 | |||
98 | |||
99 | /* Claim the DP memory for our use. | ||
100 | */ | ||
101 | dp_alloc_base = CPM_DATAONLY_BASE; | ||
102 | dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE; | ||
103 | |||
104 | |||
105 | /* Set the host page for allocation. | ||
106 | */ | ||
107 | /* host_buffer = host_page_addr; */ | ||
108 | /* host_end = host_page_addr + PAGE_SIZE; */ | ||
109 | |||
110 | /* pte = find_pte(&init_mm, host_page_addr); */ | ||
111 | /* pte_val(*pte) |= _PAGE_NO_CACHE; */ | ||
112 | /* flush_tlb_page(current->mm->mmap, host_buffer); */ | ||
113 | |||
114 | /* Tell everyone where the comm processor resides. | ||
115 | */ | ||
116 | /* cpmp = (cpm360_t *)commproc; */ | ||
117 | } | ||
118 | |||
119 | |||
120 | /* This is called during init_IRQ. We used to do it above, but this | ||
121 | * was too early since init_IRQ was not yet called. | ||
122 | */ | ||
123 | void | ||
124 | cpm_interrupt_init(void) | ||
125 | { | ||
126 | /* Initialize the CPM interrupt controller. | ||
127 | * NOTE THAT pquicc had better have been initialized! | ||
128 | * reference: MC68360UM p. 7-377 | ||
129 | */ | ||
130 | pquicc->intr_cicr = | ||
131 | (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | | ||
132 | (CPM_INTERRUPT << 13) | | ||
133 | CICR_HP_MASK | | ||
134 | (CPM_VECTOR_BASE << 5) | | ||
135 | CICR_SPS; | ||
136 | |||
137 | /* mask all CPM interrupts from reaching the cpu32 core: */ | ||
138 | pquicc->intr_cimr = 0; | ||
139 | |||
140 | |||
141 | /* mles - If I understand correctly, the 360 just pops over to the CPM | ||
142 | * specific vector, obviating the necessity to vector through the IRQ | ||
143 | * whose priority the CPM is set to. This needs a closer look, though. | ||
144 | */ | ||
145 | |||
146 | /* Set our interrupt handler with the core CPU. */ | ||
147 | /* if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0) */ | ||
148 | /* panic("Could not allocate CPM IRQ!"); */ | ||
149 | |||
150 | /* Install our own error handler. | ||
151 | */ | ||
152 | /* I think we want to hold off on this one for the moment - mles */ | ||
153 | /* cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL); */ | ||
154 | |||
155 | /* master CPM interrupt enable */ | ||
156 | /* pquicc->intr_cicr |= CICR_IEN; */ /* no such animal for 360 */ | ||
157 | } | ||
158 | |||
159 | |||
160 | |||
161 | /* CPM interrupt controller interrupt. | ||
162 | */ | ||
163 | static void | ||
164 | cpm_interrupt(int irq, void * dev, struct pt_regs * regs) | ||
165 | { | ||
166 | /* uint vec; */ | ||
167 | |||
168 | /* mles: Note that this stuff is currently being performed by | ||
169 | * M68360_do_irq(int vec, struct pt_regs *fp), in ../ints.c */ | ||
170 | |||
171 | /* figure out the vector */ | ||
172 | /* call that vector's handler */ | ||
173 | /* clear the irq's bit in the service register */ | ||
174 | |||
175 | #if 0 /* old 860 stuff: */ | ||
176 | /* Get the vector by setting the ACK bit and then reading | ||
177 | * the register. | ||
178 | */ | ||
179 | ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1; | ||
180 | vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr; | ||
181 | vec >>= 11; | ||
182 | |||
183 | |||
184 | if (cpm_vecs[vec].handler != 0) | ||
185 | (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id); | ||
186 | else | ||
187 | ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); | ||
188 | |||
189 | /* After servicing the interrupt, we have to remove the status | ||
190 | * indicator. | ||
191 | */ | ||
192 | ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec); | ||
193 | #endif | ||
194 | |||
195 | } | ||
196 | |||
197 | /* The CPM can generate the error interrupt when there is a race condition | ||
198 | * between generating and masking interrupts. All we have to do is ACK it | ||
199 | * and return. This is a no-op function so we don't need any special | ||
200 | * tests in the interrupt handler. | ||
201 | */ | ||
202 | static void | ||
203 | cpm_error_interrupt(void *dev) | ||
204 | { | ||
205 | } | ||
206 | |||
207 | /* Install a CPM interrupt handler. | ||
208 | */ | ||
209 | void | ||
210 | cpm_install_handler(int vec, void (*handler)(), void *dev_id) | ||
211 | { | ||
212 | |||
213 | request_irq(vec, handler, IRQ_FLG_LOCK, "timer", dev_id); | ||
214 | |||
215 | /* if (cpm_vecs[vec].handler != 0) */ | ||
216 | /* printk(KERN_INFO "CPM interrupt %x replacing %x\n", */ | ||
217 | /* (uint)handler, (uint)cpm_vecs[vec].handler); */ | ||
218 | /* cpm_vecs[vec].handler = handler; */ | ||
219 | /* cpm_vecs[vec].dev_id = dev_id; */ | ||
220 | |||
221 | /* ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec); */ | ||
222 | /* pquicc->intr_cimr |= (1 << vec); */ | ||
223 | |||
224 | } | ||
225 | |||
226 | /* Free a CPM interrupt handler. | ||
227 | */ | ||
228 | void | ||
229 | cpm_free_handler(int vec) | ||
230 | { | ||
231 | cpm_vecs[vec].handler = NULL; | ||
232 | cpm_vecs[vec].dev_id = NULL; | ||
233 | /* ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); */ | ||
234 | pquicc->intr_cimr &= ~(1 << vec); | ||
235 | } | ||
236 | |||
237 | |||
238 | |||
239 | |||
240 | /* Allocate some memory from the dual ported ram. We may want to | ||
241 | * enforce alignment restrictions, but right now everyone is a good | ||
242 | * citizen. | ||
243 | */ | ||
244 | uint | ||
245 | m360_cpm_dpalloc(uint size) | ||
246 | { | ||
247 | uint retloc; | ||
248 | |||
249 | if ((dp_alloc_base + size) >= dp_alloc_top) | ||
250 | return(CPM_DP_NOSPACE); | ||
251 | |||
252 | retloc = dp_alloc_base; | ||
253 | dp_alloc_base += size; | ||
254 | |||
255 | return(retloc); | ||
256 | } | ||
257 | |||
258 | |||
259 | #if 0 /* mleslie - for now these are simply kmalloc'd */ | ||
260 | /* We also own one page of host buffer space for the allocation of | ||
261 | * UART "fifos" and the like. | ||
262 | */ | ||
263 | uint | ||
264 | m360_cpm_hostalloc(uint size) | ||
265 | { | ||
266 | uint retloc; | ||
267 | |||
268 | if ((host_buffer + size) >= host_end) | ||
269 | return(0); | ||
270 | |||
271 | retloc = host_buffer; | ||
272 | host_buffer += size; | ||
273 | |||
274 | return(retloc); | ||
275 | } | ||
276 | #endif | ||
277 | |||
278 | |||
279 | /* Set a baud rate generator. This needs lots of work. There are | ||
280 | * four BRGs, any of which can be wired to any channel. | ||
281 | * The internal baud rate clock is the system clock divided by 16. | ||
282 | * This assumes the baudrate is 16x oversampled by the uart. | ||
283 | */ | ||
284 | /* #define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq * 1000000) */ | ||
285 | #define BRG_INT_CLK system_clock | ||
286 | #define BRG_UART_CLK (BRG_INT_CLK/16) | ||
287 | |||
288 | void | ||
289 | m360_cpm_setbrg(uint brg, uint rate) | ||
290 | { | ||
291 | volatile uint *bp; | ||
292 | |||
293 | /* This is good enough to get SMCs running..... | ||
294 | */ | ||
295 | /* bp = (uint *)&cpmp->cp_brgc1; */ | ||
296 | bp = (volatile uint *)(&pquicc->brgc[0].l); | ||
297 | bp += brg; | ||
298 | *bp = ((BRG_UART_CLK / rate - 1) << 1) | CPM_BRG_EN; | ||
299 | } | ||
300 | |||
301 | |||
302 | /* | ||
303 | * Local variables: | ||
304 | * c-indent-level: 4 | ||
305 | * c-basic-offset: 4 | ||
306 | * tab-width: 4 | ||
307 | * End: | ||
308 | */ | ||
diff --git a/arch/m68knommu/platform/68360/config.c b/arch/m68knommu/platform/68360/config.c new file mode 100644 index 000000000000..3db244625f0f --- /dev/null +++ b/arch/m68knommu/platform/68360/config.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * linux/arch/m68knommu/platform/68360/config.c | ||
3 | * | ||
4 | * Copyright (c) 2000 Michael Leslie <mleslie@lineo.com> | ||
5 | * Copyright (C) 1993 Hamish Macdonald | ||
6 | * Copyright (C) 1999 D. Jeff Dionne <jeff@uclinux.org> | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file COPYING in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | |||
13 | #include <stdarg.h> | ||
14 | #include <linux/config.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/tty.h> | ||
19 | #include <linux/console.h> | ||
20 | |||
21 | #include <asm/setup.h> | ||
22 | #include <asm/system.h> | ||
23 | #include <asm/pgtable.h> | ||
24 | #include <asm/irq.h> | ||
25 | #include <asm/machdep.h> | ||
26 | #include <asm/m68360.h> | ||
27 | |||
28 | #ifdef CONFIG_UCQUICC | ||
29 | #include <asm/bootstd.h> | ||
30 | #endif | ||
31 | |||
32 | extern void m360_cpm_reset(void); | ||
33 | |||
34 | // Mask to select if the PLL prescaler is enabled. | ||
35 | #define MCU_PREEN ((unsigned short)(0x0001 << 13)) | ||
36 | |||
37 | #if defined(CONFIG_UCQUICC) | ||
38 | #define OSCILLATOR (unsigned long int)33000000 | ||
39 | #endif | ||
40 | |||
41 | unsigned long int system_clock; | ||
42 | |||
43 | void M68360_init_IRQ(void); | ||
44 | |||
45 | extern QUICC *pquicc; | ||
46 | |||
47 | /* TODO DON"T Hard Code this */ | ||
48 | /* calculate properly using the right PLL and prescaller */ | ||
49 | // unsigned int system_clock = 33000000l; | ||
50 | extern unsigned long int system_clock; //In kernel setup.c | ||
51 | |||
52 | extern void config_M68360_irq(void); | ||
53 | |||
54 | void BSP_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) | ||
55 | { | ||
56 | unsigned char prescaler; | ||
57 | unsigned short tgcr_save; | ||
58 | int return_value; | ||
59 | |||
60 | #if 0 | ||
61 | /* Restart mode, Enable int, 32KHz, Enable timer */ | ||
62 | TCTL = TCTL_OM | TCTL_IRQEN | TCTL_CLKSOURCE_32KHZ | TCTL_TEN; | ||
63 | /* Set prescaler (Divide 32KHz by 32)*/ | ||
64 | TPRER = 31; | ||
65 | /* Set compare register 32Khz / 32 / 10 = 100 */ | ||
66 | TCMP = 10; | ||
67 | |||
68 | request_irq(IRQ_MACHSPEC | 1, timer_routine, IRQ_FLG_LOCK, "timer", NULL); | ||
69 | #endif | ||
70 | |||
71 | /* General purpose quicc timers: MC68360UM p7-20 */ | ||
72 | |||
73 | /* Set up timer 1 (in [1..4]) to do 100Hz */ | ||
74 | tgcr_save = pquicc->timer_tgcr & 0xfff0; | ||
75 | pquicc->timer_tgcr = tgcr_save; /* stop and reset timer 1 */ | ||
76 | /* pquicc->timer_tgcr |= 0x4444; */ /* halt timers when FREEZE (ie bdm freeze) */ | ||
77 | |||
78 | prescaler = 8; | ||
79 | pquicc->timer_tmr1 = 0x001a | /* or=1, frr=1, iclk=01b */ | ||
80 | (unsigned short)((prescaler - 1) << 8); | ||
81 | |||
82 | pquicc->timer_tcn1 = 0x0000; /* initial count */ | ||
83 | /* calculate interval for 100Hz based on the _system_clock: */ | ||
84 | pquicc->timer_trr1 = (system_clock/ prescaler) / HZ; /* reference count */ | ||
85 | |||
86 | pquicc->timer_ter1 = 0x0003; /* clear timer events */ | ||
87 | |||
88 | /* enable timer 1 interrupt in CIMR */ | ||
89 | // request_irq(IRQ_MACHSPEC | CPMVEC_TIMER1, timer_routine, IRQ_FLG_LOCK, "timer", NULL); | ||
90 | //return_value = request_irq( CPMVEC_TIMER1, timer_routine, IRQ_FLG_LOCK, "timer", NULL); | ||
91 | return_value = request_irq(CPMVEC_TIMER1 , timer_routine, IRQ_FLG_LOCK, | ||
92 | "Timer", NULL); | ||
93 | |||
94 | /* Start timer 1: */ | ||
95 | tgcr_save = (pquicc->timer_tgcr & 0xfff0) | 0x0001; | ||
96 | pquicc->timer_tgcr = tgcr_save; | ||
97 | } | ||
98 | |||
99 | |||
100 | void BSP_tick(void) | ||
101 | { | ||
102 | /* Reset Timer1 */ | ||
103 | /* TSTAT &= 0; */ | ||
104 | |||
105 | pquicc->timer_ter1 = 0x0002; /* clear timer event */ | ||
106 | } | ||
107 | |||
108 | unsigned long BSP_gettimeoffset (void) | ||
109 | { | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | void BSP_gettod (int *yearp, int *monp, int *dayp, | ||
114 | int *hourp, int *minp, int *secp) | ||
115 | { | ||
116 | } | ||
117 | |||
118 | int BSP_hwclk(int op, struct hwclk_time *t) | ||
119 | { | ||
120 | if (!op) { | ||
121 | /* read */ | ||
122 | } else { | ||
123 | /* write */ | ||
124 | } | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | int BSP_set_clock_mmss (unsigned long nowtime) | ||
129 | { | ||
130 | #if 0 | ||
131 | short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; | ||
132 | |||
133 | tod->second1 = real_seconds / 10; | ||
134 | tod->second2 = real_seconds % 10; | ||
135 | tod->minute1 = real_minutes / 10; | ||
136 | tod->minute2 = real_minutes % 10; | ||
137 | #endif | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | void BSP_reset (void) | ||
142 | { | ||
143 | local_irq_disable(); | ||
144 | asm volatile (" | ||
145 | moveal #_start, %a0; | ||
146 | moveb #0, 0xFFFFF300; | ||
147 | moveal 0(%a0), %sp; | ||
148 | moveal 4(%a0), %a0; | ||
149 | jmp (%a0); | ||
150 | "); | ||
151 | } | ||
152 | |||
153 | unsigned char *scc1_hwaddr; | ||
154 | static int errno; | ||
155 | |||
156 | #if defined (CONFIG_UCQUICC) | ||
157 | _bsc0(char *, getserialnum) | ||
158 | _bsc1(unsigned char *, gethwaddr, int, a) | ||
159 | _bsc1(char *, getbenv, char *, a) | ||
160 | #endif | ||
161 | |||
162 | |||
163 | void config_BSP(char *command, int len) | ||
164 | { | ||
165 | unsigned char *p; | ||
166 | |||
167 | m360_cpm_reset(); | ||
168 | |||
169 | /* Calculate the real system clock value. */ | ||
170 | { | ||
171 | unsigned int local_pllcr = (unsigned int)(pquicc->sim_pllcr); | ||
172 | if( local_pllcr & MCU_PREEN ) // If the prescaler is dividing by 128 | ||
173 | { | ||
174 | int mf = (int)(pquicc->sim_pllcr & 0x0fff); | ||
175 | system_clock = (OSCILLATOR / 128) * (mf + 1); | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | int mf = (int)(pquicc->sim_pllcr & 0x0fff); | ||
180 | system_clock = (OSCILLATOR) * (mf + 1); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | printk(KERN_INFO "\n68360 QUICC support (C) 2000 Lineo Inc.\n"); | ||
185 | |||
186 | #if defined(CONFIG_UCQUICC) && 0 | ||
187 | printk(KERN_INFO "uCquicc serial string [%s]\n",getserialnum()); | ||
188 | p = scc1_hwaddr = gethwaddr(0); | ||
189 | printk(KERN_INFO "uCquicc hwaddr %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", | ||
190 | p[0], p[1], p[2], p[3], p[4], p[5]); | ||
191 | |||
192 | p = getbenv("APPEND"); | ||
193 | if (p) | ||
194 | strcpy(p,command); | ||
195 | else | ||
196 | command[0] = 0; | ||
197 | #else | ||
198 | scc1_hwaddr = "\00\01\02\03\04\05"; | ||
199 | #endif | ||
200 | |||
201 | mach_sched_init = BSP_sched_init; | ||
202 | mach_tick = BSP_tick; | ||
203 | mach_gettimeoffset = BSP_gettimeoffset; | ||
204 | mach_gettod = BSP_gettod; | ||
205 | mach_hwclk = NULL; | ||
206 | mach_set_clock_mmss = NULL; | ||
207 | mach_reset = BSP_reset; | ||
208 | } | ||
diff --git a/arch/m68knommu/platform/68360/entry.S b/arch/m68knommu/platform/68360/entry.S new file mode 100644 index 000000000000..f7bc80a60e0f --- /dev/null +++ b/arch/m68knommu/platform/68360/entry.S | |||
@@ -0,0 +1,184 @@ | |||
1 | /* | ||
2 | * linux/arch/m68knommu/platform/68360/entry.S | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
5 | * Copyright (C) 2001 SED Systems, a Division of Calian Ltd. | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file README.legal in the main directory of this archive | ||
9 | * for more details. | ||
10 | * | ||
11 | * Linux/m68k support by Hamish Macdonald | ||
12 | * M68360 Port by SED Systems, and Lineo. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/sys.h> | ||
17 | #include <linux/linkage.h> | ||
18 | #include <asm/thread_info.h> | ||
19 | #include <asm/unistd.h> | ||
20 | #include <asm/errno.h> | ||
21 | #include <asm/setup.h> | ||
22 | #include <asm/segment.h> | ||
23 | #include <asm/traps.h> | ||
24 | #include <asm/asm-offsets.h> | ||
25 | #include <asm/entry.h> | ||
26 | |||
27 | .text | ||
28 | |||
29 | .globl system_call | ||
30 | .globl resume | ||
31 | .globl ret_from_exception | ||
32 | .globl ret_from_signal | ||
33 | .globl sys_call_table | ||
34 | .globl ret_from_interrupt | ||
35 | .globl bad_interrupt | ||
36 | .globl inthandler | ||
37 | |||
38 | badsys: | ||
39 | movel #-ENOSYS,%sp@(PT_D0) | ||
40 | jra ret_from_exception | ||
41 | |||
42 | do_trace: | ||
43 | movel #-ENOSYS,%sp@(PT_D0) /* needed for strace*/ | ||
44 | subql #4,%sp | ||
45 | SAVE_SWITCH_STACK | ||
46 | jbsr syscall_trace | ||
47 | RESTORE_SWITCH_STACK | ||
48 | addql #4,%sp | ||
49 | movel %sp@(PT_ORIG_D0),%d1 | ||
50 | movel #-ENOSYS,%d0 | ||
51 | cmpl #NR_syscalls,%d1 | ||
52 | jcc 1f | ||
53 | lsl #2,%d1 | ||
54 | lea sys_call_table, %a0 | ||
55 | jbsr %a0@(%d1) | ||
56 | |||
57 | 1: movel %d0,%sp@(PT_D0) /* save the return value */ | ||
58 | subql #4,%sp /* dummy return address */ | ||
59 | SAVE_SWITCH_STACK | ||
60 | jbsr syscall_trace | ||
61 | |||
62 | ret_from_signal: | ||
63 | RESTORE_SWITCH_STACK | ||
64 | addql #4,%sp | ||
65 | jra ret_from_exception | ||
66 | |||
67 | ENTRY(system_call) | ||
68 | SAVE_ALL | ||
69 | |||
70 | /* save top of frame*/ | ||
71 | pea %sp@ | ||
72 | jbsr set_esp0 | ||
73 | addql #4,%sp | ||
74 | |||
75 | btst #PF_TRACESYS_BIT,%a2@(TASK_FLAGS+PF_TRACESYS_OFF) | ||
76 | jne do_trace | ||
77 | cmpl #NR_syscalls,%d0 | ||
78 | jcc badsys | ||
79 | lsl #2,%d0 | ||
80 | lea sys_call_table,%a0 | ||
81 | movel %a0@(%d0), %a0 | ||
82 | jbsr %a0@ | ||
83 | movel %d0,%sp@(PT_D0) /* save the return value*/ | ||
84 | |||
85 | ret_from_exception: | ||
86 | btst #5,%sp@(PT_SR) /* check if returning to kernel*/ | ||
87 | jeq Luser_return /* if so, skip resched, signals*/ | ||
88 | |||
89 | Lkernel_return: | ||
90 | RESTORE_ALL | ||
91 | |||
92 | Luser_return: | ||
93 | /* only allow interrupts when we are really the last one on the*/ | ||
94 | /* kernel stack, otherwise stack overflow can occur during*/ | ||
95 | /* heavy interrupt load*/ | ||
96 | andw #ALLOWINT,%sr | ||
97 | |||
98 | movel %sp,%d1 /* get thread_info pointer */ | ||
99 | andl #0xffffe000,%d1 | ||
100 | movel %d1,%a2 | ||
101 | move %a2@(TI_FLAGS),%d1 /* thread_info->flags */ | ||
102 | andl #_TIF_WORK_MASK,%d1 | ||
103 | jne Lwork_to_do | ||
104 | RESTORE_ALL | ||
105 | |||
106 | Lwork_to_do: | ||
107 | movel %a2@(TI_FLAGS),%d1 /* thread_info->flags */ | ||
108 | btst #TIF_NEED_RESCHED,%d1 | ||
109 | jne reschedule | ||
110 | |||
111 | Lsignal_return: | ||
112 | subql #4,%sp /* dummy return address*/ | ||
113 | SAVE_SWITCH_STACK | ||
114 | pea %sp@(SWITCH_STACK_SIZE) | ||
115 | clrl %sp@- | ||
116 | bsrw do_signal | ||
117 | addql #8,%sp | ||
118 | RESTORE_SWITCH_STACK | ||
119 | addql #4,%sp | ||
120 | Lreturn: | ||
121 | RESTORE_ALL | ||
122 | |||
123 | /* | ||
124 | * This is the main interrupt handler, responsible for calling process_int() | ||
125 | */ | ||
126 | inthandler: | ||
127 | SAVE_ALL | ||
128 | addql #1,local_irq_count /* put exception # in d0*/ | ||
129 | movew %sp@(PT_VECTOR), %d0 | ||
130 | and.l #0x3ff, %d0 | ||
131 | lsr.l #0x02, %d0 | ||
132 | |||
133 | movel %sp,%sp@- | ||
134 | movel %d0,%sp@- /* put vector # on stack*/ | ||
135 | jbsr process_int /* process the IRQ*/ | ||
136 | 3: addql #8,%sp /* pop parameters off stack*/ | ||
137 | bra ret_from_interrupt | ||
138 | |||
139 | ret_from_interrupt: | ||
140 | subql #1,local_irq_count | ||
141 | jeq 1f | ||
142 | 2: | ||
143 | RESTORE_ALL | ||
144 | 1: | ||
145 | moveb %sp@(PT_SR), %d0 | ||
146 | and #7, %d0 | ||
147 | jhi 2b | ||
148 | /* check if we need to do software interrupts */ | ||
149 | |||
150 | movel irq_stat+CPUSTAT_SOFTIRQ_PENDING,%d0 | ||
151 | jeq ret_from_exception | ||
152 | |||
153 | pea ret_from_exception | ||
154 | jra do_softirq | ||
155 | |||
156 | |||
157 | /* | ||
158 | * Handler for uninitialized and spurious interrupts. | ||
159 | */ | ||
160 | bad_interrupt: | ||
161 | addql #1,num_spurious | ||
162 | rte | ||
163 | |||
164 | /* | ||
165 | * Beware - when entering resume, prev (the current task) is | ||
166 | * in a0, next (the new task) is in a1,so don't change these | ||
167 | * registers until their contents are no longer needed. | ||
168 | */ | ||
169 | ENTRY(resume) | ||
170 | movel %a0,%d1 /* save prev thread in d1 */ | ||
171 | movew %sr,%a0@(TASK_THREAD+THREAD_SR) /* save sr */ | ||
172 | movel %usp,%a2 /* save usp */ | ||
173 | movel %a2,%a0@(TASK_THREAD+THREAD_USP) | ||
174 | |||
175 | SAVE_SWITCH_STACK | ||
176 | movel %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack */ | ||
177 | movel %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */ | ||
178 | RESTORE_SWITCH_STACK | ||
179 | |||
180 | movel %a1@(TASK_THREAD+THREAD_USP),%a0 /* restore user stack */ | ||
181 | movel %a0,%usp | ||
182 | movew %a1@(TASK_THREAD+THREAD_SR),%sr /* restore thread status reg */ | ||
183 | rts | ||
184 | |||
diff --git a/arch/m68knommu/platform/68360/ints.c b/arch/m68knommu/platform/68360/ints.c new file mode 100644 index 000000000000..ba184db1651b --- /dev/null +++ b/arch/m68knommu/platform/68360/ints.c | |||
@@ -0,0 +1,335 @@ | |||
1 | /* | ||
2 | * linux/arch/$(ARCH)/platform/$(PLATFORM)/ints.c | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file COPYING in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * Copyright (c) 2000 Michael Leslie <mleslie@lineo.com> | ||
9 | * Copyright (c) 1996 Roman Zippel | ||
10 | * Copyright (c) 1999 D. Jeff Dionne <jeff@uclinux.org> | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include <linux/kernel_stat.h> | ||
19 | #include <linux/errno.h> | ||
20 | |||
21 | #include <asm/system.h> | ||
22 | #include <asm/irq.h> | ||
23 | #include <asm/traps.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <asm/machdep.h> | ||
26 | #include <asm/setup.h> | ||
27 | #include <asm/m68360.h> | ||
28 | |||
29 | /* from quicc/commproc.c: */ | ||
30 | extern QUICC *pquicc; | ||
31 | extern void cpm_interrupt_init(void); | ||
32 | |||
33 | #define INTERNAL_IRQS (96) | ||
34 | |||
35 | /* assembler routines */ | ||
36 | asmlinkage void system_call(void); | ||
37 | asmlinkage void buserr(void); | ||
38 | asmlinkage void trap(void); | ||
39 | asmlinkage irqreturn_t bad_interrupt(void); | ||
40 | asmlinkage irqreturn_t inthandler(void); | ||
41 | |||
42 | extern void *_ramvec[]; | ||
43 | |||
44 | /* The number of spurious interrupts */ | ||
45 | volatile unsigned int num_spurious; | ||
46 | unsigned int local_irq_count[NR_CPUS]; | ||
47 | |||
48 | /* irq node variables for the 32 (potential) on chip sources */ | ||
49 | static irq_node_t int_irq_list[INTERNAL_IRQS]; | ||
50 | |||
51 | static short int_irq_ablecount[INTERNAL_IRQS]; | ||
52 | |||
53 | /* | ||
54 | * This function should be called during kernel startup to initialize | ||
55 | * IRQ handling routines. | ||
56 | */ | ||
57 | |||
58 | void init_IRQ(void) | ||
59 | { | ||
60 | int i; | ||
61 | int vba = (CPM_VECTOR_BASE<<4); | ||
62 | |||
63 | /* set up the vectors */ | ||
64 | _ramvec[2] = buserr; | ||
65 | _ramvec[3] = trap; | ||
66 | _ramvec[4] = trap; | ||
67 | _ramvec[5] = trap; | ||
68 | _ramvec[6] = trap; | ||
69 | _ramvec[7] = trap; | ||
70 | _ramvec[8] = trap; | ||
71 | _ramvec[9] = trap; | ||
72 | _ramvec[10] = trap; | ||
73 | _ramvec[11] = trap; | ||
74 | _ramvec[12] = trap; | ||
75 | _ramvec[13] = trap; | ||
76 | _ramvec[14] = trap; | ||
77 | _ramvec[15] = trap; | ||
78 | |||
79 | _ramvec[32] = system_call; | ||
80 | _ramvec[33] = trap; | ||
81 | |||
82 | |||
83 | cpm_interrupt_init(); | ||
84 | |||
85 | /* set up CICR for vector base address and irq level */ | ||
86 | /* irl = 4, hp = 1f - see MC68360UM p 7-377 */ | ||
87 | pquicc->intr_cicr = 0x00e49f00 | vba; | ||
88 | |||
89 | /* CPM interrupt vectors: (p 7-376) */ | ||
90 | _ramvec[vba+CPMVEC_ERROR] = bad_interrupt; /* Error */ | ||
91 | _ramvec[vba+CPMVEC_PIO_PC11] = inthandler; /* pio - pc11 */ | ||
92 | _ramvec[vba+CPMVEC_PIO_PC10] = inthandler; /* pio - pc10 */ | ||
93 | _ramvec[vba+CPMVEC_SMC2] = inthandler; /* smc2/pip */ | ||
94 | _ramvec[vba+CPMVEC_SMC1] = inthandler; /* smc1 */ | ||
95 | _ramvec[vba+CPMVEC_SPI] = inthandler; /* spi */ | ||
96 | _ramvec[vba+CPMVEC_PIO_PC9] = inthandler; /* pio - pc9 */ | ||
97 | _ramvec[vba+CPMVEC_TIMER4] = inthandler; /* timer 4 */ | ||
98 | _ramvec[vba+CPMVEC_RESERVED1] = inthandler; /* reserved */ | ||
99 | _ramvec[vba+CPMVEC_PIO_PC8] = inthandler; /* pio - pc8 */ | ||
100 | _ramvec[vba+CPMVEC_PIO_PC7] = inthandler; /* pio - pc7 */ | ||
101 | _ramvec[vba+CPMVEC_PIO_PC6] = inthandler; /* pio - pc6 */ | ||
102 | _ramvec[vba+CPMVEC_TIMER3] = inthandler; /* timer 3 */ | ||
103 | _ramvec[vba+CPMVEC_RISCTIMER] = inthandler; /* reserved */ | ||
104 | _ramvec[vba+CPMVEC_PIO_PC5] = inthandler; /* pio - pc5 */ | ||
105 | _ramvec[vba+CPMVEC_PIO_PC4] = inthandler; /* pio - pc4 */ | ||
106 | _ramvec[vba+CPMVEC_RESERVED2] = inthandler; /* reserved */ | ||
107 | _ramvec[vba+CPMVEC_RISCTIMER] = inthandler; /* timer table */ | ||
108 | _ramvec[vba+CPMVEC_TIMER2] = inthandler; /* timer 2 */ | ||
109 | _ramvec[vba+CPMVEC_RESERVED3] = inthandler; /* reserved */ | ||
110 | _ramvec[vba+CPMVEC_IDMA2] = inthandler; /* idma 2 */ | ||
111 | _ramvec[vba+CPMVEC_IDMA1] = inthandler; /* idma 1 */ | ||
112 | _ramvec[vba+CPMVEC_SDMA_CB_ERR] = inthandler; /* sdma channel bus error */ | ||
113 | _ramvec[vba+CPMVEC_PIO_PC3] = inthandler; /* pio - pc3 */ | ||
114 | _ramvec[vba+CPMVEC_PIO_PC2] = inthandler; /* pio - pc2 */ | ||
115 | /* _ramvec[vba+CPMVEC_TIMER1] = cpm_isr_timer1; */ /* timer 1 */ | ||
116 | _ramvec[vba+CPMVEC_TIMER1] = inthandler; /* timer 1 */ | ||
117 | _ramvec[vba+CPMVEC_PIO_PC1] = inthandler; /* pio - pc1 */ | ||
118 | _ramvec[vba+CPMVEC_SCC4] = inthandler; /* scc 4 */ | ||
119 | _ramvec[vba+CPMVEC_SCC3] = inthandler; /* scc 3 */ | ||
120 | _ramvec[vba+CPMVEC_SCC2] = inthandler; /* scc 2 */ | ||
121 | _ramvec[vba+CPMVEC_SCC1] = inthandler; /* scc 1 */ | ||
122 | _ramvec[vba+CPMVEC_PIO_PC0] = inthandler; /* pio - pc0 */ | ||
123 | |||
124 | |||
125 | /* turn off all CPM interrupts */ | ||
126 | pquicc->intr_cimr = 0x00000000; | ||
127 | |||
128 | /* initialize handlers */ | ||
129 | for (i = 0; i < INTERNAL_IRQS; i++) { | ||
130 | int_irq_list[i].handler = NULL; | ||
131 | int_irq_list[i].flags = IRQ_FLG_STD; | ||
132 | int_irq_list[i].dev_id = NULL; | ||
133 | int_irq_list[i].devname = NULL; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | #if 0 | ||
138 | void M68360_insert_irq(irq_node_t **list, irq_node_t *node) | ||
139 | { | ||
140 | unsigned long flags; | ||
141 | irq_node_t *cur; | ||
142 | |||
143 | if (!node->dev_id) | ||
144 | printk(KERN_INFO "%s: Warning: dev_id of %s is zero\n", | ||
145 | __FUNCTION__, node->devname); | ||
146 | |||
147 | local_irq_save(flags); | ||
148 | |||
149 | cur = *list; | ||
150 | |||
151 | while (cur) { | ||
152 | list = &cur->next; | ||
153 | cur = cur->next; | ||
154 | } | ||
155 | |||
156 | node->next = cur; | ||
157 | *list = node; | ||
158 | |||
159 | local_irq_restore(flags); | ||
160 | } | ||
161 | |||
162 | void M68360_delete_irq(irq_node_t **list, void *dev_id) | ||
163 | { | ||
164 | unsigned long flags; | ||
165 | irq_node_t *node; | ||
166 | |||
167 | local_irq_save(flags); | ||
168 | |||
169 | for (node = *list; node; list = &node->next, node = *list) { | ||
170 | if (node->dev_id == dev_id) { | ||
171 | *list = node->next; | ||
172 | /* Mark it as free. */ | ||
173 | node->handler = NULL; | ||
174 | local_irq_restore(flags); | ||
175 | return; | ||
176 | } | ||
177 | } | ||
178 | local_irq_restore(flags); | ||
179 | printk (KERN_INFO "%s: tried to remove invalid irq\n", __FUNCTION__); | ||
180 | } | ||
181 | #endif | ||
182 | |||
183 | int request_irq( | ||
184 | unsigned int irq, | ||
185 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
186 | unsigned long flags, | ||
187 | const char *devname, | ||
188 | void *dev_id) | ||
189 | { | ||
190 | int mask = (1<<irq); | ||
191 | |||
192 | irq += (CPM_VECTOR_BASE<<4); | ||
193 | |||
194 | if (irq >= INTERNAL_IRQS) { | ||
195 | printk (KERN_ERR "%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname); | ||
196 | return -ENXIO; | ||
197 | } | ||
198 | |||
199 | if (!(int_irq_list[irq].flags & IRQ_FLG_STD)) { | ||
200 | if (int_irq_list[irq].flags & IRQ_FLG_LOCK) { | ||
201 | printk(KERN_ERR "%s: IRQ %d from %s is not replaceable\n", | ||
202 | __FUNCTION__, irq, int_irq_list[irq].devname); | ||
203 | return -EBUSY; | ||
204 | } | ||
205 | if (flags & IRQ_FLG_REPLACE) { | ||
206 | printk(KERN_ERR "%s: %s can't replace IRQ %d from %s\n", | ||
207 | __FUNCTION__, devname, irq, int_irq_list[irq].devname); | ||
208 | return -EBUSY; | ||
209 | } | ||
210 | } | ||
211 | int_irq_list[irq].handler = handler; | ||
212 | int_irq_list[irq].flags = flags; | ||
213 | int_irq_list[irq].dev_id = dev_id; | ||
214 | int_irq_list[irq].devname = devname; | ||
215 | |||
216 | /* enable in the CIMR */ | ||
217 | if (!int_irq_ablecount[irq]) | ||
218 | pquicc->intr_cimr |= mask; | ||
219 | /* *(volatile unsigned long *)0xfffff304 &= ~(1<<irq); */ | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | EXPORT_SYMBOL(request_irq); | ||
225 | |||
226 | void free_irq(unsigned int irq, void *dev_id) | ||
227 | { | ||
228 | if (irq >= INTERNAL_IRQS) { | ||
229 | printk (KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq); | ||
230 | return; | ||
231 | } | ||
232 | |||
233 | if (int_irq_list[irq].dev_id != dev_id) | ||
234 | printk(KERN_INFO "%s: removing probably wrong IRQ %d from %s\n", | ||
235 | __FUNCTION__, irq, int_irq_list[irq].devname); | ||
236 | int_irq_list[irq].handler = NULL; | ||
237 | int_irq_list[irq].flags = IRQ_FLG_STD; | ||
238 | int_irq_list[irq].dev_id = NULL; | ||
239 | int_irq_list[irq].devname = NULL; | ||
240 | |||
241 | *(volatile unsigned long *)0xfffff304 |= 1<<irq; | ||
242 | } | ||
243 | |||
244 | EXPORT_SYMBOL(free_irq); | ||
245 | |||
246 | #if 0 | ||
247 | /* | ||
248 | * Enable/disable a particular machine specific interrupt source. | ||
249 | * Note that this may affect other interrupts in case of a shared interrupt. | ||
250 | * This function should only be called for a _very_ short time to change some | ||
251 | * internal data, that may not be changed by the interrupt at the same time. | ||
252 | * int_(enable|disable)_irq calls may also be nested. | ||
253 | */ | ||
254 | void M68360_enable_irq(unsigned int irq) | ||
255 | { | ||
256 | if (irq >= INTERNAL_IRQS) { | ||
257 | printk(KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq); | ||
258 | return; | ||
259 | } | ||
260 | |||
261 | if (--int_irq_ablecount[irq]) | ||
262 | return; | ||
263 | |||
264 | /* enable the interrupt */ | ||
265 | *(volatile unsigned long *)0xfffff304 &= ~(1<<irq); | ||
266 | } | ||
267 | |||
268 | void M68360_disable_irq(unsigned int irq) | ||
269 | { | ||
270 | if (irq >= INTERNAL_IRQS) { | ||
271 | printk(KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq); | ||
272 | return; | ||
273 | } | ||
274 | |||
275 | if (int_irq_ablecount[irq]++) | ||
276 | return; | ||
277 | |||
278 | /* disable the interrupt */ | ||
279 | *(volatile unsigned long *)0xfffff304 |= 1<<irq; | ||
280 | } | ||
281 | #endif | ||
282 | |||
283 | int show_interrupts(struct seq_file *p, void *v) | ||
284 | { | ||
285 | int i = *(loff_t *) v; | ||
286 | |||
287 | if (i < NR_IRQS) { | ||
288 | if (int_irq_list[i].devname) { | ||
289 | seq_printf(p, "%3d: %10u ", i, kstat_cpu(0).irqs[i]); | ||
290 | if (int_irq_list[i].flags & IRQ_FLG_LOCK) | ||
291 | seq_printf(p, "L "); | ||
292 | else | ||
293 | seq_printf(p, " "); | ||
294 | seq_printf(p, "%s\n", int_irq_list[i].devname); | ||
295 | } | ||
296 | } | ||
297 | if (i == NR_IRQS) | ||
298 | seq_printf(p, " : %10u spurious\n", num_spurious); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | /* The 68k family did not have a good way to determine the source | ||
304 | * of interrupts until later in the family. The EC000 core does | ||
305 | * not provide the vector number on the stack, we vector everything | ||
306 | * into one vector and look in the blasted mask register... | ||
307 | * This code is designed to be fast, almost constant time, not clean! | ||
308 | */ | ||
309 | void process_int(int vec, struct pt_regs *fp) | ||
310 | { | ||
311 | int irq; | ||
312 | int mask; | ||
313 | |||
314 | /* unsigned long pend = *(volatile unsigned long *)0xfffff30c; */ | ||
315 | |||
316 | /* irq = vec + (CPM_VECTOR_BASE<<4); */ | ||
317 | irq = vec; | ||
318 | |||
319 | /* unsigned long pend = *(volatile unsigned long *)pquicc->intr_cipr; */ | ||
320 | |||
321 | /* Bugger all that weirdness. For the moment, I seem to know where I came from; | ||
322 | * vec is passed from a specific ISR, so I'll use it. */ | ||
323 | |||
324 | if (int_irq_list[irq].handler) { | ||
325 | int_irq_list[irq].handler(irq , int_irq_list[irq].dev_id, fp); | ||
326 | kstat_cpu(0).irqs[irq]++; | ||
327 | pquicc->intr_cisr = (1 << vec); /* indicate that irq has been serviced */ | ||
328 | } else { | ||
329 | printk(KERN_ERR "unregistered interrupt %d!\nTurning it off in the CIMR...\n", irq); | ||
330 | /* *(volatile unsigned long *)0xfffff304 |= mask; */ | ||
331 | pquicc->intr_cimr &= ~(1 << vec); | ||
332 | num_spurious += 1; | ||
333 | } | ||
334 | return(IRQ_HANDLED); | ||
335 | } | ||