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

📄 pic.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  Support for the interrupt controllers found on Power Macintosh, *  currently Apple's "Grand Central" interrupt controller in all *  it's incarnations. OpenPIC support used on newer machines is *  in a separate file * *  Copyright (C) 1997 Paul Mackerras (paulus@samba.org) *  Copyright (C) 2005 Benjamin Herrenschmidt (benh@kernel.crashing.org) *                     IBM, Corp. * *  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. * */#include <linux/stddef.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/pci.h>#include <linux/interrupt.h>#include <linux/sysdev.h>#include <linux/adb.h>#include <linux/pmu.h>#include <linux/module.h>#include <asm/sections.h>#include <asm/io.h>#include <asm/smp.h>#include <asm/prom.h>#include <asm/pci-bridge.h>#include <asm/time.h>#include <asm/pmac_feature.h>#include <asm/mpic.h>#include "pmac.h"/* * XXX this should be in xmon.h, but putting it there means xmon.h * has to include <linux/interrupt.h> (to get irqreturn_t), which * causes all sorts of problems.  -- paulus */extern irqreturn_t xmon_irq(int, void *);#ifdef CONFIG_PPC32struct pmac_irq_hw {        unsigned int    event;        unsigned int    enable;        unsigned int    ack;        unsigned int    level;};/* Default addresses */static volatile struct pmac_irq_hw __iomem *pmac_irq_hw[4];#define GC_LEVEL_MASK		0x3ff00000#define OHARE_LEVEL_MASK	0x1ff00000#define HEATHROW_LEVEL_MASK	0x1ff00000static int max_irqs;static int max_real_irqs;static u32 level_mask[4];static DEFINE_SPINLOCK(pmac_pic_lock);#define NR_MASK_WORDS	((NR_IRQS + 31) / 32)static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];static int pmac_irq_cascade = -1;static struct irq_host *pmac_pic_host;static void __pmac_retrigger(unsigned int irq_nr){	if (irq_nr >= max_real_irqs && pmac_irq_cascade > 0) {		__set_bit(irq_nr, ppc_lost_interrupts);		irq_nr = pmac_irq_cascade;		mb();	}	if (!__test_and_set_bit(irq_nr, ppc_lost_interrupts)) {		atomic_inc(&ppc_n_lost_interrupts);		set_dec(1);	}}static void pmac_mask_and_ack_irq(unsigned int virq){	unsigned int src = irq_map[virq].hwirq;        unsigned long bit = 1UL << (src & 0x1f);        int i = src >> 5;        unsigned long flags;	spin_lock_irqsave(&pmac_pic_lock, flags);        __clear_bit(src, ppc_cached_irq_mask);        if (__test_and_clear_bit(src, ppc_lost_interrupts))                atomic_dec(&ppc_n_lost_interrupts);        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);        out_le32(&pmac_irq_hw[i]->ack, bit);        do {                /* make sure ack gets to controller before we enable                   interrupts */                mb();        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)                != (ppc_cached_irq_mask[i] & bit));	spin_unlock_irqrestore(&pmac_pic_lock, flags);}static void pmac_ack_irq(unsigned int virq){	unsigned int src = irq_map[virq].hwirq;        unsigned long bit = 1UL << (src & 0x1f);        int i = src >> 5;        unsigned long flags;  	spin_lock_irqsave(&pmac_pic_lock, flags);	if (__test_and_clear_bit(src, ppc_lost_interrupts))                atomic_dec(&ppc_n_lost_interrupts);        out_le32(&pmac_irq_hw[i]->ack, bit);        (void)in_le32(&pmac_irq_hw[i]->ack);	spin_unlock_irqrestore(&pmac_pic_lock, flags);}static void __pmac_set_irq_mask(unsigned int irq_nr, int nokicklost){        unsigned long bit = 1UL << (irq_nr & 0x1f);        int i = irq_nr >> 5;        if ((unsigned)irq_nr >= max_irqs)                return;        /* enable unmasked interrupts */        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);        do {                /* make sure mask gets to controller before we                   return to user */                mb();        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)                != (ppc_cached_irq_mask[i] & bit));        /*         * Unfortunately, setting the bit in the enable register         * when the device interrupt is already on *doesn't* set         * the bit in the flag register or request another interrupt.         */        if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))		__pmac_retrigger(irq_nr);}/* When an irq gets requested for the first client, if it's an * edge interrupt, we clear any previous one on the controller */static unsigned int pmac_startup_irq(unsigned int virq){	unsigned long flags;	unsigned int src = irq_map[virq].hwirq;        unsigned long bit = 1UL << (src & 0x1f);        int i = src >> 5;  	spin_lock_irqsave(&pmac_pic_lock, flags);	if ((irq_desc[virq].status & IRQ_LEVEL) == 0)		out_le32(&pmac_irq_hw[i]->ack, bit);        __set_bit(src, ppc_cached_irq_mask);        __pmac_set_irq_mask(src, 0);  	spin_unlock_irqrestore(&pmac_pic_lock, flags);	return 0;}static void pmac_mask_irq(unsigned int virq){	unsigned long flags;	unsigned int src = irq_map[virq].hwirq;  	spin_lock_irqsave(&pmac_pic_lock, flags);        __clear_bit(src, ppc_cached_irq_mask);        __pmac_set_irq_mask(src, 1);  	spin_unlock_irqrestore(&pmac_pic_lock, flags);}static void pmac_unmask_irq(unsigned int virq){	unsigned long flags;	unsigned int src = irq_map[virq].hwirq;	spin_lock_irqsave(&pmac_pic_lock, flags);	__set_bit(src, ppc_cached_irq_mask);        __pmac_set_irq_mask(src, 0);  	spin_unlock_irqrestore(&pmac_pic_lock, flags);}static int pmac_retrigger(unsigned int virq){	unsigned long flags;  	spin_lock_irqsave(&pmac_pic_lock, flags);	__pmac_retrigger(irq_map[virq].hwirq);  	spin_unlock_irqrestore(&pmac_pic_lock, flags);	return 1;}static struct irq_chip pmac_pic = {	.typename	= " PMAC-PIC ",	.startup	= pmac_startup_irq,	.mask		= pmac_mask_irq,	.ack		= pmac_ack_irq,	.mask_ack	= pmac_mask_and_ack_irq,	.unmask		= pmac_unmask_irq,	.retrigger	= pmac_retrigger,};static irqreturn_t gatwick_action(int cpl, void *dev_id){	unsigned long flags;	int irq, bits;	int rc = IRQ_NONE;  	spin_lock_irqsave(&pmac_pic_lock, flags);	for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {		int i = irq >> 5;		bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];		/* We must read level interrupts from the level register */		bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);		bits &= ppc_cached_irq_mask[i];		if (bits == 0)			continue;		irq += __ilog2(bits);		spin_unlock_irqrestore(&pmac_pic_lock, flags);		__do_IRQ(irq);		spin_lock_irqsave(&pmac_pic_lock, flags);		rc = IRQ_HANDLED;	}  	spin_unlock_irqrestore(&pmac_pic_lock, flags);	return rc;}static unsigned int pmac_pic_get_irq(void){	int irq;	unsigned long bits = 0;	unsigned long flags;#ifdef CONFIG_SMP	void psurge_smp_message_recv(void);       	/* IPI's are a hack on the powersurge -- Cort */       	if ( smp_processor_id() != 0 ) {		psurge_smp_message_recv();		return NO_IRQ_IGNORE;	/* ignore, already handled */        }#endif /* CONFIG_SMP */  	spin_lock_irqsave(&pmac_pic_lock, flags);	for (irq = max_real_irqs; (irq -= 32) >= 0; ) {		int i = irq >> 5;		bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];		/* We must read level interrupts from the level register */		bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);		bits &= ppc_cached_irq_mask[i];		if (bits == 0)			continue;		irq += __ilog2(bits);		break;	}  	spin_unlock_irqrestore(&pmac_pic_lock, flags);	if (unlikely(irq < 0))		return NO_IRQ;	return irq_linear_revmap(pmac_pic_host, irq);}#ifdef CONFIG_XMONstatic struct irqaction xmon_action = {	.handler	= xmon_irq,	.flags		= 0,	.mask		= CPU_MASK_NONE,	.name		= "NMI - XMON"};#endifstatic struct irqaction gatwick_cascade_action = {	.handler	= gatwick_action,	.flags		= IRQF_DISABLED,	.mask		= CPU_MASK_NONE,	.name		= "cascade",};static int pmac_pic_host_match(struct irq_host *h, struct device_node *node){	/* We match all, we don't always have a node anyway */	return 1;}static int pmac_pic_host_map(struct irq_host *h, unsigned int virq,			     irq_hw_number_t hw){	struct irq_desc *desc = get_irq_desc(virq);	int level;	if (hw >= max_irqs)		return -EINVAL;	/* Mark level interrupts, set delayed disable for edge ones and set	 * handlers	 */	level = !!(level_mask[hw >> 5] & (1UL << (hw & 0x1f)));	if (level)		desc->status |= IRQ_LEVEL;	set_irq_chip_and_handler(virq, &pmac_pic, level ?				 handle_level_irq : handle_edge_irq);	return 0;}static int pmac_pic_host_xlate(struct irq_host *h, struct device_node *ct,			       u32 *intspec, unsigned int intsize,			       irq_hw_number_t *out_hwirq,			       unsigned int *out_flags){	*out_flags = IRQ_TYPE_NONE;	*out_hwirq = *intspec;	return 0;}static struct irq_host_ops pmac_pic_host_ops = {	.match = pmac_pic_host_match,	.map = pmac_pic_host_map,	.xlate = pmac_pic_host_xlate,};static void __init pmac_pic_probe_oldstyle(void){        int i;        struct device_node *master = NULL;	struct device_node *slave = NULL;	u8 __iomem *addr;	struct resource r;	/* Set our get_irq function */	ppc_md.get_irq = pmac_pic_get_irq;	/*	 * Find the interrupt controller type & node	 */	if ((master = of_find_node_by_name(NULL, "gc")) != NULL) {		max_irqs = max_real_irqs = 32;		level_mask[0] = GC_LEVEL_MASK;	} else if ((master = of_find_node_by_name(NULL, "ohare")) != NULL) {

⌨️ 快捷键说明

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