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

📄 iosapic.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 3 页
字号:
	.startup =	iosapic_startup_level_irq,	.shutdown =	iosapic_shutdown_level_irq,	.enable =	iosapic_enable_level_irq,	.disable =	iosapic_disable_level_irq,	.ack =		iosapic_ack_level_irq,	.end =		iosapic_end_level_irq,	.set_affinity =	iosapic_set_affinity};/* * Handlers for edge-triggered interrupts. */static unsigned intiosapic_startup_edge_irq (unsigned int irq){	unmask_irq(irq);	/*	 * IOSAPIC simply drops interrupts pended while the	 * corresponding pin was masked, so we can't know if an	 * interrupt is pending already.  Let's hope not...	 */	return 0;}static voidiosapic_ack_edge_irq (unsigned int irq){	irq_desc_t *idesc = irq_descp(irq);	move_irq(irq);	/*	 * Once we have recorded IRQ_PENDING already, we can mask the	 * interrupt for real. This prevents IRQ storms from unhandled	 * devices.	 */	if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED))		mask_irq(irq);}#define iosapic_enable_edge_irq		unmask_irq#define iosapic_disable_edge_irq	nop#define iosapic_end_edge_irq		nopstruct hw_interrupt_type irq_type_iosapic_edge = {	.typename =	"IO-SAPIC-edge",	.startup =	iosapic_startup_edge_irq,	.shutdown =	iosapic_disable_edge_irq,	.enable =	iosapic_enable_edge_irq,	.disable =	iosapic_disable_edge_irq,	.ack =		iosapic_ack_edge_irq,	.end =		iosapic_end_edge_irq,	.set_affinity =	iosapic_set_affinity};unsigned intiosapic_version (char __iomem *addr){	/*	 * IOSAPIC Version Register return 32 bit structure like:	 * {	 *	unsigned int version   : 8;	 *	unsigned int reserved1 : 8;	 *	unsigned int max_redir : 8;	 *	unsigned int reserved2 : 8;	 * }	 */	return iosapic_read(addr, IOSAPIC_VERSION);}static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol){	int i, vector = -1, min_count = -1;	struct iosapic_intr_info *info;	/*	 * shared vectors for edge-triggered interrupts are not	 * supported yet	 */	if (trigger == IOSAPIC_EDGE)		return -1;	for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {		info = &iosapic_intr_info[i];		if (info->trigger == trigger && info->polarity == pol &&		    (info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) {			if (min_count == -1 || info->count < min_count) {				vector = i;				min_count = info->count;			}		}	}	return vector;}/* * if the given vector is already owned by other, *  assign a new vector for the other and make the vector available */static void __initiosapic_reassign_vector (int vector){	int new_vector;	if (!list_empty(&iosapic_intr_info[vector].rtes)) {		new_vector = assign_irq_vector(AUTO_ASSIGN);		if (new_vector < 0)			panic("%s: out of interrupt vectors!\n", __FUNCTION__);		printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);		memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],		       sizeof(struct iosapic_intr_info));		INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);		list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes);		memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));		iosapic_intr_info[vector].low32 = IOSAPIC_MASK;		INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);	}}static struct iosapic_rte_info *iosapic_alloc_rte (void){	int i;	struct iosapic_rte_info *rte;	int preallocated = 0;	if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {#ifdef XEN		rte = xmalloc_bytes(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES);#else		rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES);#endif		if (!rte)			return NULL;		for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)			list_add(&rte->rte_list, &free_rte_list);	}	if (!list_empty(&free_rte_list)) {		rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list);		list_del(&rte->rte_list);		preallocated++;	} else {		rte = kmalloc(sizeof(struct iosapic_rte_info), GFP_ATOMIC);		if (!rte)			return NULL;	}	memset(rte, 0, sizeof(struct iosapic_rte_info));	if (preallocated)		rte->flags |= RTE_PREALLOCATED;	return rte;}static void iosapic_free_rte (struct iosapic_rte_info *rte){	if (rte->flags & RTE_PREALLOCATED)		list_add_tail(&rte->rte_list, &free_rte_list);	else		kfree(rte);}static inline int vector_is_shared (int vector){	return (iosapic_intr_info[vector].count > 1);}static intregister_intr (unsigned int gsi, int vector, unsigned char delivery,	       unsigned long polarity, unsigned long trigger){	irq_desc_t *idesc;	struct hw_interrupt_type *irq_type;	int rte_index;	int index;	unsigned long gsi_base;	void __iomem *iosapic_address;	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;	}	iosapic_address = iosapic_lists[index].addr;	gsi_base = iosapic_lists[index].gsi_base;	rte = gsi_vector_to_rte(gsi, vector);	if (!rte) {		rte = iosapic_alloc_rte();		if (!rte) {			printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__);			return -ENOMEM;		}		rte_index = gsi - gsi_base;		rte->rte_index	= rte_index;		rte->addr	= iosapic_address;		rte->gsi_base	= gsi_base;		rte->refcnt++;		list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);		iosapic_intr_info[vector].count++;		iosapic_lists[index].rtes_inuse++;	}	else if (vector_is_shared(vector)) {		struct iosapic_intr_info *info = &iosapic_intr_info[vector];		if (info->trigger != trigger || info->polarity != polarity) {			printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__);			return -EINVAL;		}	}	iosapic_intr_info[vector].polarity = polarity;	iosapic_intr_info[vector].dmode    = delivery;	iosapic_intr_info[vector].trigger  = trigger;	if (trigger == IOSAPIC_EDGE)		irq_type = &irq_type_iosapic_edge;	else		irq_type = &irq_type_iosapic_level;	idesc = irq_descp(vector);	if (idesc->handler != irq_type) {		if (idesc->handler != &no_irq_type)			printk(KERN_WARNING "%s: changing vector %d from %s to %s\n",			       __FUNCTION__, vector, idesc->handler->typename, irq_type->typename);		idesc->handler = irq_type;	}	return 0;}static unsigned intget_target_cpu (unsigned int gsi, int vector){#ifdef CONFIG_SMP	static int cpu = -1;	/*	 * In case of vector shared by multiple RTEs, all RTEs that	 * share the vector need to use the same destination CPU.	 */	if (!list_empty(&iosapic_intr_info[vector].rtes))		return iosapic_intr_info[vector].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_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);		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 vector assigment to distribute across cpus in node */		cpu_index = vector % 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));	return cpu_physical_id(cpu);#else	return cpu_physical_id(smp_processor_id());#endif}/* * 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 vector, mask = 1, err;	unsigned int dest;	unsigned long flags;	struct iosapic_rte_info *rte;	u32 low32;again:	/*	 * 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);	{		vector = gsi_to_vector(gsi);		if (vector > 0) {			rte = gsi_vector_to_rte(gsi, vector);			rte->refcnt++;			spin_unlock_irqrestore(&iosapic_lock, flags);			return vector;		}	}	spin_unlock_irqrestore(&iosapic_lock, flags);	/* If vector is running out, we try to find a sharable vector */	vector = assign_irq_vector(AUTO_ASSIGN);	if (vector < 0) {		vector = iosapic_find_sharable_vector(trigger, polarity);  		if (vector < 0)			return -ENOSPC;	}	spin_lock_irqsave(&irq_descp(vector)->lock, flags);	spin_lock(&iosapic_lock);	{		if (gsi_to_vector(gsi) > 0) {			if (list_empty(&iosapic_intr_info[vector].rtes))				free_irq_vector(vector);			spin_unlock(&iosapic_lock);			spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);			goto again;		}		dest = get_target_cpu(gsi, vector);		err = register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,			      polarity, trigger);		if (err < 0) {			spin_unlock(&iosapic_lock);			spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);			return err;		}		/*		 * If the vector is shared and already unmasked for		 * other interrupt sources, don't mask it.		 */		low32 = iosapic_intr_info[vector].low32;		if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK))			mask = 0;		set_rte(gsi, vector, dest, mask);	}	spin_unlock(&iosapic_lock);	spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);	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, vector);	return vector;}voidiosapic_unregister_intr (unsigned int gsi){	unsigned long flags;	int irq, vector, 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;	}	vector = irq_to_vector(irq);	idesc = irq_descp(irq);	spin_lock_irqsave(&idesc->lock, flags);	spin_lock(&iosapic_lock);	{		if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {			printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);			WARN_ON(1);

⌨️ 快捷键说明

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