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

📄 io_apic.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	unsigned int v, ver, maxlvt;	printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",		smp_processor_id(), hard_smp_processor_id());	v = apic_read(APIC_ID);	printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v, GET_APIC_ID(v));	v = apic_read(APIC_LVR);	printk(KERN_INFO "... APIC VERSION: %08x\n", v);	ver = GET_APIC_VERSION(v);	maxlvt = get_maxlvt();	v = apic_read(APIC_TASKPRI);	printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);	if (APIC_INTEGRATED(ver)) {			/* !82489DX */		v = apic_read(APIC_ARBPRI);		printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v,			v & APIC_ARBPRI_MASK);		v = apic_read(APIC_PROCPRI);		printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v);	}	v = apic_read(APIC_EOI);	printk(KERN_DEBUG "... APIC EOI: %08x\n", v);	v = apic_read(APIC_RRR);	printk(KERN_DEBUG "... APIC RRR: %08x\n", v);	v = apic_read(APIC_LDR);	printk(KERN_DEBUG "... APIC LDR: %08x\n", v);	v = apic_read(APIC_DFR);	printk(KERN_DEBUG "... APIC DFR: %08x\n", v);	v = apic_read(APIC_SPIV);	printk(KERN_DEBUG "... APIC SPIV: %08x\n", v);	printk(KERN_DEBUG "... APIC ISR field:\n");	print_APIC_bitfield(APIC_ISR);	printk(KERN_DEBUG "... APIC TMR field:\n");	print_APIC_bitfield(APIC_TMR);	printk(KERN_DEBUG "... APIC IRR field:\n");	print_APIC_bitfield(APIC_IRR);	if (APIC_INTEGRATED(ver)) {		/* !82489DX */		if (maxlvt > 3)		/* Due to the Pentium erratum 3AP. */			apic_write(APIC_ESR, 0);		v = apic_read(APIC_ESR);		printk(KERN_DEBUG "... APIC ESR: %08x\n", v);	}	v = apic_read(APIC_ICR);	printk(KERN_DEBUG "... APIC ICR: %08x\n", v);	v = apic_read(APIC_ICR2);	printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);	v = apic_read(APIC_LVTT);	printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);	if (maxlvt > 3) {                       /* PC is LVT#4. */		v = apic_read(APIC_LVTPC);		printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v);	}	v = apic_read(APIC_LVT0);	printk(KERN_DEBUG "... APIC LVT0: %08x\n", v);	v = apic_read(APIC_LVT1);	printk(KERN_DEBUG "... APIC LVT1: %08x\n", v);	if (maxlvt > 2) {			/* ERR is LVT#3. */		v = apic_read(APIC_LVTERR);		printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v);	}	v = apic_read(APIC_TMICT);	printk(KERN_DEBUG "... APIC TMICT: %08x\n", v);	v = apic_read(APIC_TMCCT);	printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v);	v = apic_read(APIC_TDCR);	printk(KERN_DEBUG "... APIC TDCR: %08x\n", v);	printk("\n");}void print_all_local_APICs (void){	on_each_cpu(print_local_APIC, NULL, 1, 1);}void /*__init*/ print_PIC(void){	extern spinlock_t i8259A_lock;	unsigned int v;	unsigned long flags;	printk(KERN_DEBUG "\nprinting PIC contents\n");	spin_lock_irqsave(&i8259A_lock, flags);	v = inb(0xa1) << 8 | inb(0x21);	printk(KERN_DEBUG "... PIC  IMR: %04x\n", v);	v = inb(0xa0) << 8 | inb(0x20);	printk(KERN_DEBUG "... PIC  IRR: %04x\n", v);	outb(0x0b,0xa0);	outb(0x0b,0x20);	v = inb(0xa0) << 8 | inb(0x20);	outb(0x0a,0xa0);	outb(0x0a,0x20);	spin_unlock_irqrestore(&i8259A_lock, flags);	printk(KERN_DEBUG "... PIC  ISR: %04x\n", v);	v = inb(0x4d1) << 8 | inb(0x4d0);	printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);}static void __init enable_IO_APIC(void){	union IO_APIC_reg_01 reg_01;	int i;	unsigned long flags;	for (i = 0; i < PIN_MAP_SIZE; i++) {		irq_2_pin[i].pin = -1;		irq_2_pin[i].next = 0;	}	if (!pirqs_enabled)		for (i = 0; i < MAX_PIRQS; i++)			pirq_entries[i] = -1;	/*	 * The number of IO-APIC IRQ registers (== #pins):	 */	for (i = 0; i < nr_ioapics; i++) {		spin_lock_irqsave(&ioapic_lock, flags);		reg_01.raw = io_apic_read(i, 1);		spin_unlock_irqrestore(&ioapic_lock, flags);		nr_ioapic_registers[i] = reg_01.bits.entries+1;	}	/*	 * Do not trust the IO-APIC being empty at bootup	 */	clear_IO_APIC();}/* * Not an __init, needed by the reboot code */void disable_IO_APIC(void){	/*	 * Clear the IO-APIC before rebooting:	 */	clear_IO_APIC();	disconnect_bsp_APIC();}/* * function to set the IO-APIC physical IDs based on the * values stored in the MPC table. * * by Matt Domsch <Matt_Domsch@dell.com>  Tue Dec 21 12:25:05 CST 1999 */#ifndef CONFIG_X86_NUMAQstatic void __init setup_ioapic_ids_from_mpc(void){	union IO_APIC_reg_00 reg_00;	physid_mask_t phys_id_present_map;	int apic;	int i;	unsigned char old_id;	unsigned long flags;	/*	 * This is broken; anything with a real cpu count has to	 * circumvent this idiocy regardless.	 */	phys_id_present_map = ioapic_phys_id_map(phys_cpu_present_map);	/*	 * Set the IOAPIC ID to the value stored in the MPC table.	 */	for (apic = 0; apic < nr_ioapics; apic++) {		/* Read the register 0 value */		spin_lock_irqsave(&ioapic_lock, flags);		reg_00.raw = io_apic_read(apic, 0);		spin_unlock_irqrestore(&ioapic_lock, flags);				old_id = mp_ioapics[apic].mpc_apicid;		if (mp_ioapics[apic].mpc_apicid >= get_physical_broadcast()) {			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",				apic, mp_ioapics[apic].mpc_apicid);			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",				reg_00.bits.ID);			mp_ioapics[apic].mpc_apicid = reg_00.bits.ID;		}		/* Don't check I/O APIC IDs for some xAPIC systems.  They have		 * no meaning without the serial APIC bus. */		if (NO_IOAPIC_CHECK)			continue;		/*		 * Sanity check, is the ID really free? Every APIC in a		 * system must have a unique ID or we get lots of nice		 * 'stuck on smp_invalidate_needed IPI wait' messages.		 */		if (check_apicid_used(phys_id_present_map,					mp_ioapics[apic].mpc_apicid)) {			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",				apic, mp_ioapics[apic].mpc_apicid);			for (i = 0; i < get_physical_broadcast(); i++)				if (!physid_isset(i, phys_id_present_map))					break;			if (i >= get_physical_broadcast())				panic("Max APIC ID exceeded!\n");			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",				i);			physid_set(i, phys_id_present_map);			mp_ioapics[apic].mpc_apicid = i;		} else {			physid_mask_t tmp;			tmp = apicid_to_cpu_present(mp_ioapics[apic].mpc_apicid);			printk("Setting %d in the phys_id_present_map\n", mp_ioapics[apic].mpc_apicid);			physids_or(phys_id_present_map, phys_id_present_map, tmp);		}		/*		 * We need to adjust the IRQ routing table		 * if the ID changed.		 */		if (old_id != mp_ioapics[apic].mpc_apicid)			for (i = 0; i < mp_irq_entries; i++)				if (mp_irqs[i].mpc_dstapic == old_id)					mp_irqs[i].mpc_dstapic						= mp_ioapics[apic].mpc_apicid;		/*		 * Read the right value from the MPC table and		 * write it into the ID register.	 	 */		printk(KERN_INFO "...changing IO-APIC physical APIC ID to %d ...",					mp_ioapics[apic].mpc_apicid);		reg_00.bits.ID = mp_ioapics[apic].mpc_apicid;		spin_lock_irqsave(&ioapic_lock, flags);		io_apic_write(apic, 0, reg_00.raw);		spin_unlock_irqrestore(&ioapic_lock, flags);		/*		 * Sanity check		 */		spin_lock_irqsave(&ioapic_lock, flags);		reg_00.raw = io_apic_read(apic, 0);		spin_unlock_irqrestore(&ioapic_lock, flags);		if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid)			panic("could not set ID!\n");		else			printk(" ok.\n");	}}#elsestatic void __init setup_ioapic_ids_from_mpc(void) { }#endif/* * There is a nasty bug in some older SMP boards, their mptable lies * about the timer IRQ. We do the following to work around the situation: * *	- timer IRQ defaults to IO-APIC IRQ *	- if this function detects that timer IRQs are defunct, then we fall *	  back to ISA timer IRQs */static int __init timer_irq_works(void){	unsigned long t1 = jiffies;	local_irq_enable();	/* Let ten ticks pass... */	mdelay((10 * 1000) / HZ);	/*	 * Expect a few ticks at least, to be sure some possible	 * glue logic does not lock up after one or two first	 * ticks in a non-ExtINT mode.  Also the local APIC	 * might have cached one ExtINT interrupt.  Finally, at	 * least one tick may be lost due to delays.	 */	if (jiffies - t1 > 4)		return 1;	return 0;}/* * In the SMP+IOAPIC case it might happen that there are an unspecified * number of pending IRQ events unhandled. These cases are very rare, * so we 'resend' these IRQs via IPIs, to the same CPU. It's much * better to do it this way as thus we do not have to be aware of * 'pending' interrupts in the IRQ path, except at this point. *//* * Edge triggered needs to resend any interrupt * that was delayed but this is now handled in the device * independent code. *//* * Starting up a edge-triggered IO-APIC interrupt is * nasty - we need to make sure that we get the edge. * If it is already asserted for some reason, we need * return 1 to indicate that is was pending. * * This is not complete - we should be able to fake * an edge even if it isn't on the 8259A... */static unsigned int startup_edge_ioapic_irq(unsigned int irq){	int was_pending = 0;	unsigned long flags;	spin_lock_irqsave(&ioapic_lock, flags);	if (irq < 16) {		disable_8259A_irq(irq);		if (i8259A_irq_pending(irq))			was_pending = 1;	}	__unmask_IO_APIC_irq(irq);	spin_unlock_irqrestore(&ioapic_lock, flags);	return was_pending;}/* * Once we have recorded IRQ_PENDING already, we can mask the * interrupt for real. This prevents IRQ storms from unhandled * devices. */static void ack_edge_ioapic_irq(unsigned int irq){	move_irq(irq);	if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))					== (IRQ_PENDING | IRQ_DISABLED))		mask_IO_APIC_irq(irq);	ack_APIC_irq();}/* * Level triggered interrupts can just be masked, * and shutting down and starting up the interrupt * is the same as enabling and disabling them -- except * with a startup need to return a "was pending" value. * * Level triggered interrupts are special because we * do not touch any IO-APIC register while handling * them. We ack the APIC in the end-IRQ handler, not * in the start-IRQ-handler. Protection against reentrance * from the same interrupt is still provided, both by the * generic IRQ layer and by the fact that an unacked local * APIC does not accept IRQs. */static unsigned int startup_level_ioapic_irq (unsigned int irq){	unmask_IO_APIC_irq(irq);	return 0; /* don't check for pending */}static void end_level_ioapic_irq (unsigned int irq){	unsigned long v;	int i;	move_irq(irq);/* * It appears there is an erratum which affects at least version 0x11 * of I/O APIC (that's the 82093AA and cores integrated into various * chipsets).  Under certain conditions a level-triggered interrupt is * erroneously delivered as edge-triggered one but the respective IRR * bit gets set nevertheless.  As a result the I/O unit expects an EOI * message but it will never arrive and further interrupts are blocked * from the source.  The exact reason is so far unknown, but the * phenomenon was observed when two consecutive interrupt requests * from a given source get delivered to the same CPU and the source is * temporarily disabled in between. * * A workaround is to simulate an EOI message manually.  We achieve it * by setting the trigger mode to edge and then to level when the edge * trigger mode gets detected in the TMR of a local APIC for a * level-triggered interrupt.  We mask the source for the time of the * operation to prevent an edge-triggered interrupt escaping meanwhile. * The idea is from Manfred Spraul.  --macro */	i = IO_APIC_VECTOR(irq);	v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));	ack_APIC_irq();	if (!(v & (1 << (i & 0x1f)))) {#ifdef APIC_MISMATCH_DEBUG		atomic_inc(&irq_mis_count);#endif		spin_lock(&ioapic_lock);		__mask_and_edge_IO_APIC_irq(irq);		__unmask_and_level_IO_APIC_irq(irq);		spin_unlock(&ioapic_lock);	}}#ifdef CONFIG_PCI_MSIstatic unsigned int startup_edge_ioapic_vector(unsigned int vector){	int irq = vector_to_irq(vector);	return startup_edge_ioapic_irq(irq);}static void ack_edge_ioapic_vector(unsigned int vector){	int irq = vector_to_irq(vector);	ack_edge_ioapic_irq(irq);}static unsigned int startup_level_ioapic_vector (unsigned int vector){	int irq = vector_to_irq(vector);	return startup_level_ioapic_irq (irq);}static void end_level_ioapic_vector (unsigned int vector){	int irq = vector_to_irq(vector);	end_level_ioapic_irq(irq);}static void mask_IO_APIC_vector (unsigned int vector){	int irq = vector_to_irq(vector);	mask_IO_APIC_irq(irq);}static void unmask_IO_APIC_vector (unsigned int vector){	int irq = vector_to_irq(vector);	unmask_IO_APIC_irq(irq);}static void set_ioapic_affinity_vector (unsigned int vector,					cpumask_t cpu_mask){	int irq = vector_to_irq(vector);	set_ioapic_affinity_irq(irq, cpu_mask);}#endif/* * Level and edge triggered IO-APIC interrupts need different handling, * so we use two separate IRQ descriptors. Edge triggered IRQs can be * handled with the level-triggered descriptor, but that one has slightly * more overhead. Level-triggered interrupts cannot be handled with the * edge-triggered handler, without risking IRQ storms and other ugly * races. */static struct hw_interrupt_type ioapic_edge_type = {	.typename 	= "IO-APIC-edge",	.startup 	= startup_edge_ioapic,	.shutdown 	= shutdown_edge_ioapic,	.enable 	= enable_edge_ioapic,	.disable 	= disable_edge_ioapic,	.ack 		= ack_edge_ioapic,	.end 		= end_edge_ioapic,	.set_affinity 	= set_ioapic_affinity,};static struct hw_interrupt_type ioapic_level_type = {	.typename 	= "IO-APIC-level",	.startup 	= startup_level_ioapic,

⌨️ 快捷键说明

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