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

📄 iosapic.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (preallocated)		rte->flags |= RTE_PREALLOCATED;	return rte;}static inline int irq_is_shared (int irq){	return (iosapic_intr_info[irq].count > 1);}static intregister_intr (unsigned int gsi, int irq, unsigned char delivery,	       unsigned long polarity, unsigned long trigger){	irq_desc_t *idesc;	struct hw_interrupt_type *irq_type;	int index;	struct iosapic_rte_info *rte;	index = find_iosapic(gsi);	if (index < 0) {		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n",		       __FUNCTION__, gsi);		return -ENODEV;	}	rte = find_rte(irq, gsi);	if (!rte) {		rte = iosapic_alloc_rte();		if (!rte) {			printk(KERN_WARNING "%s: cannot allocate memory\n",			       __FUNCTION__);			return -ENOMEM;		}		rte->iosapic	= &iosapic_lists[index];		rte->rte_index	= gsi - rte->iosapic->gsi_base;		rte->refcnt++;		list_add_tail(&rte->rte_list, &iosapic_intr_info[irq].rtes);		iosapic_intr_info[irq].count++;		iosapic_lists[index].rtes_inuse++;	}	else if (rte->refcnt == NO_REF_RTE) {		struct iosapic_intr_info *info = &iosapic_intr_info[irq];		if (info->count > 0 &&		    (info->trigger != trigger || info->polarity != polarity)){			printk (KERN_WARNING				"%s: cannot override the interrupt\n",				__FUNCTION__);			return -EINVAL;		}		rte->refcnt++;		iosapic_intr_info[irq].count++;		iosapic_lists[index].rtes_inuse++;	}	iosapic_intr_info[irq].polarity = polarity;	iosapic_intr_info[irq].dmode    = delivery;	iosapic_intr_info[irq].trigger  = trigger;	if (trigger == IOSAPIC_EDGE)		irq_type = &irq_type_iosapic_edge;	else		irq_type = &irq_type_iosapic_level;	idesc = irq_desc + irq;	if (idesc->chip != irq_type) {		if (idesc->chip != &no_irq_type)			printk(KERN_WARNING			       "%s: changing vector %d from %s to %s\n",			       __FUNCTION__, irq_to_vector(irq),			       idesc->chip->name, irq_type->name);		idesc->chip = irq_type;	}	return 0;}static unsigned intget_target_cpu (unsigned int gsi, int irq){#ifdef CONFIG_SMP	static int cpu = -1;	extern int cpe_vector;	cpumask_t domain = irq_to_domain(irq);	/*	 * In case of vector shared by multiple RTEs, all RTEs that	 * share the vector need to use the same destination CPU.	 */	if (iosapic_intr_info[irq].count)		return iosapic_intr_info[irq].dest;	/*	 * If the platform supports redirection via XTP, let it	 * distribute interrupts.	 */	if (smp_int_redirect & SMP_IRQ_REDIRECTION)		return cpu_physical_id(smp_processor_id());	/*	 * Some interrupts (ACPI SCI, for instance) are registered	 * before the BSP is marked as online.	 */	if (!cpu_online(smp_processor_id()))		return cpu_physical_id(smp_processor_id());#ifdef CONFIG_ACPI	if (cpe_vector > 0 && irq_to_vector(irq) == IA64_CPEP_VECTOR)		return get_cpei_target_cpu();#endif#ifdef CONFIG_NUMA	{		int num_cpus, cpu_index, iosapic_index, numa_cpu, i = 0;		cpumask_t cpu_mask;		iosapic_index = find_iosapic(gsi);		if (iosapic_index < 0 ||		    iosapic_lists[iosapic_index].node == MAX_NUMNODES)			goto skip_numa_setup;		cpu_mask = node_to_cpumask(iosapic_lists[iosapic_index].node);		cpus_and(cpu_mask, cpu_mask, domain);		for_each_cpu_mask(numa_cpu, cpu_mask) {			if (!cpu_online(numa_cpu))				cpu_clear(numa_cpu, cpu_mask);		}		num_cpus = cpus_weight(cpu_mask);		if (!num_cpus)			goto skip_numa_setup;		/* Use irq assignment to distribute across cpus in node */		cpu_index = irq % num_cpus;		for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++)			numa_cpu = next_cpu(numa_cpu, cpu_mask);		if (numa_cpu != NR_CPUS)			return cpu_physical_id(numa_cpu);	}skip_numa_setup:#endif	/*	 * Otherwise, round-robin interrupt vectors across all the	 * processors.  (It'd be nice if we could be smarter in the	 * case of NUMA.)	 */	do {		if (++cpu >= NR_CPUS)			cpu = 0;	} while (!cpu_online(cpu) || !cpu_isset(cpu, domain));	return cpu_physical_id(cpu);#else  /* CONFIG_SMP */	return cpu_physical_id(smp_processor_id());#endif}static inline unsigned char choose_dmode(void){#ifdef CONFIG_SMP	if (smp_int_redirect & SMP_IRQ_REDIRECTION)		return IOSAPIC_LOWEST_PRIORITY;#endif	return IOSAPIC_FIXED;}/* * ACPI can describe IOSAPIC interrupts via static tables and namespace * methods.  This provides an interface to register those interrupts and * program the IOSAPIC RTE. */intiosapic_register_intr (unsigned int gsi,		       unsigned long polarity, unsigned long trigger){	int irq, mask = 1, err;	unsigned int dest;	unsigned long flags;	struct iosapic_rte_info *rte;	u32 low32;	unsigned char dmode;	/*	 * If this GSI has already been registered (i.e., it's a	 * shared interrupt, or we lost a race to register it),	 * don't touch the RTE.	 */	spin_lock_irqsave(&iosapic_lock, flags);	irq = __gsi_to_irq(gsi);	if (irq > 0) {		rte = find_rte(irq, gsi);		if(iosapic_intr_info[irq].count == 0) {			assign_irq_vector(irq);			dynamic_irq_init(irq);		} else if (rte->refcnt != NO_REF_RTE) {			rte->refcnt++;			goto unlock_iosapic_lock;		}	} else		irq = create_irq();	/* If vector is running out, we try to find a sharable vector */	if (irq < 0) {		irq = iosapic_find_sharable_irq(trigger, polarity);		if (irq < 0)			goto unlock_iosapic_lock;	}	spin_lock(&irq_desc[irq].lock);	dest = get_target_cpu(gsi, irq);	dmode = choose_dmode();	err = register_intr(gsi, irq, dmode, polarity, trigger);	if (err < 0) {		spin_unlock(&irq_desc[irq].lock);		irq = err;		goto unlock_iosapic_lock;	}	/*	 * If the vector is shared and already unmasked for other	 * interrupt sources, don't mask it.	 */	low32 = iosapic_intr_info[irq].low32;	if (irq_is_shared(irq) && !(low32 & IOSAPIC_MASK))		mask = 0;	set_rte(gsi, irq, dest, mask);	printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",	       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),	       cpu_logical_id(dest), dest, irq_to_vector(irq));	spin_unlock(&irq_desc[irq].lock); unlock_iosapic_lock:	spin_unlock_irqrestore(&iosapic_lock, flags);	return irq;}voidiosapic_unregister_intr (unsigned int gsi){	unsigned long flags;	int irq, index;	irq_desc_t *idesc;	u32 low32;	unsigned long trigger, polarity;	unsigned int dest;	struct iosapic_rte_info *rte;	/*	 * If the irq associated with the gsi is not found,	 * iosapic_unregister_intr() is unbalanced. We need to check	 * this again after getting locks.	 */	irq = gsi_to_irq(gsi);	if (irq < 0) {		printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n",		       gsi);		WARN_ON(1);		return;	}	spin_lock_irqsave(&iosapic_lock, flags);	if ((rte = find_rte(irq, gsi)) == NULL) {		printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n",		       gsi);		WARN_ON(1);		goto out;	}	if (--rte->refcnt > 0)		goto out;	idesc = irq_desc + irq;	rte->refcnt = NO_REF_RTE;	/* Mask the interrupt */	low32 = iosapic_intr_info[irq].low32 | IOSAPIC_MASK;	iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte->rte_index), low32);	iosapic_intr_info[irq].count--;	index = find_iosapic(gsi);	iosapic_lists[index].rtes_inuse--;	WARN_ON(iosapic_lists[index].rtes_inuse < 0);	trigger  = iosapic_intr_info[irq].trigger;	polarity = iosapic_intr_info[irq].polarity;	dest     = iosapic_intr_info[irq].dest;	printk(KERN_INFO	       "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n",	       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),	       cpu_logical_id(dest), dest, irq_to_vector(irq));	if (iosapic_intr_info[irq].count == 0) {#ifdef CONFIG_SMP		/* Clear affinity */		cpus_setall(idesc->affinity);#endif		/* Clear the interrupt information */		iosapic_intr_info[irq].dest = 0;		iosapic_intr_info[irq].dmode = 0;		iosapic_intr_info[irq].polarity = 0;		iosapic_intr_info[irq].trigger = 0;		iosapic_intr_info[irq].low32 |= IOSAPIC_MASK;		/* Destroy and reserve IRQ */		destroy_and_reserve_irq(irq);	} out:	spin_unlock_irqrestore(&iosapic_lock, flags);}/* * ACPI calls this when it finds an entry for a platform interrupt. */int __initiosapic_register_platform_intr (u32 int_type, unsigned int gsi,				int iosapic_vector, u16 eid, u16 id,				unsigned long polarity, unsigned long trigger){	static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"};	unsigned char delivery;	int irq, vector, mask = 0;	unsigned int dest = ((id << 8) | eid) & 0xffff;	switch (int_type) {	      case ACPI_INTERRUPT_PMI:		irq = vector = iosapic_vector;		bind_irq_vector(irq, vector, CPU_MASK_ALL);		/*		 * since PMI vector is alloc'd by FW(ACPI) not by kernel,		 * we need to make sure the vector is available		 */		iosapic_reassign_vector(irq);		delivery = IOSAPIC_PMI;		break;	      case ACPI_INTERRUPT_INIT:		irq = create_irq();		if (irq < 0)			panic("%s: out of interrupt vectors!\n", __FUNCTION__);		vector = irq_to_vector(irq);		delivery = IOSAPIC_INIT;		break;	      case ACPI_INTERRUPT_CPEI:		irq = vector = IA64_CPE_VECTOR;		BUG_ON(bind_irq_vector(irq, vector, CPU_MASK_ALL));		delivery = IOSAPIC_FIXED;		mask = 1;		break;	      default:		printk(KERN_ERR "%s: invalid int type 0x%x\n", __FUNCTION__,		       int_type);		return -1;	}	register_intr(gsi, irq, delivery, polarity, trigger);	printk(KERN_INFO	       "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x)"	       " vector %d\n",	       int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown",	       int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),	       cpu_logical_id(dest), dest, vector);	set_rte(gsi, irq, dest, mask);	return vector;}/* * ACPI calls this when it finds an entry for a legacy ISA IRQ override. */void __devinitiosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,			  unsigned long polarity,			  unsigned long trigger){	int vector, irq;	unsigned int dest = cpu_physical_id(smp_processor_id());	unsigned char dmode;	irq = vector = isa_irq_to_vector(isa_irq);	BUG_ON(bind_irq_vector(irq, vector, CPU_MASK_ALL));	dmode = choose_dmode();	register_intr(gsi, irq, dmode, polarity, trigger);	DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",	    isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level",	    polarity == IOSAPIC_POL_HIGH ? "high" : "low",	    cpu_logical_id(dest), dest, vector);	set_rte(gsi, irq, dest, 1);}void __initiosapic_system_init (int system_pcat_compat){	int irq;	for (irq = 0; irq < NR_IRQS; ++irq) {		iosapic_intr_info[irq].low32 = IOSAPIC_MASK;		/* mark as unused */		INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);		iosapic_intr_info[irq].count = 0;	}	pcat_compat = system_pcat_compat;	if (pcat_compat) {		/*		 * Disable the compatibility mode interrupts (8259 style),		 * needs IN/OUT support enabled.		 */		printk(KERN_INFO		       "%s: Disabling PC-AT compatible 8259 interrupts\n",		       __FUNCTION__);		outb(0xff, 0xA1);		outb(0xff, 0x21);	}}static inline intiosapic_alloc (void){	int index;	for (index = 0; index < NR_IOSAPICS; index++)		if (!iosapic_lists[index].addr)			return index;	printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__);	return -1;}static inline voidiosapic_free (int index){	memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0]));}static inline intiosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver){	int index;	unsigned int gsi_end, base, end;	/* check gsi range */	gsi_end = gsi_base + ((ver >> 16) & 0xff);	for (index = 0; index < NR_IOSAPICS; index++) {		if (!iosapic_lists[index].addr)			continue;		base = iosapic_lists[index].gsi_base;		end  = base + iosapic_lists[index].num_rte - 1;		if (gsi_end < base || end < gsi_base)			continue; /* OK */		return -EBUSY;	}	return 0;}int __devinitiosapic_init (unsigned long phys_addr, unsigned int gsi_base){	int num_rte, err, index;	unsigned int isa_irq, ver;	char __iomem *addr;	unsigned long flags;	spin_lock_irqsave(&iosapic_lock, flags);	index = find_iosapic(gsi_base);	if (index >= 0) {		spin_unlock_irqrestore(&iosapic_lock, flags);		return -EBUSY;	}	addr = ioremap(phys_addr, 0);	ver = iosapic_version(addr);	if ((err = iosapic_check_gsi_range(gsi_base, ver))) {		iounmap(addr);		spin_unlock_irqrestore(&iosapic_lock, flags);		return err;	}	/*	 * The MAX_REDIR register holds the highest input pin number	 * (starting from 0).  We add 1 so that we can use it for	 * number of pins (= RTEs)	 */	num_rte = ((ver >> 16) & 0xff) + 1;	index = iosapic_alloc();	iosapic_lists[index].addr = addr;	iosapic_lists[index].gsi_base = gsi_base;	iosapic_lists[index].num_rte = num_rte;#ifdef CONFIG_NUMA	iosapic_lists[index].node = MAX_NUMNODES;#endif	spin_lock_init(&iosapic_lists[index].lock);	spin_unlock_irqrestore(&iosapic_lock, flags);	if ((gsi_base == 0) && pcat_compat) {		/*		 * Map the legacy ISA devices into the IOSAPIC data.  Some of		 * these may get reprogrammed later on with data from the ACPI		 * Interrupt Source Override table.		 */		for (isa_irq = 0; isa_irq < 16; ++isa_irq)			iosapic_override_isa_irq(isa_irq, isa_irq,						 IOSAPIC_POL_HIGH,						 IOSAPIC_EDGE);	}	return 0;}#ifdef CONFIG_HOTPLUGintiosapic_remove (unsigned int gsi_base){	int index, err = 0;	unsigned long flags;	spin_lock_irqsave(&iosapic_lock, flags);	index = find_iosapic(gsi_base);	if (index < 0) {		printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",		       __FUNCTION__, gsi_base);		goto out;	}	if (iosapic_lists[index].rtes_inuse) {		err = -EBUSY;		printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",		       __FUNCTION__, gsi_base);		goto out;	}	iounmap(iosapic_lists[index].addr);	iosapic_free(index); out:	spin_unlock_irqrestore(&iosapic_lock, flags);	return err;}#endif /* CONFIG_HOTPLUG */#ifdef CONFIG_NUMAvoid __devinitmap_iosapic_to_node(unsigned int gsi_base, int node){	int index;	index = find_iosapic(gsi_base);	if (index < 0) {		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n",		       __FUNCTION__, gsi_base);		return;	}	iosapic_lists[index].node = node;	return;}#endifstatic int __init iosapic_enable_kmalloc (void){	iosapic_kmalloc_ok = 1;	return 0;}core_initcall (iosapic_enable_kmalloc);

⌨️ 快捷键说明

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