[TG3]: Set minimal hw interrupt mitigation.
[linux-2.6/verdex.git] / arch / ppc / 8xx_io / commproc.c
blob0cc2e7a9cb11fdffdd979f640103549f8745a63e
1 /*
2 * General Purpose functions for the global management of the
3 * Communication Processor Module.
4 * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
6 * In addition to the individual control of the communication
7 * channels, there are a few functions that globally affect the
8 * communication processor.
10 * Buffer descriptors must be allocated from the dual ported memory
11 * space. The allocator for that is here. When the communication
12 * process is reset, we reclaim the memory available. There is
13 * currently no deallocator for this memory.
14 * The amount of space available is platform dependent. On the
15 * MBX, the EPPC software loads additional microcode into the
16 * communication processor, and uses some of the DP ram for this
17 * purpose. Current, the first 512 bytes and the last 256 bytes of
18 * memory are used. Right now I am conservative and only use the
19 * memory that can never be used for microcode. If there are
20 * applications that require more DP ram, we can expand the boundaries
21 * but then we have to be careful of any downloaded microcode.
23 #include <linux/errno.h>
24 #include <linux/sched.h>
25 #include <linux/kernel.h>
26 #include <linux/dma-mapping.h>
27 #include <linux/param.h>
28 #include <linux/string.h>
29 #include <linux/mm.h>
30 #include <linux/interrupt.h>
31 #include <linux/irq.h>
32 #include <linux/module.h>
33 #include <asm/mpc8xx.h>
34 #include <asm/page.h>
35 #include <asm/pgtable.h>
36 #include <asm/8xx_immap.h>
37 #include <asm/commproc.h>
38 #include <asm/io.h>
39 #include <asm/tlbflush.h>
40 #include <asm/rheap.h>
42 extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep);
44 static void m8xx_cpm_dpinit(void);
45 static uint host_buffer; /* One page of host buffer */
46 static uint host_end; /* end + 1 */
47 cpm8xx_t *cpmp; /* Pointer to comm processor space */
49 /* CPM interrupt vector functions.
51 struct cpm_action {
52 void (*handler)(void *, struct pt_regs * regs);
53 void *dev_id;
55 static struct cpm_action cpm_vecs[CPMVEC_NR];
56 static irqreturn_t cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
57 static irqreturn_t cpm_error_interrupt(int irq, void *dev, struct pt_regs * regs);
58 static void alloc_host_memory(void);
59 /* Define a table of names to identify CPM interrupt handlers in
60 * /proc/interrupts.
62 const char *cpm_int_name[] =
63 { "error", "PC4", "PC5", "SMC2",
64 "SMC1", "SPI", "PC6", "Timer 4",
65 "", "PC7", "PC8", "PC9",
66 "Timer 3", "", "PC10", "PC11",
67 "I2C", "RISC Timer", "Timer 2", "",
68 "IDMA2", "IDMA1", "SDMA error", "PC12",
69 "PC13", "Timer 1", "PC14", "SCC4",
70 "SCC3", "SCC2", "SCC1", "PC15"
73 static void
74 cpm_mask_irq(unsigned int irq)
76 int cpm_vec = irq - CPM_IRQ_OFFSET;
78 ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << cpm_vec);
81 static void
82 cpm_unmask_irq(unsigned int irq)
84 int cpm_vec = irq - CPM_IRQ_OFFSET;
86 ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << cpm_vec);
89 static void
90 cpm_ack(unsigned int irq)
92 /* We do not need to do anything here. */
95 static void
96 cpm_eoi(unsigned int irq)
98 int cpm_vec = irq - CPM_IRQ_OFFSET;
100 ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << cpm_vec);
103 struct hw_interrupt_type cpm_pic = {
104 .typename = " CPM ",
105 .enable = cpm_unmask_irq,
106 .disable = cpm_mask_irq,
107 .ack = cpm_ack,
108 .end = cpm_eoi,
111 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
113 void
114 m8xx_cpm_reset(uint bootpage)
116 volatile immap_t *imp;
117 volatile cpm8xx_t *commproc;
118 pte_t *pte;
120 imp = (immap_t *)IMAP_ADDR;
121 commproc = (cpm8xx_t *)&imp->im_cpm;
123 #ifdef CONFIG_UCODE_PATCH
124 /* Perform a reset.
126 commproc->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG);
128 /* Wait for it.
130 while (commproc->cp_cpcr & CPM_CR_FLG);
132 cpm_load_patch(imp);
133 #endif
135 /* Set SDMA Bus Request priority 5.
136 * On 860T, this also enables FEC priority 6. I am not sure
137 * this is what we realy want for some applications, but the
138 * manual recommends it.
139 * Bit 25, FAM can also be set to use FEC aggressive mode (860T).
141 imp->im_siu_conf.sc_sdcr = 1;
143 /* Reclaim the DP memory for our use. */
144 m8xx_cpm_dpinit();
146 /* get the PTE for the bootpage */
147 if (!get_pteptr(&init_mm, bootpage, &pte))
148 panic("get_pteptr failed\n");
150 /* and make it uncachable */
151 pte_val(*pte) |= _PAGE_NO_CACHE;
152 _tlbie(bootpage);
154 host_buffer = bootpage;
155 host_end = host_buffer + PAGE_SIZE;
157 /* Tell everyone where the comm processor resides.
159 cpmp = (cpm8xx_t *)commproc;
162 /* We used to do this earlier, but have to postpone as long as possible
163 * to ensure the kernel VM is now running.
165 static void
166 alloc_host_memory(void)
168 dma_addr_t physaddr;
170 /* Set the host page for allocation.
172 host_buffer = (uint)dma_alloc_coherent(NULL, PAGE_SIZE, &physaddr,
173 GFP_KERNEL);
174 host_end = host_buffer + PAGE_SIZE;
177 /* This is called during init_IRQ. We used to do it above, but this
178 * was too early since init_IRQ was not yet called.
180 static struct irqaction cpm_error_irqaction = {
181 .handler = cpm_error_interrupt,
182 .mask = CPU_MASK_NONE,
184 static struct irqaction cpm_interrupt_irqaction = {
185 .handler = cpm_interrupt,
186 .mask = CPU_MASK_NONE,
187 .name = "CPM cascade",
190 void
191 cpm_interrupt_init(void)
193 int i;
195 /* Initialize the CPM interrupt controller.
197 ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr =
198 (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
199 ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK;
200 ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0;
202 /* install the CPM interrupt controller routines for the CPM
203 * interrupt vectors
205 for ( i = CPM_IRQ_OFFSET ; i < CPM_IRQ_OFFSET + NR_CPM_INTS ; i++ )
206 irq_desc[i].handler = &cpm_pic;
208 /* Set our interrupt handler with the core CPU. */
209 if (setup_irq(CPM_INTERRUPT, &cpm_interrupt_irqaction))
210 panic("Could not allocate CPM IRQ!");
212 /* Install our own error handler. */
213 cpm_error_irqaction.name = cpm_int_name[CPMVEC_ERROR];
214 if (setup_irq(CPM_IRQ_OFFSET + CPMVEC_ERROR, &cpm_error_irqaction))
215 panic("Could not allocate CPM error IRQ!");
217 ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN;
221 * Get the CPM interrupt vector.
224 cpm_get_irq(struct pt_regs *regs)
226 int cpm_vec;
228 /* Get the vector by setting the ACK bit and then reading
229 * the register.
231 ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1;
232 cpm_vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr;
233 cpm_vec >>= 11;
235 return cpm_vec;
238 /* CPM interrupt controller cascade interrupt.
240 static irqreturn_t
241 cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
243 /* This interrupt handler never actually gets called. It is
244 * installed only to unmask the CPM cascade interrupt in the SIU
245 * and to make the CPM cascade interrupt visible in /proc/interrupts.
247 return IRQ_HANDLED;
250 /* The CPM can generate the error interrupt when there is a race condition
251 * between generating and masking interrupts. All we have to do is ACK it
252 * and return. This is a no-op function so we don't need any special
253 * tests in the interrupt handler.
255 static irqreturn_t
256 cpm_error_interrupt(int irq, void *dev, struct pt_regs *regs)
258 return IRQ_HANDLED;
261 /* A helper function to translate the handler prototype required by
262 * request_irq() to the handler prototype required by cpm_install_handler().
264 static irqreturn_t
265 cpm_handler_helper(int irq, void *dev_id, struct pt_regs *regs)
267 int cpm_vec = irq - CPM_IRQ_OFFSET;
269 (*cpm_vecs[cpm_vec].handler)(dev_id, regs);
271 return IRQ_HANDLED;
274 /* Install a CPM interrupt handler.
275 * This routine accepts a CPM interrupt vector in the range 0 to 31.
276 * This routine is retained for backward compatibility. Rather than using
277 * this routine to install a CPM interrupt handler, you can now use
278 * request_irq() with an IRQ in the range CPM_IRQ_OFFSET to
279 * CPM_IRQ_OFFSET + NR_CPM_INTS - 1 (16 to 47).
281 * Notice that the prototype of the interrupt handler function must be
282 * different depending on whether you install the handler with
283 * request_irq() or cpm_install_handler().
285 void
286 cpm_install_handler(int cpm_vec, void (*handler)(void *, struct pt_regs *regs),
287 void *dev_id)
289 int err;
291 /* If null handler, assume we are trying to free the IRQ.
293 if (!handler) {
294 free_irq(CPM_IRQ_OFFSET + cpm_vec, dev_id);
295 return;
298 if (cpm_vecs[cpm_vec].handler != 0)
299 printk(KERN_INFO "CPM interrupt %x replacing %x\n",
300 (uint)handler, (uint)cpm_vecs[cpm_vec].handler);
301 cpm_vecs[cpm_vec].handler = handler;
302 cpm_vecs[cpm_vec].dev_id = dev_id;
304 if ((err = request_irq(CPM_IRQ_OFFSET + cpm_vec, cpm_handler_helper,
305 0, cpm_int_name[cpm_vec], dev_id)))
306 printk(KERN_ERR "request_irq() returned %d for CPM vector %d\n",
307 err, cpm_vec);
310 /* Free a CPM interrupt handler.
311 * This routine accepts a CPM interrupt vector in the range 0 to 31.
312 * This routine is retained for backward compatibility.
314 void
315 cpm_free_handler(int cpm_vec)
317 request_irq(CPM_IRQ_OFFSET + cpm_vec, NULL, 0, 0,
318 cpm_vecs[cpm_vec].dev_id);
320 cpm_vecs[cpm_vec].handler = NULL;
321 cpm_vecs[cpm_vec].dev_id = NULL;
324 /* We also own one page of host buffer space for the allocation of
325 * UART "fifos" and the like.
327 uint
328 m8xx_cpm_hostalloc(uint size)
330 uint retloc;
332 if (host_buffer == 0)
333 alloc_host_memory();
335 if ((host_buffer + size) >= host_end)
336 return(0);
338 retloc = host_buffer;
339 host_buffer += size;
341 return(retloc);
344 /* Set a baud rate generator. This needs lots of work. There are
345 * four BRGs, any of which can be wired to any channel.
346 * The internal baud rate clock is the system clock divided by 16.
347 * This assumes the baudrate is 16x oversampled by the uart.
349 #define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq)
350 #define BRG_UART_CLK (BRG_INT_CLK/16)
351 #define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16)
353 void
354 cpm_setbrg(uint brg, uint rate)
356 volatile uint *bp;
358 /* This is good enough to get SMCs running.....
360 bp = (uint *)&cpmp->cp_brgc1;
361 bp += brg;
362 /* The BRG has a 12-bit counter. For really slow baud rates (or
363 * really fast processors), we may have to further divide by 16.
365 if (((BRG_UART_CLK / rate) - 1) < 4096)
366 *bp = (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN;
367 else
368 *bp = (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) |
369 CPM_BRG_EN | CPM_BRG_DIV16;
373 * dpalloc / dpfree bits.
375 static spinlock_t cpm_dpmem_lock;
377 * 16 blocks should be enough to satisfy all requests
378 * until the memory subsystem goes up...
380 static rh_block_t cpm_boot_dpmem_rh_block[16];
381 static rh_info_t cpm_dpmem_info;
383 #define CPM_DPMEM_ALIGNMENT 8
385 void m8xx_cpm_dpinit(void)
387 cpm8xx_t *cp = &((immap_t *)IMAP_ADDR)->im_cpm;
389 spin_lock_init(&cpm_dpmem_lock);
391 /* Initialize the info header */
392 rh_init(&cpm_dpmem_info, CPM_DPMEM_ALIGNMENT,
393 sizeof(cpm_boot_dpmem_rh_block) /
394 sizeof(cpm_boot_dpmem_rh_block[0]),
395 cpm_boot_dpmem_rh_block);
398 * Attach the usable dpmem area.
399 * XXX: This is actually crap. CPM_DATAONLY_BASE and
400 * CPM_DATAONLY_SIZE are a subset of the available dparm. It varies
401 * with the processor and the microcode patches applied / activated.
402 * But the following should be at least safe.
404 rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
408 * Allocate the requested size worth of DP memory.
409 * This function used to return an index into the DPRAM area.
410 * Now it returns the actuall physical address of that area.
411 * use m8xx_cpm_dpram_offset() to get the index
413 uint cpm_dpalloc(uint size, uint align)
415 void *start;
416 unsigned long flags;
418 spin_lock_irqsave(&cpm_dpmem_lock, flags);
419 cpm_dpmem_info.alignment = align;
420 start = rh_alloc(&cpm_dpmem_info, size, "commproc");
421 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
423 return (uint)start;
425 EXPORT_SYMBOL(cpm_dpalloc);
427 int cpm_dpfree(uint offset)
429 int ret;
430 unsigned long flags;
432 spin_lock_irqsave(&cpm_dpmem_lock, flags);
433 ret = rh_free(&cpm_dpmem_info, (void *)offset);
434 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
436 return ret;
438 EXPORT_SYMBOL(cpm_dpfree);
440 uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
442 void *start;
443 unsigned long flags;
445 spin_lock_irqsave(&cpm_dpmem_lock, flags);
446 cpm_dpmem_info.alignment = align;
447 start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
448 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
450 return (uint)start;
452 EXPORT_SYMBOL(cpm_dpalloc_fixed);
454 void cpm_dpdump(void)
456 rh_dump(&cpm_dpmem_info);
458 EXPORT_SYMBOL(cpm_dpdump);
460 void *cpm_dpram_addr(uint offset)
462 return ((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem + offset;
464 EXPORT_SYMBOL(cpm_dpram_addr);