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

📄 irq.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
				if (bp != bucket	&&				    bp->imap == imap	&&				    (bp->flags & IBF_ACTIVE) != 0)					break;			}			/* Only disable when no other sub-irq levels of			 * the same IMAP are active.			 */			if (ent == NUM_IVECS)				disable_irq(irq);		}	}	spin_unlock_irqrestore(&irq_action_lock, flags);}EXPORT_SYMBOL(free_irq);#ifdef CONFIG_SMPvoid synchronize_irq(unsigned int irq){	struct ino_bucket *bucket = __bucket(irq);#if 0	/* The following is how I wish I could implement this.	 * Unfortunately the ICLR registers are read-only, you can	 * only write ICLR_foo values to them.  To get the current	 * IRQ status you would need to get at the IRQ diag registers	 * in the PCI/SBUS controller and the layout of those vary	 * from one controller to the next, sigh... -DaveM	 */	unsigned long iclr = bucket->iclr;	while (1) {		u32 tmp = upa_readl(iclr);				if (tmp == ICLR_TRANSMIT ||		    tmp == ICLR_PENDING) {			cpu_relax();			continue;		}		break;	}#else	/* So we have to do this with a INPROGRESS bit just like x86.  */	while (bucket->flags & IBF_INPROGRESS)		cpu_relax();#endif}#endif /* CONFIG_SMP */static void process_bucket(int irq, struct ino_bucket *bp, struct pt_regs *regs){	struct irq_desc *desc = bp->irq_info;	unsigned char flags = bp->flags;	u32 action_mask, i;	int random;	bp->flags |= IBF_INPROGRESS;	if (unlikely(!(flags & IBF_ACTIVE))) {		bp->pending = 1;		goto out;	}	if (desc->pre_handler)		desc->pre_handler(bp,				  desc->pre_handler_arg1,				  desc->pre_handler_arg2);	action_mask = desc->action_active_mask;	random = 0;	for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) {		struct irqaction *p = &desc->action[i];		u32 mask = (1 << i);		if (!(action_mask & mask))			continue;		action_mask &= ~mask;		if (p->handler(__irq(bp), p->dev_id, regs) == IRQ_HANDLED)			random |= p->flags;		if (!action_mask)			break;	}	if (bp->pil != 0) {		upa_writel(ICLR_IDLE, bp->iclr);		/* Test and add entropy */		if (random & SA_SAMPLE_RANDOM)			add_interrupt_randomness(irq);	}out:	bp->flags &= ~IBF_INPROGRESS;}void handler_irq(int irq, struct pt_regs *regs){	struct ino_bucket *bp;	int cpu = smp_processor_id();#ifndef CONFIG_SMP	/*	 * Check for TICK_INT on level 14 softint.	 */	{		unsigned long clr_mask = 1 << irq;		unsigned long tick_mask = tick_ops->softint_mask;		if ((irq == 14) && (get_softint() & tick_mask)) {			irq = 0;			clr_mask = tick_mask;		}		clear_softint(clr_mask);	}#else	clear_softint(1 << irq);#endif	irq_enter();	kstat_this_cpu.irqs[irq]++;	/* Sliiiick... */#ifndef CONFIG_SMP	bp = ((irq != 0) ?	      __bucket(xchg32(irq_work(cpu, irq), 0)) :	      &pil0_dummy_bucket);#else	bp = __bucket(xchg32(irq_work(cpu, irq), 0));#endif	while (bp) {		struct ino_bucket *nbp = __bucket(bp->irq_chain);		bp->irq_chain = 0;		process_bucket(irq, bp, regs);		bp = nbp;	}	irq_exit();}#ifdef CONFIG_BLK_DEV_FDextern irqreturn_t floppy_interrupt(int, void *, struct pt_regs *);;/* XXX No easy way to include asm/floppy.h XXX */extern unsigned char *pdma_vaddr;extern unsigned long pdma_size;extern volatile int doing_pdma;extern unsigned long fdc_status;irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs){	if (likely(doing_pdma)) {		void __iomem *stat = (void __iomem *) fdc_status;		unsigned char *vaddr = pdma_vaddr;		unsigned long size = pdma_size;		u8 val;		while (size) {			val = readb(stat);			if (unlikely(!(val & 0x80))) {				pdma_vaddr = vaddr;				pdma_size = size;				return IRQ_HANDLED;			}			if (unlikely(!(val & 0x20))) {				pdma_vaddr = vaddr;				pdma_size = size;				doing_pdma = 0;				goto main_interrupt;			}			if (val & 0x40) {				/* read */				*vaddr++ = readb(stat + 1);			} else {				unsigned char data = *vaddr++;				/* write */				writeb(data, stat + 1);			}			size--;		}		pdma_vaddr = vaddr;		pdma_size = size;		/* Send Terminal Count pulse to floppy controller. */		val = readb(auxio_register);		val |= AUXIO_AUX1_FTCNT;		writeb(val, auxio_register);		val &= AUXIO_AUX1_FTCNT;		writeb(val, auxio_register);		doing_pdma = 0;	}main_interrupt:	return floppy_interrupt(irq, dev_cookie, regs);}EXPORT_SYMBOL(sparc_floppy_irq);#endif/* We really don't need these at all on the Sparc.  We only have * stubs here because they are exported to modules. */unsigned long probe_irq_on(void){	return 0;}EXPORT_SYMBOL(probe_irq_on);int probe_irq_off(unsigned long mask){	return 0;}EXPORT_SYMBOL(probe_irq_off);#ifdef CONFIG_SMPstatic int retarget_one_irq(struct irqaction *p, int goal_cpu){	struct ino_bucket *bucket = get_ino_in_irqaction(p) + ivector_table;	unsigned long imap = bucket->imap;	unsigned int tid;	while (!cpu_online(goal_cpu)) {		if (++goal_cpu >= NR_CPUS)			goal_cpu = 0;	}	if (tlb_type == cheetah || tlb_type == cheetah_plus) {		tid = goal_cpu << 26;		tid &= IMAP_AID_SAFARI;	} else if (this_is_starfire == 0) {		tid = goal_cpu << 26;		tid &= IMAP_TID_UPA;	} else {		tid = (starfire_translate(imap, goal_cpu) << 26);		tid &= IMAP_TID_UPA;	}	upa_writel(tid | IMAP_VALID, imap);	do {		if (++goal_cpu >= NR_CPUS)			goal_cpu = 0;	} while (!cpu_online(goal_cpu));	return goal_cpu;}/* Called from request_irq. */static void distribute_irqs(void){	unsigned long flags;	int cpu, level;	spin_lock_irqsave(&irq_action_lock, flags);	cpu = 0;	/*	 * Skip the timer at [0], and very rare error/power intrs at [15].	 * Also level [12], it causes problems on Ex000 systems.	 */	for (level = 1; level < NR_IRQS; level++) {		struct irqaction *p = irq_action[level];		if (level == 12)			continue;		while(p) {			cpu = retarget_one_irq(p, cpu);			p = p->next;		}	}	spin_unlock_irqrestore(&irq_action_lock, flags);}#endifstruct sun5_timer {	u64	count0;	u64	limit0;	u64	count1;	u64	limit1;};static struct sun5_timer *prom_timers;static u64 prom_limit0, prom_limit1;static void map_prom_timers(void){	unsigned int addr[3];	int tnode, err;	/* PROM timer node hangs out in the top level of device siblings... */	tnode = prom_finddevice("/counter-timer");	/* Assume if node is not present, PROM uses different tick mechanism	 * which we should not care about.	 */	if (tnode == 0 || tnode == -1) {		prom_timers = (struct sun5_timer *) 0;		return;	}	/* If PROM is really using this, it must be mapped by him. */	err = prom_getproperty(tnode, "address", (char *)addr, sizeof(addr));	if (err == -1) {		prom_printf("PROM does not have timer mapped, trying to continue.\n");		prom_timers = (struct sun5_timer *) 0;		return;	}	prom_timers = (struct sun5_timer *) ((unsigned long)addr[0]);}static void kill_prom_timer(void){	if (!prom_timers)		return;	/* Save them away for later. */	prom_limit0 = prom_timers->limit0;	prom_limit1 = prom_timers->limit1;	/* Just as in sun4c/sun4m PROM uses timer which ticks at IRQ 14.	 * We turn both off here just to be paranoid.	 */	prom_timers->limit0 = 0;	prom_timers->limit1 = 0;	/* Wheee, eat the interrupt packet too... */	__asm__ __volatile__("	mov	0x40, %%g2\n""	ldxa	[%%g0] %0, %%g1\n""	ldxa	[%%g2] %1, %%g1\n""	stxa	%%g0, [%%g0] %0\n""	membar	#Sync\n"	: /* no outputs */	: "i" (ASI_INTR_RECEIVE), "i" (ASI_INTR_R)	: "g1", "g2");}void init_irqwork_curcpu(void){	register struct irq_work_struct *workp asm("o2");	register unsigned long tmp asm("o3");	int cpu = hard_smp_processor_id();	memset(__irq_work + cpu, 0, sizeof(*workp));	/* Make sure we are called with PSTATE_IE disabled.  */	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"			     : "=r" (tmp));	if (tmp & PSTATE_IE) {		prom_printf("BUG: init_irqwork_curcpu() called with "			    "PSTATE_IE enabled, bailing.\n");		__asm__ __volatile__("mov	%%i7, %0\n\t"				     : "=r" (tmp));		prom_printf("BUG: Called from %lx\n", tmp);		prom_halt();	}	/* Set interrupt globals.  */	workp = &__irq_work[cpu];	__asm__ __volatile__(	"rdpr	%%pstate, %0\n\t"	"wrpr	%0, %1, %%pstate\n\t"	"mov	%2, %%g6\n\t"	"wrpr	%0, 0x0, %%pstate\n\t"	: "=&r" (tmp)	: "i" (PSTATE_IG), "r" (workp));}/* Only invoked on boot processor. */void __init init_IRQ(void){	map_prom_timers();	kill_prom_timer();	memset(&ivector_table[0], 0, sizeof(ivector_table));	/* We need to clear any IRQ's pending in the soft interrupt	 * registers, a spurious one could be left around from the	 * PROM timer which we just disabled.	 */	clear_softint(get_softint());	/* Now that ivector table is initialized, it is safe	 * to receive IRQ vector traps.  We will normally take	 * one or two right now, in case some device PROM used	 * to boot us wants to speak to us.  We just ignore them.	 */	__asm__ __volatile__("rdpr	%%pstate, %%g1\n\t"			     "or	%%g1, %0, %%g1\n\t"			     "wrpr	%%g1, 0x0, %%pstate"			     : /* No outputs */			     : "i" (PSTATE_IE)			     : "g1");}static struct proc_dir_entry * root_irq_dir;static struct proc_dir_entry * irq_dir [NUM_IVECS];#ifdef CONFIG_SMPstatic int irq_affinity_read_proc (char *page, char **start, off_t off,			int count, int *eof, void *data){	struct ino_bucket *bp = ivector_table + (long)data;	struct irq_desc *desc = bp->irq_info;	struct irqaction *ap = desc->action;	cpumask_t mask;	int len;	mask = get_smpaff_in_irqaction(ap);	if (cpus_empty(mask))		mask = cpu_online_map;	len = cpumask_scnprintf(page, count, mask);	if (count - len < 2)		return -EINVAL;	len += sprintf(page + len, "\n");	return len;}static inline void set_intr_affinity(int irq, cpumask_t hw_aff){	struct ino_bucket *bp = ivector_table + irq;	struct irq_desc *desc = bp->irq_info;	struct irqaction *ap = desc->action;	/* Users specify affinity in terms of hw cpu ids.	 * As soon as we do this, handler_irq() might see and take action.	 */	put_smpaff_in_irqaction(ap, hw_aff);	/* Migration is simply done by the next cpu to service this	 * interrupt.	 */}static int irq_affinity_write_proc (struct file *file, const char __user *buffer,					unsigned long count, void *data){	int irq = (long) data, full_count = count, err;	cpumask_t new_value;	err = cpumask_parse(buffer, count, new_value);	/*	 * Do not allow disabling IRQs completely - it's a too easy	 * way to make the system unusable accidentally :-) At least	 * one online CPU still has to be targeted.	 */	cpus_and(new_value, new_value, cpu_online_map);	if (cpus_empty(new_value))		return -EINVAL;	set_intr_affinity(irq, new_value);	return full_count;}#endif#define MAX_NAMELEN 10static void register_irq_proc (unsigned int irq){	char name [MAX_NAMELEN];	if (!root_irq_dir || irq_dir[irq])		return;	memset(name, 0, MAX_NAMELEN);	sprintf(name, "%x", irq);	/* create /proc/irq/1234 */	irq_dir[irq] = proc_mkdir(name, root_irq_dir);#ifdef CONFIG_SMP	/* XXX SMP affinity not supported on starfire yet. */	if (this_is_starfire == 0) {		struct proc_dir_entry *entry;		/* create /proc/irq/1234/smp_affinity */		entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);		if (entry) {			entry->nlink = 1;			entry->data = (void *)(long)irq;			entry->read_proc = irq_affinity_read_proc;			entry->write_proc = irq_affinity_write_proc;		}	}#endif}void init_irq_proc (void){	/* create /proc/irq */	root_irq_dir = proc_mkdir("irq", NULL);}

⌨️ 快捷键说明

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