X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc%2F8xx_io%2Fcommproc.c;h=0cc2e7a9cb11fdffdd979f640103549f8745a63e;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=2688504d62bf28bbec473aaf53210a1af2b82632;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c index 2688504d6..0cc2e7a9c 100644 --- a/arch/ppc/8xx_io/commproc.c +++ b/arch/ppc/8xx_io/commproc.c @@ -23,18 +23,20 @@ #include #include #include +#include #include #include #include #include +#include #include -#include #include #include #include #include #include #include +#include #include extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep); @@ -51,68 +53,69 @@ struct cpm_action { void *dev_id; }; static struct cpm_action cpm_vecs[CPMVEC_NR]; -static void cpm_interrupt(int irq, void * dev, struct pt_regs * regs); -static void cpm_error_interrupt(void *, struct pt_regs * regs); +static irqreturn_t cpm_interrupt(int irq, void * dev, struct pt_regs * regs); +static irqreturn_t cpm_error_interrupt(int irq, void *dev, struct pt_regs * regs); static void alloc_host_memory(void); +/* Define a table of names to identify CPM interrupt handlers in + * /proc/interrupts. + */ +const char *cpm_int_name[] = + { "error", "PC4", "PC5", "SMC2", + "SMC1", "SPI", "PC6", "Timer 4", + "", "PC7", "PC8", "PC9", + "Timer 3", "", "PC10", "PC11", + "I2C", "RISC Timer", "Timer 2", "", + "IDMA2", "IDMA1", "SDMA error", "PC12", + "PC13", "Timer 1", "PC14", "SCC4", + "SCC3", "SCC2", "SCC1", "PC15" + }; -#if 1 -void -m8xx_cpm_reset(void) +static void +cpm_mask_irq(unsigned int irq) { - volatile immap_t *imp; - volatile cpm8xx_t *commproc; - - imp = (immap_t *)IMAP_ADDR; - commproc = (cpm8xx_t *)&imp->im_cpm; - -#ifdef CONFIG_UCODE_PATCH - /* Perform a reset. - */ - commproc->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG); + int cpm_vec = irq - CPM_IRQ_OFFSET; - /* Wait for it. - */ - while (commproc->cp_cpcr & CPM_CR_FLG); - - cpm_load_patch(imp); -#endif + ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << cpm_vec); +} - /* Set SDMA Bus Request priority 5. - * On 860T, this also enables FEC priority 6. I am not sure - * this is what we realy want for some applications, but the - * manual recommends it. - * Bit 25, FAM can also be set to use FEC aggressive mode (860T). - */ - imp->im_siu_conf.sc_sdcr = 1; +static void +cpm_unmask_irq(unsigned int irq) +{ + int cpm_vec = irq - CPM_IRQ_OFFSET; - /* Reclaim the DP memory for our use. */ - m8xx_cpm_dpinit(); + ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << cpm_vec); +} - /* Tell everyone where the comm processor resides. - */ - cpmp = (cpm8xx_t *)commproc; +static void +cpm_ack(unsigned int irq) +{ + /* We do not need to do anything here. */ } -/* We used to do this earlier, but have to postpone as long as possible - * to ensure the kernel VM is now running. - */ static void -alloc_host_memory() +cpm_eoi(unsigned int irq) { - uint physaddr; + int cpm_vec = irq - CPM_IRQ_OFFSET; - /* Set the host page for allocation. - */ - host_buffer = (uint)consistent_alloc(GFP_KERNEL, PAGE_SIZE, &physaddr); - host_end = host_buffer + PAGE_SIZE; + ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << cpm_vec); } -#else + +struct hw_interrupt_type cpm_pic = { + .typename = " CPM ", + .enable = cpm_unmask_irq, + .disable = cpm_mask_irq, + .ack = cpm_ack, + .end = cpm_eoi, +}; + +extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); + void -m8xx_cpm_reset(uint host_page_addr) +m8xx_cpm_reset(uint bootpage) { volatile immap_t *imp; volatile cpm8xx_t *commproc; - pte_t *pte; + pte_t *pte; imp = (immap_t *)IMAP_ADDR; commproc = (cpm8xx_t *)&imp->im_cpm; @@ -134,40 +137,61 @@ m8xx_cpm_reset(uint host_page_addr) * this is what we realy want for some applications, but the * manual recommends it. * Bit 25, FAM can also be set to use FEC aggressive mode (860T). - */ + */ imp->im_siu_conf.sc_sdcr = 1; /* Reclaim the DP memory for our use. */ m8xx_cpm_dpinit(); - /* Set the host page for allocation. - */ - host_buffer = host_page_addr; /* Host virtual page address */ - host_end = host_page_addr + PAGE_SIZE; + /* get the PTE for the bootpage */ + if (!get_pteptr(&init_mm, bootpage, &pte)) + panic("get_pteptr failed\n"); + + /* and make it uncachable */ + pte_val(*pte) |= _PAGE_NO_CACHE; + _tlbie(bootpage); - /* We need to get this page early, so I have to do it the - * hard way. - */ - if (get_pteptr(&init_mm, host_page_addr, &pte)) { - pte_val(*pte) |= _PAGE_NO_CACHE; - flush_tlb_page(init_mm.mmap, host_buffer); - } - else { - panic("Huh? No CPM host page?"); - } + host_buffer = bootpage; + host_end = host_buffer + PAGE_SIZE; /* Tell everyone where the comm processor resides. */ cpmp = (cpm8xx_t *)commproc; } -#endif + +/* We used to do this earlier, but have to postpone as long as possible + * to ensure the kernel VM is now running. + */ +static void +alloc_host_memory(void) +{ + dma_addr_t physaddr; + + /* Set the host page for allocation. + */ + host_buffer = (uint)dma_alloc_coherent(NULL, PAGE_SIZE, &physaddr, + GFP_KERNEL); + host_end = host_buffer + PAGE_SIZE; +} /* This is called during init_IRQ. We used to do it above, but this * was too early since init_IRQ was not yet called. */ +static struct irqaction cpm_error_irqaction = { + .handler = cpm_error_interrupt, + .mask = CPU_MASK_NONE, +}; +static struct irqaction cpm_interrupt_irqaction = { + .handler = cpm_interrupt, + .mask = CPU_MASK_NONE, + .name = "CPM cascade", +}; + void cpm_interrupt_init(void) { + int i; + /* Initialize the CPM interrupt controller. */ ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr = @@ -175,41 +199,52 @@ cpm_interrupt_init(void) ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK; ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0; - /* Set our interrupt handler with the core CPU. - */ - if (request_8xxirq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0) + /* install the CPM interrupt controller routines for the CPM + * interrupt vectors + */ + for ( i = CPM_IRQ_OFFSET ; i < CPM_IRQ_OFFSET + NR_CPM_INTS ; i++ ) + irq_desc[i].handler = &cpm_pic; + + /* Set our interrupt handler with the core CPU. */ + if (setup_irq(CPM_INTERRUPT, &cpm_interrupt_irqaction)) panic("Could not allocate CPM IRQ!"); - /* Install our own error handler. - */ - cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL); + /* Install our own error handler. */ + cpm_error_irqaction.name = cpm_int_name[CPMVEC_ERROR]; + if (setup_irq(CPM_IRQ_OFFSET + CPMVEC_ERROR, &cpm_error_irqaction)) + panic("Could not allocate CPM error IRQ!"); + ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN; } -/* CPM interrupt controller interrupt. -*/ -static void -cpm_interrupt(int irq, void * dev, struct pt_regs * regs) +/* + * Get the CPM interrupt vector. + */ +int +cpm_get_irq(struct pt_regs *regs) { - uint vec; + int cpm_vec; /* Get the vector by setting the ACK bit and then reading * the register. */ ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1; - vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr; - vec >>= 11; + cpm_vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr; + cpm_vec >>= 11; - if (cpm_vecs[vec].handler != 0) - (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id, regs); - else - ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); + return cpm_vec; +} - /* After servicing the interrupt, we have to remove the status - * indicator. +/* CPM interrupt controller cascade interrupt. +*/ +static irqreturn_t +cpm_interrupt(int irq, void * dev, struct pt_regs * regs) +{ + /* This interrupt handler never actually gets called. It is + * installed only to unmask the CPM cascade interrupt in the SIU + * and to make the CPM cascade interrupt visible in /proc/interrupts. */ - ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr = (1 << vec); - + return IRQ_HANDLED; } /* The CPM can generate the error interrupt when there is a race condition @@ -217,41 +252,73 @@ cpm_interrupt(int irq, void * dev, struct pt_regs * regs) * and return. This is a no-op function so we don't need any special * tests in the interrupt handler. */ -static void -cpm_error_interrupt(void *dev, struct pt_regs *regs) +static irqreturn_t +cpm_error_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + return IRQ_HANDLED; +} + +/* A helper function to translate the handler prototype required by + * request_irq() to the handler prototype required by cpm_install_handler(). + */ +static irqreturn_t +cpm_handler_helper(int irq, void *dev_id, struct pt_regs *regs) { + int cpm_vec = irq - CPM_IRQ_OFFSET; + + (*cpm_vecs[cpm_vec].handler)(dev_id, regs); + + return IRQ_HANDLED; } /* Install a CPM interrupt handler. -*/ + * This routine accepts a CPM interrupt vector in the range 0 to 31. + * This routine is retained for backward compatibility. Rather than using + * this routine to install a CPM interrupt handler, you can now use + * request_irq() with an IRQ in the range CPM_IRQ_OFFSET to + * CPM_IRQ_OFFSET + NR_CPM_INTS - 1 (16 to 47). + * + * Notice that the prototype of the interrupt handler function must be + * different depending on whether you install the handler with + * request_irq() or cpm_install_handler(). + */ void -cpm_install_handler(int vec, void (*handler)(void *, struct pt_regs *regs), +cpm_install_handler(int cpm_vec, void (*handler)(void *, struct pt_regs *regs), void *dev_id) { + int err; /* If null handler, assume we are trying to free the IRQ. */ if (!handler) { - cpm_free_handler(vec); + free_irq(CPM_IRQ_OFFSET + cpm_vec, dev_id); return; } - if (cpm_vecs[vec].handler != 0) - printk("CPM interrupt %x replacing %x\n", - (uint)handler, (uint)cpm_vecs[vec].handler); - cpm_vecs[vec].handler = handler; - cpm_vecs[vec].dev_id = dev_id; - ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec); + if (cpm_vecs[cpm_vec].handler != 0) + printk(KERN_INFO "CPM interrupt %x replacing %x\n", + (uint)handler, (uint)cpm_vecs[cpm_vec].handler); + cpm_vecs[cpm_vec].handler = handler; + cpm_vecs[cpm_vec].dev_id = dev_id; + + if ((err = request_irq(CPM_IRQ_OFFSET + cpm_vec, cpm_handler_helper, + 0, cpm_int_name[cpm_vec], dev_id))) + printk(KERN_ERR "request_irq() returned %d for CPM vector %d\n", + err, cpm_vec); } /* Free a CPM interrupt handler. -*/ + * This routine accepts a CPM interrupt vector in the range 0 to 31. + * This routine is retained for backward compatibility. + */ void -cpm_free_handler(int vec) +cpm_free_handler(int cpm_vec) { - cpm_vecs[vec].handler = NULL; - cpm_vecs[vec].dev_id = NULL; - ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); + request_irq(CPM_IRQ_OFFSET + cpm_vec, NULL, 0, 0, + cpm_vecs[cpm_vec].dev_id); + + cpm_vecs[cpm_vec].handler = NULL; + cpm_vecs[cpm_vec].dev_id = NULL; } /* We also own one page of host buffer space for the allocation of @@ -262,10 +329,8 @@ m8xx_cpm_hostalloc(uint size) { uint retloc; -#if 1 if (host_buffer == 0) alloc_host_memory(); -#endif if ((host_buffer + size) >= host_end) return(0);