⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 irq.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */#include <linux/config.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/linkage.h>#include <linux/interrupt.h>#include <linux/spinlock.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/kernel_stat.h>#include <asm/errno.h>#include <asm/signal.h>#include <asm/system.h>#include <asm/ptrace.h>#include <asm/io.h>#include <asm/sibyte/bcm1480_regs.h>#include <asm/sibyte/bcm1480_int.h>#include <asm/sibyte/bcm1480_scd.h>#include <asm/sibyte/sb1250_uart.h>#include <asm/sibyte/sb1250.h>/* * These are the routines that handle all the low level interrupt stuff. * Actions handled here are: initialization of the interrupt map, requesting of * interrupt lines by handlers, dispatching if interrupts to handlers, probing * for interrupt lines */#define shutdown_bcm1480_irq	disable_bcm1480_irqstatic void end_bcm1480_irq(unsigned int irq);static void enable_bcm1480_irq(unsigned int irq);static void disable_bcm1480_irq(unsigned int irq);static unsigned int startup_bcm1480_irq(unsigned int irq);static void ack_bcm1480_irq(unsigned int irq);#ifdef CONFIG_SMPstatic void bcm1480_set_affinity(unsigned int irq, cpumask_t mask);#endif#ifdef CONFIG_PCIextern unsigned long ht_eoi_space;#endif#ifdef CONFIG_KGDB#include <asm/gdb-stub.h>extern void breakpoint(void);static int kgdb_irq;#ifdef CONFIG_GDB_CONSOLEextern void register_gdb_console(void);#endif/* kgdb is on when configured.  Pass "nokgdb" kernel arg to turn it off */static int kgdb_flag = 1;static int __init nokgdb(char *str){	kgdb_flag = 0;	return 1;}__setup("nokgdb", nokgdb);/* Default to UART1 */int kgdb_port = 1;#ifdef CONFIG_SIBYTE_SB1250_DUARTextern char sb1250_duart_present[];#endif#endifstatic struct hw_interrupt_type bcm1480_irq_type = {	.typename = "BCM1480-IMR",	.startup = startup_bcm1480_irq,	.shutdown = shutdown_bcm1480_irq,	.enable = enable_bcm1480_irq,	.disable = disable_bcm1480_irq,	.ack = ack_bcm1480_irq,	.end = end_bcm1480_irq,#ifdef CONFIG_SMP	.set_affinity = bcm1480_set_affinity#endif};/* Store the CPU id (not the logical number) */int bcm1480_irq_owner[BCM1480_NR_IRQS];DEFINE_SPINLOCK(bcm1480_imr_lock);void bcm1480_mask_irq(int cpu, int irq){	unsigned long flags;	u64 cur_ints,hl_spacing;	spin_lock_irqsave(&bcm1480_imr_lock, flags);	hl_spacing = 0;	if ((irq >= BCM1480_NR_IRQS_HALF) && (irq <= BCM1480_NR_IRQS)) {		hl_spacing = BCM1480_IMR_HL_SPACING;		irq -= BCM1480_NR_IRQS_HALF;	}	cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));	cur_ints |= (((u64) 1) << irq);	____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));	spin_unlock_irqrestore(&bcm1480_imr_lock, flags);}void bcm1480_unmask_irq(int cpu, int irq){	unsigned long flags;	u64 cur_ints,hl_spacing;	spin_lock_irqsave(&bcm1480_imr_lock, flags);	hl_spacing = 0;	if ((irq >= BCM1480_NR_IRQS_HALF) && (irq <= BCM1480_NR_IRQS)) {		hl_spacing = BCM1480_IMR_HL_SPACING;		irq -= BCM1480_NR_IRQS_HALF;	}	cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));	cur_ints &= ~(((u64) 1) << irq);	____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + hl_spacing));	spin_unlock_irqrestore(&bcm1480_imr_lock, flags);}#ifdef CONFIG_SMPstatic void bcm1480_set_affinity(unsigned int irq, cpumask_t mask){	int i = 0, old_cpu, cpu, int_on, k;	u64 cur_ints;	irq_desc_t *desc = irq_desc + irq;	unsigned long flags;	unsigned int irq_dirty;	i = first_cpu(mask);	if (next_cpu(i, mask) <= NR_CPUS) {		printk("attempted to set irq affinity for irq %d to multiple CPUs\n", irq);		return;	}	/* Convert logical CPU to physical CPU */	cpu = cpu_logical_map(i);	/* Protect against other affinity changers and IMR manipulation */	spin_lock_irqsave(&desc->lock, flags);	spin_lock(&bcm1480_imr_lock);	/* Swizzle each CPU's IMR (but leave the IP selection alone) */	old_cpu = bcm1480_irq_owner[irq];	irq_dirty = irq;	if ((irq_dirty >= BCM1480_NR_IRQS_HALF) && (irq_dirty <= BCM1480_NR_IRQS)) {		irq_dirty -= BCM1480_NR_IRQS_HALF;	}	for (k=0; k<2; k++) { /* Loop through high and low interrupt mask register */		cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(old_cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));		int_on = !(cur_ints & (((u64) 1) << irq_dirty));		if (int_on) {			/* If it was on, mask it */			cur_ints |= (((u64) 1) << irq_dirty);			____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(old_cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));		}		bcm1480_irq_owner[irq] = cpu;		if (int_on) {			/* unmask for the new CPU */			cur_ints = ____raw_readq(IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));			cur_ints &= ~(((u64) 1) << irq_dirty);			____raw_writeq(cur_ints, IOADDR(A_BCM1480_IMR_MAPPER(cpu) + R_BCM1480_IMR_INTERRUPT_MASK_H + (k*BCM1480_IMR_HL_SPACING)));		}	}	spin_unlock(&bcm1480_imr_lock);	spin_unlock_irqrestore(&desc->lock, flags);}#endif/*****************************************************************************/static unsigned int startup_bcm1480_irq(unsigned int irq){	bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq);	return 0;		/* never anything pending */}static void disable_bcm1480_irq(unsigned int irq){	bcm1480_mask_irq(bcm1480_irq_owner[irq], irq);}static void enable_bcm1480_irq(unsigned int irq){	bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq);}static void ack_bcm1480_irq(unsigned int irq){	u64 pending;	unsigned int irq_dirty;	int k;	/*	 * If the interrupt was an HT interrupt, now is the time to	 * clear it.  NOTE: we assume the HT bridge was set up to	 * deliver the interrupts to all CPUs (which makes affinity	 * changing easier for us)	 */	irq_dirty = irq;	if ((irq_dirty >= BCM1480_NR_IRQS_HALF) && (irq_dirty <= BCM1480_NR_IRQS)) {		irq_dirty -= BCM1480_NR_IRQS_HALF;	}	for (k=0; k<2; k++) { /* Loop through high and low LDT interrupts */		pending = __raw_readq(IOADDR(A_BCM1480_IMR_REGISTER(bcm1480_irq_owner[irq],						R_BCM1480_IMR_LDT_INTERRUPT_H + (k*BCM1480_IMR_HL_SPACING))));		pending &= ((u64)1 << (irq_dirty));		if (pending) {#ifdef CONFIG_SMP			int i;			for (i=0; i<NR_CPUS; i++) {				/*				 * Clear for all CPUs so an affinity switch				 * doesn't find an old status				 */				__raw_writeq(pending, IOADDR(A_BCM1480_IMR_REGISTER(cpu_logical_map(i),								R_BCM1480_IMR_LDT_INTERRUPT_CLR_H + (k*BCM1480_IMR_HL_SPACING))));			}#else			__raw_writeq(pending, IOADDR(A_BCM1480_IMR_REGISTER(0, R_BCM1480_IMR_LDT_INTERRUPT_CLR_H + (k*BCM1480_IMR_HL_SPACING))));#endif			/*			 * Generate EOI.  For Pass 1 parts, EOI is a nop.  For			 * Pass 2, the LDT world may be edge-triggered, but			 * this EOI shouldn't hurt.  If they are			 * level-sensitive, the EOI is required.			 */#ifdef CONFIG_PCI			if (ht_eoi_space)				*(uint32_t *)(ht_eoi_space+(irq<<16)+(7<<2)) = 0;#endif		}	}	bcm1480_mask_irq(bcm1480_irq_owner[irq], irq);}static void end_bcm1480_irq(unsigned int irq){	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {		bcm1480_unmask_irq(bcm1480_irq_owner[irq], irq);	}}void __init init_bcm1480_irqs(void){	int i;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -