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

📄 irq.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
字号:
/* * Copyright (C) 2000, 2001 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 <asm/errno.h>#include <asm/signal.h>#include <asm/system.h>#include <asm/ptrace.h>#include <asm/sibyte/sb1250_regs.h>#include <asm/sibyte/sb1250_int.h>#include <asm/sibyte/sb1250_uart.h>#include <asm/sibyte/sb1250_scd.h>#include <asm/sibyte/sb1250.h>#include <asm/sibyte/64bit.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_sb1250_irq	disable_sb1250_irqstatic void end_sb1250_irq(unsigned int irq);static void enable_sb1250_irq(unsigned int irq);static void disable_sb1250_irq(unsigned int irq);static unsigned int startup_sb1250_irq(unsigned int irq);static void ack_sb1250_irq(unsigned int irq);#ifdef CONFIG_REMOTE_DEBUGextern void breakpoint(void);extern void set_debug_traps(void);/* 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;}__setup("nokgdb", nokgdb);#endif#define NR_IRQS 64static struct hw_interrupt_type sb1250_irq_type = {	"SB1250-IMR",	startup_sb1250_irq,	shutdown_sb1250_irq,	enable_sb1250_irq,	disable_sb1250_irq,	ack_sb1250_irq,	end_sb1250_irq,	NULL};spinlock_t sb1250_imr_lock = SPIN_LOCK_UNLOCKED;void sb1250_mask_irq(int cpu, int irq){	unsigned long flags;	u64 cur_ints;	spin_lock_irqsave(&sb1250_imr_lock, flags);	cur_ints = in64(KSEG1 + A_IMR_MAPPER(cpu) + R_IMR_INTERRUPT_MASK);	cur_ints |= (((u64) 1) << irq);	out64(cur_ints, KSEG1 + A_IMR_MAPPER(cpu) + R_IMR_INTERRUPT_MASK);	spin_unlock_irqrestore(&sb1250_imr_lock, flags);}void sb1250_unmask_irq(int cpu, int irq){	unsigned long flags;	u64 cur_ints;	spin_lock_irqsave(&sb1250_imr_lock, flags);	cur_ints = in64(KSEG1 + A_IMR_MAPPER(cpu) + R_IMR_INTERRUPT_MASK);	cur_ints &= ~(((u64) 1) << irq);	out64(cur_ints, KSEG1 + A_IMR_MAPPER(cpu) + R_IMR_INTERRUPT_MASK);	spin_unlock_irqrestore(&sb1250_imr_lock, flags);}/* Defined in arch/mips/sibyte/sb1250/irq_handler.S */extern void sb1250_irq_handler(void);/*****************************************************************************/static unsigned int startup_sb1250_irq(unsigned int irq){	sb1250_unmask_irq(0, irq);	return 0;		/* never anything pending */}static void disable_sb1250_irq(unsigned int irq){	sb1250_mask_irq(0, irq);}static void enable_sb1250_irq(unsigned int irq){	sb1250_unmask_irq(0, irq);}static void ack_sb1250_irq(unsigned int irq){	u64 pending;	/*	 * If the interrupt was an LDT interrupt, now is the time	 * to clear it.	 */	pending = in64(KSEG1 + A_IMR_REGISTER(0,R_IMR_LDT_INTERRUPT));	pending &= ((u64)1 << (irq));	if (pending)		out64(pending, KSEG1+A_IMR_REGISTER(0,R_IMR_LDT_INTERRUPT_CLR));	sb1250_mask_irq(0, irq);}static void end_sb1250_irq(unsigned int irq){	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {		sb1250_unmask_irq(0, irq);	}}void __init init_sb1250_irqs(void){	int i;	for (i = 0; i < NR_IRQS; i++) {		irq_desc[i].status = IRQ_DISABLED;		irq_desc[i].action = 0;		irq_desc[i].depth = 1;		irq_desc[i].handler = &sb1250_irq_type;	}}static void sb1250_dummy_handler(int irq, void *dev_id, struct pt_regs *regs){}static struct irqaction sb1250_dummy_action = {	handler: sb1250_dummy_handler,	flags:   0,	mask:    0,	name:    "sb1250-private",	next:    NULL,	dev_id:  0};int sb1250_steal_irq(int irq){	irq_desc_t *desc = irq_desc + irq;	unsigned long flags;	int retval = 0;	if (irq >= NR_IRQS)		return -EINVAL;	spin_lock_irqsave(&desc->lock,flags);	/* Don't allow sharing at all for these */	if (desc->action != NULL)		retval = -EBUSY;	else {		desc->action = &sb1250_dummy_action;		desc->depth = 0;	}	spin_unlock_irqrestore(&desc->lock,flags);}/* *  init_IRQ is called early in the boot sequence from init/main.c.  It *  is responsible for setting up the interrupt mapper and installing the *  handler that will be responsible for dispatching interrupts to the *  "right" place. *//* * For now, map all interrupts to IP[2].  We could save * some cycles by parceling out system interrupts to different * IP lines, but keep it simple for bringup.  We'll also direct * all interrupts to a single CPU; we should probably route * PCI and LDT to one cpu and everything else to the other * to balance the load a bit. * * On the second cpu, everything is set to IP5, which is * ignored, EXCEPT the mailbox interrupt.  That one is * set to IP[2] so it is handled.  This is needed so we * can do cross-cpu function calls, as requred by SMP */#define IMR_IP2_VAL	K_INT_MAP_I0#define IMR_IP3_VAL	K_INT_MAP_I1#define IMR_IP4_VAL	K_INT_MAP_I2#define IMR_IP5_VAL	K_INT_MAP_I3#define IMR_IP6_VAL	K_INT_MAP_I4void __init init_IRQ(void){	unsigned int i;	u64 tmp;	unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |		STATUSF_IP1 | STATUSF_IP0;	/* Default everything to IP2 */	for (i = 0; i < NR_IRQS; i++) {	/* was I0 */		out64(IMR_IP2_VAL,		      KSEG1 + A_IMR_REGISTER(0,					     R_IMR_INTERRUPT_MAP_BASE) +		      (i << 3));		out64(IMR_IP2_VAL,		      KSEG1 + A_IMR_REGISTER(1,					     R_IMR_INTERRUPT_MAP_BASE) +		      (i << 3));	}	init_sb1250_irqs();	/*	 * Map the high 16 bits of the mailbox registers to IP[3], for	 * inter-cpu messages	 */	/* Was I1 */	out64(IMR_IP3_VAL, KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) +	                   (K_INT_MBOX_0 << 3));	out64(IMR_IP3_VAL, KSEG1 + A_IMR_REGISTER(1, R_IMR_INTERRUPT_MAP_BASE) +	                   (K_INT_MBOX_0 << 3));	/* Clear the mailboxes.  The firmware may leave them dirty */	out64(0xffffffffffffffff,	      KSEG1 + A_IMR_REGISTER(0, R_IMR_MAILBOX_CLR_CPU));	out64(0xffffffffffffffff,	      KSEG1 + A_IMR_REGISTER(1, R_IMR_MAILBOX_CLR_CPU));	/* Mask everything except the mailbox registers for both cpus */	tmp = ~((u64) 0) ^ (((u64) 1) << K_INT_MBOX_0);	out64(tmp, KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK));	out64(tmp, KSEG1 + A_IMR_REGISTER(1, R_IMR_INTERRUPT_MASK));	sb1250_steal_irq(K_INT_MBOX_0);	/*	 * Note that the timer interrupts are also mapped, but this is	 * done in sb1250_time_init()	 */#ifdef CONFIG_BCM1250_PROF	imask |= STATUSF_IP7;#endif#ifdef CONFIG_REMOTE_DEBUG	imask |= STATUSF_IP6;#endif	/* Enable necessary IPs, disable the rest */	change_cp0_status(ST0_IM, imask);	set_except_vector(0, sb1250_irq_handler);#ifdef CONFIG_REMOTE_DEBUG	if (kgdb_flag) {		/* Setup uart 1 settings, mapper */		out64(M_DUART_IMR_BRK, KSEG1 + A_DUART + R_DUART_IMR_B);		out64(IMR_IP6_VAL,			KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MAP_BASE) + (K_INT_UART_1<<3));		tmp = in64(KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK));		tmp &= ~(1<<K_INT_UART_1);		out64(tmp, KSEG1 + A_IMR_REGISTER(0, R_IMR_INTERRUPT_MASK));		set_debug_traps();		breakpoint();	}#endif}#ifdef CONFIG_REMOTE_DEBUG#include <linux/delay.h>extern void set_async_breakpoint(unsigned int epc);#define duart_out(reg, val)     out64(val, KSEG1 + A_DUART_CHANREG(1,reg))#define duart_in(reg)           in64(KSEG1 + A_DUART_CHANREG(1,reg))void sb1250_kgdb_interrupt(struct pt_regs *regs){	/*	 * Clear break-change status (allow some time for the remote	 * host to stop the break, since we would see another	 * interrupt on the end-of-break too)	 */	mdelay(500);	duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT |				M_DUART_RX_EN | M_DUART_TX_EN);	if (!user_mode(regs))		set_async_breakpoint(regs->cp0_epc);}#endif 	/* CONFIG_REMOTE_DEBUG */

⌨️ 快捷键说明

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