ppc4xx_pic.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 529 行
C
529 行
/* * * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> * * Module name: ppc4xx_pic.c * * Description: * Interrupt controller driver for PowerPC 4xx-based processors. *//* * The PowerPC 403 cores' Asynchronous Interrupt Controller (AIC) has * 32 possible interrupts, a majority of which are not implemented on * all cores. There are six configurable, external interrupt pins and * there are eight internal interrupts for the on-chip serial port * (SPU), DMA controller, and JTAG controller. * * The PowerPC 405/440 cores' Universal Interrupt Controller (UIC) has * 32 possible interrupts as well. Depending on the core and SoC * implementation, a portion of the interrrupts are used for on-chip * peripherals and a portion of the interrupts are available to be * configured for external devices generating interrupts. * * The PowerNP and 440GP (and most likely future implementations) have * cascaded UICs. * */#include <linux/init.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/stddef.h>#include <asm/processor.h>#include <asm/system.h>#include <asm/irq.h>#include <asm/ppc4xx_pic.h>/* Global Variables */struct hw_interrupt_type *ppc4xx_pic;/* * We define 4xxIRQ_InitSenses table thusly: * bit 0x1: sense, 1 for edge and 0 for level. * bit 0x2: polarity, 0 for negative, 1 for positive. */unsigned int ibm4xxPIC_NumInitSenses __initdata = 0;unsigned char *ibm4xxPIC_InitSenses __initdata = NULL;/* Six of one, half dozen of the other....#ifdefs, separate files, * other tricks..... * * There are basically two types of interrupt controllers, the 403 AIC * and the "others" with UIC. I just kept them both here separated * with #ifdefs, but it seems to change depending upon how supporting * files (like ppc4xx.h) change. -- Dan. */#ifdef CONFIG_403/* Function Prototypes */static void ppc403_aic_enable(unsigned int irq);static void ppc403_aic_disable(unsigned int irq);static void ppc403_aic_disable_and_ack(unsigned int irq);static struct hw_interrupt_type ppc403_aic = { "403GC AIC", NULL, NULL, ppc403_aic_enable, ppc403_aic_disable, ppc403_aic_disable_and_ack, 0};intppc403_pic_get_irq(struct pt_regs *regs){ int irq; unsigned long bits; /* * Only report the status of those interrupts that are actually * enabled. */ bits = mfdcr(DCRN_EXISR) & mfdcr(DCRN_EXIER); /* * Walk through the interrupts from highest priority to lowest, and * report the first pending interrupt found. * We want PPC, not C bit numbering, so just subtract the ffs() * result from 32. */ irq = 32 - ffs(bits); if (irq == NR_AIC_IRQS) irq = -1; return (irq);}static voidppc403_aic_enable(unsigned int irq){ int bit, word; bit = irq & 0x1f; word = irq >> 5; ppc_cached_irq_mask[word] |= (1 << (31 - bit)); mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);}static voidppc403_aic_disable(unsigned int irq){ int bit, word; bit = irq & 0x1f; word = irq >> 5; ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);}static voidppc403_aic_disable_and_ack(unsigned int irq){ int bit, word; bit = irq & 0x1f; word = irq >> 5; ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]); mtdcr(DCRN_EXISR, (1 << (31 - bit)));}#else#ifndef UIC1#define UIC1 UIC0#endif#ifndef UIC2#define UIC2 UIC1#endifstatic voidppc4xx_uic_enable(unsigned int irq){ int bit, word; irq_desc_t *desc = irq_desc + irq; bit = irq & 0x1f; word = irq >> 5;#ifdef UIC_DEBUG printk("ppc4xx_uic_enable - irq %d word %d bit 0x%x\n", irq, word, bit);#endif ppc_cached_irq_mask[word] |= 1 << (31 - bit); switch (word) { case 0: mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]); if ((mfdcr(DCRN_UIC_TR(UIC0)) & (1 << (31 - bit))) == 0) desc->status |= IRQ_LEVEL; else desc->status = desc->status & ~IRQ_LEVEL; break; case 1: mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]); if ((mfdcr(DCRN_UIC_TR(UIC1)) & (1 << (31 - bit))) == 0) desc->status |= IRQ_LEVEL; else desc->status = desc->status & ~IRQ_LEVEL; break; case 2: mtdcr(DCRN_UIC_ER(UIC2), ppc_cached_irq_mask[word]); if ((mfdcr(DCRN_UIC_TR(UIC2)) & (1 << (31 - bit))) == 0) desc->status |= IRQ_LEVEL; else desc->status = desc->status & ~IRQ_LEVEL; break; }}static voidppc4xx_uic_disable(unsigned int irq){ int bit, word; bit = irq & 0x1f; word = irq >> 5;#ifdef UIC_DEBUG printk("ppc4xx_uic_disable - irq %d word %d bit 0x%x\n", irq, word, bit);#endif ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); switch (word) { case 0: mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]); break; case 1: mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]); break; case 2: mtdcr(DCRN_UIC_ER(UIC2), ppc_cached_irq_mask[word]); break; }}static voidppc4xx_uic_disable_and_ack(unsigned int irq){ int bit, word; bit = irq & 0x1f; word = irq >> 5;#ifdef UIC_DEBUG printk("ppc4xx_uic_disable_and_ack - irq %d word %d bit 0x%x\n", irq, word, bit);#endif ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); switch (word) { case 0: mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]); mtdcr(DCRN_UIC_SR(UIC0), (1 << (31 - bit)));#if (NR_UICS > 2) mtdcr(DCRN_UIC_SR(UICB), UICB_UIC0NC);#endif break; case 1: mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]); mtdcr(DCRN_UIC_SR(UIC1), (1 << (31 - bit)));#if (NR_UICS == 2) mtdcr(DCRN_UIC_SR(UIC0), (1 << (31 - UIC0_UIC1NC)));#endif#if (NR_UICS > 2) mtdcr(DCRN_UIC_SR(UICB), UICB_UIC1NC);#endif break; case 2: mtdcr(DCRN_UIC_ER(UIC2), ppc_cached_irq_mask[word]); mtdcr(DCRN_UIC_SR(UIC2), (1 << (31 - bit)));#if (NR_UICS > 2) mtdcr(DCRN_UIC_SR(UICB), UICB_UIC2NC);#endif break; }}static voidppc4xx_uic_end(unsigned int irq){ int bit, word; unsigned int tr_bits; bit = irq & 0x1f; word = irq >> 5;#ifdef UIC_DEBUG printk("ppc4xx_uic_end - irq %d word %d bit 0x%x\n", irq, word, bit);#endif switch (word) { case 0: tr_bits = mfdcr(DCRN_UIC_TR(UIC0)); break; case 1: tr_bits = mfdcr(DCRN_UIC_TR(UIC1)); break; case 2: tr_bits = mfdcr(DCRN_UIC_TR(UIC2)); break; } if ((tr_bits & (1 << (31 - bit))) == 0) { /* level trigger */ switch (word) { case 0: mtdcr(DCRN_UIC_SR(UIC0), 1 << (31 - bit));#if (NR_UICS > 2) mtdcr(DCRN_UIC_SR(UICB), UICB_UIC0NC);#endif break; case 1: mtdcr(DCRN_UIC_SR(UIC1), 1 << (31 - bit));#if (NR_UICS == 2) mtdcr(DCRN_UIC_SR(UIC0), (1 << (31 - UIC0_UIC1NC)));#endif#if (NR_UICS > 2) mtdcr(DCRN_UIC_SR(UICB), UICB_UIC1NC);#endif break; case 2: mtdcr(DCRN_UIC_SR(UIC2), 1 << (31 - bit));#if (NR_UICS > 2) mtdcr(DCRN_UIC_SR(UICB), UICB_UIC2NC);#endif break; } } if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { ppc_cached_irq_mask[word] |= 1 << (31 - bit); switch (word) { case 0: mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]); break; case 1: mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]); break; case 2: mtdcr(DCRN_UIC_ER(UIC2), ppc_cached_irq_mask[word]); break; } }}static struct hw_interrupt_type ppc4xx_uic = {#if (NR_UICS == 1) "IBM UIC",#else "IBM UIC Cascade",#endif NULL, NULL, ppc4xx_uic_enable, ppc4xx_uic_disable, ppc4xx_uic_disable_and_ack, ppc4xx_uic_end, 0};intppc4xx_pic_get_irq(struct pt_regs *regs){ int irq, cas_irq; unsigned long bits; cas_irq = 0; /* * Only report the status of those interrupts that are actually * enabled. */#if (NR_UICS > 2) bits = mfdcr(DCRN_UIC_MSR(UICB));#else bits = mfdcr(DCRN_UIC_MSR(UIC0));#endif#if (NR_UICS > 2) if (bits & UICB_UIC0NC) { bits = mfdcr(DCRN_UIC_MSR(UIC0)); irq = 32 - ffs(bits); } else if (bits & UICB_UIC1NC) { bits = mfdcr(DCRN_UIC_MSR(UIC1)); irq = 64 - ffs(bits); } else if (bits & UICB_UIC2NC) { bits = mfdcr(DCRN_UIC_MSR(UIC2)); irq = 96 - ffs(bits); } else { irq = -1; }#elif (NR_UICS > 1) if (bits & UIC_CASCADE_MASK) { bits = mfdcr(DCRN_UIC_MSR(UIC1)); cas_irq = 32 - ffs(bits); irq = 32 + cas_irq; } else { irq = 32 - ffs(bits); if (irq == 32) irq = -1; }#else /* * Walk through the interrupts from highest priority to lowest, and * report the first pending interrupt found. * We want PPC, not C bit numbering, so just subtract the ffs() * result from 32. */ irq = 32 - ffs(bits);#endif if (irq == (NR_UIC_IRQS * NR_UICS)) irq = -1;#ifdef UIC_DEBUG printk("ppc4xx_pic_get_irq - irq %d bit 0x%x\n", irq, bits);#endif return (irq);}#endifvoid __initppc4xx_extpic_init(void){ /* set polarity * 1 = default/pos/rising , 0= neg/falling internal * 1 = neg/falling , 0= pos/rising external * Sense * 0 = default level internal * 0 = level, 1 = edge external */ unsigned int sense, irq; int bit, word; unsigned long ppc_cached_sense_mask[NR_MASK_WORDS]; unsigned long ppc_cached_pol_mask[NR_MASK_WORDS]; ppc_cached_sense_mask[0] = 0; ppc_cached_sense_mask[1] = 0; ppc_cached_sense_mask[2] = 0; ppc_cached_pol_mask[0] = 0; ppc_cached_pol_mask[1] = 0; ppc_cached_pol_mask[2] = 0; for (irq = 0; irq < NR_IRQS; irq++) { bit = irq & 0x1f; word = irq >> 5; sense = (irq < ibm4xxPIC_NumInitSenses) ? ibm4xxPIC_InitSenses[irq] : 3;#ifdef PPC4xx_PIC_DEBUG printk("PPC4xx_picext %d word:%x bit:%x sense:%x", irq, word, bit, sense);#endif ppc_cached_sense_mask[word] |= (~sense & IRQ_SENSE_MASK) << (31 - bit); ppc_cached_pol_mask[word] |= ((sense & IRQ_POLARITY_MASK) >> 1) << (31 - bit); switch (word) { case 0:#ifdef PPC4xx_PIC_DEBUG printk("Pol %x ", mfdcr(DCRN_UIC_PR(UIC0))); printk("Level %x\n", mfdcr(DCRN_UIC_TR(UIC0)));#endif /* polarity setting */ mtdcr(DCRN_UIC_PR(UIC0), ppc_cached_pol_mask[word]); /* Level setting */ mtdcr(DCRN_UIC_TR(UIC0), ppc_cached_sense_mask[word]); break; case 1:#ifdef PPC4xx_PIC_DEBUG printk("Pol %x ", mfdcr(DCRN_UIC_PR(UIC1))); printk("Level %x\n", mfdcr(DCRN_UIC_TR(UIC1)));#endif /* polarity setting */ mtdcr(DCRN_UIC_PR(UIC1), ppc_cached_pol_mask[word]); /* Level setting */ mtdcr(DCRN_UIC_TR(UIC1), ppc_cached_sense_mask[word]); break; case 2:#ifdef PPC4xx_PIC_DEBUG printk("Pol %x ", mfdcr(DCRN_UIC_PR(UIC2))); printk("Level %x\n", mfdcr(DCRN_UIC_TR(UIC2)));#endif /* polarity setting */ mtdcr(DCRN_UIC_PR(UIC2), ppc_cached_pol_mask[word]); /* Level setting */ mtdcr(DCRN_UIC_TR(UIC2), ppc_cached_sense_mask[word]); break; } }}void __initppc4xx_pic_init(void){ /* * Disable all external interrupts until they are * explicity requested. */ ppc_cached_irq_mask[0] = 0; ppc_cached_irq_mask[1] = 0; ppc_cached_irq_mask[2] = 0;#if defined CONFIG_403 mtdcr(DCRN_EXIER, ppc_cached_irq_mask[0]); ppc4xx_pic = &ppc403_aic; ppc_md.get_irq = ppc403_pic_get_irq;#else#if (NR_UICS > 2) mtdcr(DCRN_UIC_ER(UICB), UICB_UIC0NC | UICB_UIC1NC | UICB_UIC2NC); mtdcr(DCRN_UIC_CR(UICB), 0); mtdcr(DCRN_UIC_ER(UIC2), ppc_cached_irq_mask[2]); mtdcr(DCRN_UIC_CR(UIC2), 0);#endif#if (NR_UICS > 1)#if (NR_UICS == 2) /* enable cascading interrupt */ ppc_cached_irq_mask[0] |= 1 << (31 - UIC0_UIC1NC);#endif mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[1]); mtdcr(DCRN_UIC_CR(UIC1), 0);#endif mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]); mtdcr(DCRN_UIC_CR(UIC0), 0); if (ibm4xxPIC_InitSenses != NULL) ppc4xx_extpic_init(); /* Clear any pending interrupts */#if (NR_UICS > 2) mtdcr(DCRN_UIC_SR(UICB), 0xffffffff); mtdcr(DCRN_UIC_SR(UIC2), 0xffffffff);#endif#if (NR_UICS > 1) mtdcr(DCRN_UIC_SR(UIC1), 0xffffffff);#endif mtdcr(DCRN_UIC_SR(UIC0), 0xffffffff); ppc4xx_pic = &ppc4xx_uic; ppc_md.get_irq = ppc4xx_pic_get_irq;#endif}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?