iosapic.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 746 行 · 第 1/2 页

C
746
字号
{	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);}/* * 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 (iosapic_intr_info[vector].rte_index >= 0 || iosapic_intr_info[vector].addr	    || iosapic_intr_info[vector].gsi_base || iosapic_intr_info[vector].dmode	    || iosapic_intr_info[vector].polarity || iosapic_intr_info[vector].trigger)	{		new_vector = assign_irq_vector(AUTO_ASSIGN);		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));		memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));		iosapic_intr_info[vector].rte_index = -1;	}}static voidregister_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;	index = find_iosapic(gsi);	if (index < 0) {		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi);		return;	}	iosapic_address = iosapic_lists[index].addr;	gsi_base = iosapic_lists[index].gsi_base;	rte_index = gsi - gsi_base;	iosapic_intr_info[vector].rte_index = rte_index;	iosapic_intr_info[vector].polarity = polarity;	iosapic_intr_info[vector].dmode    = delivery;	iosapic_intr_info[vector].addr     = iosapic_address;	iosapic_intr_info[vector].gsi_base = gsi_base;	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;	}}static unsigned intget_target_cpu (unsigned int gsi, int vector){#ifdef CONFIG_SMP	static int cpu = -1;	/*	 * If the platform supports redirection via XTP, let it	 * distribute interrupts.	 */	if (smp_int_redirect & SMP_IRQ_REDIRECTION)		return hard_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 hard_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);				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 hard_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;	unsigned int dest;	unsigned long flags;	/*	 * 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) {			spin_unlock_irqrestore(&iosapic_lock, flags);			return vector;		}		vector = assign_irq_vector(AUTO_ASSIGN);		dest = get_target_cpu(gsi, vector);		register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,			polarity, trigger);	}	spin_unlock_irqrestore(&iosapic_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);	set_rte(vector, dest, 1);	return vector;}/* * ACPI calls this when it finds an entry for a platform interrupt. * Note that the irq_base and IOSAPIC address must be set in iosapic_init(). */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 vector, mask = 0;	unsigned int dest = ((id << 8) | eid) & 0xffff;	switch (int_type) {	      case ACPI_INTERRUPT_PMI:		vector = iosapic_vector;		/*		 * since PMI vector is alloc'd by FW(ACPI) not by kernel,		 * we need to make sure the vector is available		 */		iosapic_reassign_vector(vector);		delivery = IOSAPIC_PMI;		break;	      case ACPI_INTERRUPT_INIT:		vector = assign_irq_vector(AUTO_ASSIGN);		delivery = IOSAPIC_INIT;		break;	      case ACPI_INTERRUPT_CPEI:		vector = IA64_CPE_VECTOR;		delivery = IOSAPIC_LOWEST_PRIORITY;		mask = 1;		break;	      default:		printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type);		return -1;	}	register_intr(gsi, vector, 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(vector, dest, mask);	return vector;}/* * ACPI calls this when it finds an entry for a legacy ISA IRQ override. * Note that the gsi_base and IOSAPIC address must be set in iosapic_init(). */void __initiosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,			  unsigned long polarity,			  unsigned long trigger){	int vector;	unsigned int dest = hard_smp_processor_id();	vector = isa_irq_to_vector(isa_irq);	register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, 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(vector, dest, 1);}void __initiosapic_system_init (int system_pcat_compat){	int vector;	for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)		iosapic_intr_info[vector].rte_index = -1;	/* mark as unused */	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);	}}void __initiosapic_init (unsigned long phys_addr, unsigned int gsi_base){	int num_rte;	unsigned int isa_irq, ver;	char __iomem *addr;	addr = ioremap(phys_addr, 0);	ver = iosapic_version(addr);	/*	 * 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;	iosapic_lists[num_iosapic].addr = addr;	iosapic_lists[num_iosapic].gsi_base = gsi_base;	iosapic_lists[num_iosapic].num_rte = num_rte;#ifdef CONFIG_NUMA	iosapic_lists[num_iosapic].node = MAX_NUMNODES;#endif	num_iosapic++;	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);	}}#ifdef CONFIG_NUMAvoid __initmap_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;}#endif

⌨️ 快捷键说明

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