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

📄 irq.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	pr_debug("irq: Default host set to @0x%p\n", host);	irq_default_host = host;}void irq_set_virq_count(unsigned int count){	pr_debug("irq: Trying to set virq count to %d\n", count);	BUG_ON(count < NUM_ISA_INTERRUPTS);	if (count < NR_IRQS)		irq_virq_count = count;}/* radix tree not lockless safe ! we use a brlock-type mecanism * for now, until we can use a lockless radix tree */static void irq_radix_wrlock(unsigned long *flags){	unsigned int cpu, ok;	spin_lock_irqsave(&irq_big_lock, *flags);	irq_radix_writer = 1;	smp_mb();	do {		barrier();		ok = 1;		for_each_possible_cpu(cpu) {			if (per_cpu(irq_radix_reader, cpu)) {				ok = 0;				break;			}		}		if (!ok)			cpu_relax();	} while(!ok);}static void irq_radix_wrunlock(unsigned long flags){	smp_wmb();	irq_radix_writer = 0;	spin_unlock_irqrestore(&irq_big_lock, flags);}static void irq_radix_rdlock(unsigned long *flags){	local_irq_save(*flags);	__get_cpu_var(irq_radix_reader) = 1;	smp_mb();	if (likely(irq_radix_writer == 0))		return;	__get_cpu_var(irq_radix_reader) = 0;	smp_wmb();	spin_lock(&irq_big_lock);	__get_cpu_var(irq_radix_reader) = 1;	spin_unlock(&irq_big_lock);}static void irq_radix_rdunlock(unsigned long flags){	__get_cpu_var(irq_radix_reader) = 0;	local_irq_restore(flags);}static int irq_setup_virq(struct irq_host *host, unsigned int virq,			    irq_hw_number_t hwirq){	/* Clear IRQ_NOREQUEST flag */	get_irq_desc(virq)->status &= ~IRQ_NOREQUEST;	/* map it */	smp_wmb();	irq_map[virq].hwirq = hwirq;	smp_mb();	if (host->ops->map(host, virq, hwirq)) {		pr_debug("irq: -> mapping failed, freeing\n");		irq_free_virt(virq, 1);		return -1;	}	return 0;}unsigned int irq_create_direct_mapping(struct irq_host *host){	unsigned int virq;	if (host == NULL)		host = irq_default_host;	BUG_ON(host == NULL);	WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP);	virq = irq_alloc_virt(host, 1, 0);	if (virq == NO_IRQ) {		pr_debug("irq: create_direct virq allocation failed\n");		return NO_IRQ;	}	pr_debug("irq: create_direct obtained virq %d\n", virq);	if (irq_setup_virq(host, virq, virq))		return NO_IRQ;	return virq;}unsigned int irq_create_mapping(struct irq_host *host,				irq_hw_number_t hwirq){	unsigned int virq, hint;	pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", host, hwirq);	/* Look for default host if nececssary */	if (host == NULL)		host = irq_default_host;	if (host == NULL) {		printk(KERN_WARNING "irq_create_mapping called for"		       " NULL host, hwirq=%lx\n", hwirq);		WARN_ON(1);		return NO_IRQ;	}	pr_debug("irq: -> using host @%p\n", host);	/* Check if mapping already exist, if it does, call	 * host->ops->map() to update the flags	 */	virq = irq_find_mapping(host, hwirq);	if (virq != NO_IRQ) {		if (host->ops->remap)			host->ops->remap(host, virq, hwirq);		pr_debug("irq: -> existing mapping on virq %d\n", virq);		return virq;	}	/* Get a virtual interrupt number */	if (host->revmap_type == IRQ_HOST_MAP_LEGACY) {		/* Handle legacy */		virq = (unsigned int)hwirq;		if (virq == 0 || virq >= NUM_ISA_INTERRUPTS)			return NO_IRQ;		return virq;	} else {		/* Allocate a virtual interrupt number */		hint = hwirq % irq_virq_count;		virq = irq_alloc_virt(host, 1, hint);		if (virq == NO_IRQ) {			pr_debug("irq: -> virq allocation failed\n");			return NO_IRQ;		}	}	pr_debug("irq: -> obtained virq %d\n", virq);	if (irq_setup_virq(host, virq, hwirq))		return NO_IRQ;	return virq;}EXPORT_SYMBOL_GPL(irq_create_mapping);unsigned int irq_create_of_mapping(struct device_node *controller,				   u32 *intspec, unsigned int intsize){	struct irq_host *host;	irq_hw_number_t hwirq;	unsigned int type = IRQ_TYPE_NONE;	unsigned int virq;	if (controller == NULL)		host = irq_default_host;	else		host = irq_find_host(controller);	if (host == NULL) {		printk(KERN_WARNING "irq: no irq host found for %s !\n",		       controller->full_name);		return NO_IRQ;	}	/* If host has no translation, then we assume interrupt line */	if (host->ops->xlate == NULL)		hwirq = intspec[0];	else {		if (host->ops->xlate(host, controller, intspec, intsize,				     &hwirq, &type))			return NO_IRQ;	}	/* Create mapping */	virq = irq_create_mapping(host, hwirq);	if (virq == NO_IRQ)		return virq;	/* Set type if specified and different than the current one */	if (type != IRQ_TYPE_NONE &&	    type != (get_irq_desc(virq)->status & IRQF_TRIGGER_MASK))		set_irq_type(virq, type);	return virq;}EXPORT_SYMBOL_GPL(irq_create_of_mapping);unsigned int irq_of_parse_and_map(struct device_node *dev, int index){	struct of_irq oirq;	if (of_irq_map_one(dev, index, &oirq))		return NO_IRQ;	return irq_create_of_mapping(oirq.controller, oirq.specifier,				     oirq.size);}EXPORT_SYMBOL_GPL(irq_of_parse_and_map);void irq_dispose_mapping(unsigned int virq){	struct irq_host *host;	irq_hw_number_t hwirq;	unsigned long flags;	if (virq == NO_IRQ)		return;	host = irq_map[virq].host;	WARN_ON (host == NULL);	if (host == NULL)		return;	/* Never unmap legacy interrupts */	if (host->revmap_type == IRQ_HOST_MAP_LEGACY)		return;	/* remove chip and handler */	set_irq_chip_and_handler(virq, NULL, NULL);	/* Make sure it's completed */	synchronize_irq(virq);	/* Tell the PIC about it */	if (host->ops->unmap)		host->ops->unmap(host, virq);	smp_mb();	/* Clear reverse map */	hwirq = irq_map[virq].hwirq;	switch(host->revmap_type) {	case IRQ_HOST_MAP_LINEAR:		if (hwirq < host->revmap_data.linear.size)			host->revmap_data.linear.revmap[hwirq] = NO_IRQ;		break;	case IRQ_HOST_MAP_TREE:		/* Check if radix tree allocated yet */		if (host->revmap_data.tree.gfp_mask == 0)			break;		irq_radix_wrlock(&flags);		radix_tree_delete(&host->revmap_data.tree, hwirq);		irq_radix_wrunlock(flags);		break;	}	/* Destroy map */	smp_mb();	irq_map[virq].hwirq = host->inval_irq;	/* Set some flags */	get_irq_desc(virq)->status |= IRQ_NOREQUEST;	/* Free it */	irq_free_virt(virq, 1);}EXPORT_SYMBOL_GPL(irq_dispose_mapping);unsigned int irq_find_mapping(struct irq_host *host,			      irq_hw_number_t hwirq){	unsigned int i;	unsigned int hint = hwirq % irq_virq_count;	/* Look for default host if nececssary */	if (host == NULL)		host = irq_default_host;	if (host == NULL)		return NO_IRQ;	/* legacy -> bail early */	if (host->revmap_type == IRQ_HOST_MAP_LEGACY)		return hwirq;	/* Slow path does a linear search of the map */	if (hint < NUM_ISA_INTERRUPTS)		hint = NUM_ISA_INTERRUPTS;	i = hint;	do  {		if (irq_map[i].host == host &&		    irq_map[i].hwirq == hwirq)			return i;		i++;		if (i >= irq_virq_count)			i = NUM_ISA_INTERRUPTS;	} while(i != hint);	return NO_IRQ;}EXPORT_SYMBOL_GPL(irq_find_mapping);unsigned int irq_radix_revmap(struct irq_host *host,			      irq_hw_number_t hwirq){	struct radix_tree_root *tree;	struct irq_map_entry *ptr;	unsigned int virq;	unsigned long flags;	WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);	/* Check if the radix tree exist yet. We test the value of	 * the gfp_mask for that. Sneaky but saves another int in the	 * structure. If not, we fallback to slow mode	 */	tree = &host->revmap_data.tree;	if (tree->gfp_mask == 0)		return irq_find_mapping(host, hwirq);	/* Now try to resolve */	irq_radix_rdlock(&flags);	ptr = radix_tree_lookup(tree, hwirq);	irq_radix_rdunlock(flags);	/* Found it, return */	if (ptr) {		virq = ptr - irq_map;		return virq;	}	/* If not there, try to insert it */	virq = irq_find_mapping(host, hwirq);	if (virq != NO_IRQ) {		irq_radix_wrlock(&flags);		radix_tree_insert(tree, hwirq, &irq_map[virq]);		irq_radix_wrunlock(flags);	}	return virq;}unsigned int irq_linear_revmap(struct irq_host *host,			       irq_hw_number_t hwirq){	unsigned int *revmap;	WARN_ON(host->revmap_type != IRQ_HOST_MAP_LINEAR);	/* Check revmap bounds */	if (unlikely(hwirq >= host->revmap_data.linear.size))		return irq_find_mapping(host, hwirq);	/* Check if revmap was allocated */	revmap = host->revmap_data.linear.revmap;	if (unlikely(revmap == NULL))		return irq_find_mapping(host, hwirq);	/* Fill up revmap with slow path if no mapping found */	if (unlikely(revmap[hwirq] == NO_IRQ))		revmap[hwirq] = irq_find_mapping(host, hwirq);	return revmap[hwirq];}unsigned int irq_alloc_virt(struct irq_host *host,			    unsigned int count,			    unsigned int hint){	unsigned long flags;	unsigned int i, j, found = NO_IRQ;	if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS))		return NO_IRQ;	spin_lock_irqsave(&irq_big_lock, flags);	/* Use hint for 1 interrupt if any */	if (count == 1 && hint >= NUM_ISA_INTERRUPTS &&	    hint < irq_virq_count && irq_map[hint].host == NULL) {		found = hint;		goto hint_found;	}	/* Look for count consecutive numbers in the allocatable	 * (non-legacy) space	 */	for (i = NUM_ISA_INTERRUPTS, j = 0; i < irq_virq_count; i++) {		if (irq_map[i].host != NULL)			j = 0;		else			j++;		if (j == count) {			found = i - count + 1;			break;		}	}	if (found == NO_IRQ) {		spin_unlock_irqrestore(&irq_big_lock, flags);		return NO_IRQ;	} hint_found:	for (i = found; i < (found + count); i++) {		irq_map[i].hwirq = host->inval_irq;		smp_wmb();		irq_map[i].host = host;	}	spin_unlock_irqrestore(&irq_big_lock, flags);	return found;}void irq_free_virt(unsigned int virq, unsigned int count){	unsigned long flags;	unsigned int i;	WARN_ON (virq < NUM_ISA_INTERRUPTS);	WARN_ON (count == 0 || (virq + count) > irq_virq_count);	spin_lock_irqsave(&irq_big_lock, flags);	for (i = virq; i < (virq + count); i++) {		struct irq_host *host;		if (i < NUM_ISA_INTERRUPTS ||		    (virq + count) > irq_virq_count)			continue;		host = irq_map[i].host;		irq_map[i].hwirq = host->inval_irq;		smp_wmb();		irq_map[i].host = NULL;	}	spin_unlock_irqrestore(&irq_big_lock, flags);}void irq_early_init(void){	unsigned int i;	for (i = 0; i < NR_IRQS; i++)		get_irq_desc(i)->status |= IRQ_NOREQUEST;}/* We need to create the radix trees late */static int irq_late_init(void){	struct irq_host *h;	unsigned long flags;	irq_radix_wrlock(&flags);	list_for_each_entry(h, &irq_hosts, link) {		if (h->revmap_type == IRQ_HOST_MAP_TREE)			INIT_RADIX_TREE(&h->revmap_data.tree, GFP_ATOMIC);	}	irq_radix_wrunlock(flags);	return 0;}arch_initcall(irq_late_init);#ifdef CONFIG_VIRQ_DEBUGstatic int virq_debug_show(struct seq_file *m, void *private){	unsigned long flags;	irq_desc_t *desc;	const char *p;	char none[] = "none";	int i;	seq_printf(m, "%-5s  %-7s  %-15s  %s\n", "virq", "hwirq",		      "chip name", "host name");	for (i = 1; i < NR_IRQS; i++) {		desc = get_irq_desc(i);		spin_lock_irqsave(&desc->lock, flags);		if (desc->action && desc->action->handler) {			seq_printf(m, "%5d  ", i);			seq_printf(m, "0x%05lx  ", virq_to_hw(i));			if (desc->chip && desc->chip->typename)				p = desc->chip->typename;			else				p = none;			seq_printf(m, "%-15s  ", p);			if (irq_map[i].host && irq_map[i].host->of_node)				p = irq_map[i].host->of_node->full_name;			else				p = none;			seq_printf(m, "%s\n", p);		}		spin_unlock_irqrestore(&desc->lock, flags);	}	return 0;}static int virq_debug_open(struct inode *inode, struct file *file){	return single_open(file, virq_debug_show, inode->i_private);}static const struct file_operations virq_debug_fops = {	.open = virq_debug_open,	.read = seq_read,	.llseek = seq_lseek,	.release = single_release,};static int __init irq_debugfs_init(void){	if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root,				 NULL, &virq_debug_fops))		return -ENOMEM;	return 0;}__initcall(irq_debugfs_init);#endif /* CONFIG_VIRQ_DEBUG */#endif /* CONFIG_PPC_MERGE */#ifdef CONFIG_PPC64static int __init setup_noirqdistrib(char *str){	distribute_irqs = 0;	return 1;}__setup("noirqdistrib", setup_noirqdistrib);#endif /* CONFIG_PPC64 */

⌨️ 快捷键说明

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