X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc%2F8xx_io%2Fcommproc.c;h=3b23bcb35b7abf9f8b3bd1c2efc9373f53ac60db;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=ec637ed48e55bab893731c77efe6779d431648db;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c index ec637ed48..3b23bcb35 100644 --- a/arch/ppc/8xx_io/commproc.c +++ b/arch/ppc/8xx_io/commproc.c @@ -23,22 +23,23 @@ #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); - -static uint dp_alloc_base; /* Starting offset in DP ram */ -static uint dp_alloc_top; /* Max offset + 1 */ +static void m8xx_cpm_dpinit(void); static uint host_buffer; /* One page of host buffer */ static uint host_end; /* end + 1 */ cpm8xx_t *cpmp; /* Pointer to comm processor space */ @@ -46,15 +47,65 @@ cpm8xx_t *cpmp; /* Pointer to comm processor space */ /* CPM interrupt vector functions. */ struct cpm_action { - void (*handler)(void *, struct pt_regs * regs); + void (*handler)(void *); 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); +static irqreturn_t cpm_error_interrupt(int irq, void *dev); 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" + }; + +static void +cpm_mask_irq(unsigned int irq) +{ + int cpm_vec = irq - CPM_IRQ_OFFSET; + + clrbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, (1 << cpm_vec)); +} + +static void +cpm_unmask_irq(unsigned int irq) +{ + int cpm_vec = irq - CPM_IRQ_OFFSET; + + setbits32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr, (1 << cpm_vec)); +} + +static void +cpm_ack(unsigned int irq) +{ + /* We do not need to do anything here. */ +} + +static void +cpm_eoi(unsigned int irq) +{ + int cpm_vec = irq - CPM_IRQ_OFFSET; + + out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr, (1 << cpm_vec)); +} + +struct hw_interrupt_type cpm_pic = { + .typename = " CPM ", + .enable = cpm_unmask_irq, + .disable = cpm_mask_irq, + .ack = cpm_ack, + .end = cpm_eoi, +}; -#if 1 void m8xx_cpm_reset(void) { @@ -82,12 +133,10 @@ m8xx_cpm_reset(void) * manual recommends it. * Bit 25, FAM can also be set to use FEC aggressive mode (860T). */ - imp->im_siu_conf.sc_sdcr = 1; + out_be32(&imp->im_siu_conf.sc_sdcr, 1), - /* Reclaim the DP memory for our use. - */ - dp_alloc_base = CPM_DATAONLY_BASE; - dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE; + /* Reclaim the DP memory for our use. */ + m8xx_cpm_dpinit(); /* Tell everyone where the comm processor resides. */ @@ -98,121 +147,88 @@ m8xx_cpm_reset(void) * to ensure the kernel VM is now running. */ static void -alloc_host_memory() +alloc_host_memory(void) { - uint physaddr; + dma_addr_t physaddr; /* Set the host page for allocation. */ - host_buffer = (uint)consistent_alloc(GFP_KERNEL, PAGE_SIZE, &physaddr); + host_buffer = (uint)dma_alloc_coherent(NULL, PAGE_SIZE, &physaddr, + GFP_KERNEL); host_end = host_buffer + PAGE_SIZE; } -#else -void -m8xx_cpm_reset(uint host_page_addr) -{ - volatile immap_t *imp; - volatile cpm8xx_t *commproc; - pte_t *pte; - - 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); - - /* Wait for it. - */ - while (commproc->cp_cpcr & CPM_CR_FLG); - - cpm_load_patch(imp); -#endif - - /* 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; - - /* Reclaim the DP memory for our use. - */ - dp_alloc_base = CPM_DATAONLY_BASE; - dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE; - - /* Set the host page for allocation. - */ - host_buffer = host_page_addr; /* Host virtual page address */ - host_end = host_page_addr + PAGE_SIZE; - - /* 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?"); - } - - /* Tell everyone where the comm processor resides. - */ - cpmp = (cpm8xx_t *)commproc; -} -#endif /* 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 = + out_be32(&((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr, (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | - ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK; - ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr = 0; + ((CPM_INTERRUPT/2) << 13) | CICR_HP_MASK); + out_be32(&((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].chip = &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); - ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr |= CICR_IEN; + /* 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!"); + + setbits32(&((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(void) { - 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; + out_be16(&((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr, 1); + cpm_vec = in_be16(&((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) +{ + /* 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 @@ -220,65 +236,72 @@ 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) { + 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) +{ + int cpm_vec = irq - CPM_IRQ_OFFSET; + + (*cpm_vecs[cpm_vec].handler)(dev_id); + + 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), - void *dev_id) +cpm_install_handler(int cpm_vec, void (*handler)(void *), 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); -/* Allocate some memory from the dual ported ram. We may want to - * enforce alignment restrictions, but right now everyone is a good - * citizen. - */ -uint -m8xx_cpm_dpalloc(uint size) -{ - uint retloc; - - if ((dp_alloc_base + size) >= dp_alloc_top) - return(CPM_DP_NOSPACE); - - retloc = dp_alloc_base; - dp_alloc_base += size; - - return(retloc); -} - -uint -m8xx_cpm_dpalloc_index(void) -{ - return dp_alloc_base; + 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 @@ -289,10 +312,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); @@ -313,7 +334,7 @@ m8xx_cpm_hostalloc(uint size) #define BRG_UART_CLK_DIV16 (BRG_UART_CLK/16) void -m8xx_cpm_setbrg(uint brg, uint rate) +cpm_setbrg(uint brg, uint rate) { volatile uint *bp; @@ -330,3 +351,94 @@ m8xx_cpm_setbrg(uint brg, uint rate) *bp = (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) | CPM_BRG_EN | CPM_BRG_DIV16; } + +/* + * dpalloc / dpfree bits. + */ +static spinlock_t cpm_dpmem_lock; +/* + * 16 blocks should be enough to satisfy all requests + * until the memory subsystem goes up... + */ +static rh_block_t cpm_boot_dpmem_rh_block[16]; +static rh_info_t cpm_dpmem_info; + +#define CPM_DPMEM_ALIGNMENT 8 + +void m8xx_cpm_dpinit(void) +{ + spin_lock_init(&cpm_dpmem_lock); + + /* Initialize the info header */ + rh_init(&cpm_dpmem_info, CPM_DPMEM_ALIGNMENT, + sizeof(cpm_boot_dpmem_rh_block) / + sizeof(cpm_boot_dpmem_rh_block[0]), + cpm_boot_dpmem_rh_block); + + /* + * Attach the usable dpmem area. + * XXX: This is actually crap. CPM_DATAONLY_BASE and + * CPM_DATAONLY_SIZE are a subset of the available dparm. It varies + * with the processor and the microcode patches applied / activated. + * But the following should be at least safe. + */ + rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE); +} + +/* + * Allocate the requested size worth of DP memory. + * This function returns an offset into the DPRAM area. + * Use cpm_dpram_addr() to get the virtual address of the area. + */ +uint cpm_dpalloc(uint size, uint align) +{ + void *start; + unsigned long flags; + + spin_lock_irqsave(&cpm_dpmem_lock, flags); + cpm_dpmem_info.alignment = align; + start = rh_alloc(&cpm_dpmem_info, size, "commproc"); + spin_unlock_irqrestore(&cpm_dpmem_lock, flags); + + return (uint)start; +} +EXPORT_SYMBOL(cpm_dpalloc); + +int cpm_dpfree(uint offset) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&cpm_dpmem_lock, flags); + ret = rh_free(&cpm_dpmem_info, (void *)offset); + spin_unlock_irqrestore(&cpm_dpmem_lock, flags); + + return ret; +} +EXPORT_SYMBOL(cpm_dpfree); + +uint cpm_dpalloc_fixed(uint offset, uint size, uint align) +{ + void *start; + unsigned long flags; + + spin_lock_irqsave(&cpm_dpmem_lock, flags); + cpm_dpmem_info.alignment = align; + start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc"); + spin_unlock_irqrestore(&cpm_dpmem_lock, flags); + + return (uint)start; +} +EXPORT_SYMBOL(cpm_dpalloc_fixed); + +void cpm_dpdump(void) +{ + rh_dump(&cpm_dpmem_info); +} +EXPORT_SYMBOL(cpm_dpdump); + +void *cpm_dpram_addr(uint offset) +{ + return ((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem + offset; +} +EXPORT_SYMBOL(cpm_dpram_addr);