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 + -
显示快捷键?