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

📄 io_apic_32.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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){	unsigned int v;	unsigned long flags;	if (apic_verbosity == APIC_QUIET)		return;	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);}#endif  /*  0  */static void __init enable_IO_APIC(void){	union IO_APIC_reg_01 reg_01;	int i8259_apic, i8259_pin;	int i, apic;	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 (apic = 0; apic < nr_ioapics; apic++) {		spin_lock_irqsave(&ioapic_lock, flags);		reg_01.raw = io_apic_read(apic, 1);		spin_unlock_irqrestore(&ioapic_lock, flags);		nr_ioapic_registers[apic] = reg_01.bits.entries+1;	}	for(apic = 0; apic < nr_ioapics; apic++) {		int pin;		/* See if any of the pins is in ExtINT mode */		for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {			struct IO_APIC_route_entry entry;			entry = ioapic_read_entry(apic, pin);			/* If the interrupt line is enabled and in ExtInt mode			 * I have found the pin where the i8259 is connected.			 */			if ((entry.mask == 0) && (entry.delivery_mode == dest_ExtINT)) {				ioapic_i8259.apic = apic;				ioapic_i8259.pin  = pin;				goto found_i8259;			}		}	} found_i8259:	/* Look to see what if the MP table has reported the ExtINT */	/* If we could not find the appropriate pin by looking at the ioapic	 * the i8259 probably is not connected the ioapic but give the	 * mptable a chance anyway.	 */	i8259_pin  = find_isa_irq_pin(0, mp_ExtINT);	i8259_apic = find_isa_irq_apic(0, mp_ExtINT);	/* Trust the MP table if nothing is setup in the hardware */	if ((ioapic_i8259.pin == -1) && (i8259_pin >= 0)) {		printk(KERN_WARNING "ExtINT not setup in hardware but reported by MP table\n");		ioapic_i8259.pin  = i8259_pin;		ioapic_i8259.apic = i8259_apic;	}	/* Complain if the MP table and the hardware disagree */	if (((ioapic_i8259.apic != i8259_apic) || (ioapic_i8259.pin != i8259_pin)) &&		(i8259_pin >= 0) && (ioapic_i8259.pin >= 0))	{		printk(KERN_WARNING "ExtINT in hardware and MP table differ\n");	}	/*	 * 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();	/*	 * If the i8259 is routed through an IOAPIC	 * Put that IOAPIC in virtual wire mode	 * so legacy interrupts can be delivered.	 */	if (ioapic_i8259.pin != -1) {		struct IO_APIC_route_entry entry;		memset(&entry, 0, sizeof(entry));		entry.mask            = 0; /* Enabled */		entry.trigger         = 0; /* Edge */		entry.irr             = 0;		entry.polarity        = 0; /* High */		entry.delivery_status = 0;		entry.dest_mode       = 0; /* Physical */		entry.delivery_mode   = dest_ExtINT; /* ExtInt */		entry.vector          = 0;		entry.dest.physical.physical_dest =					GET_APIC_ID(apic_read(APIC_ID));		/*		 * Add it to the IO-APIC irq-routing table:		 */		ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry);	}	disconnect_bsp_APIC(ioapic_i8259.pin != -1);}/* * 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;	/*	 * Don't check I/O APIC IDs for xAPIC systems.  They have	 * no meaning without the serial APIC bus.	 */	if (!(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)		|| APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))		return;	/*	 * 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;		}		/*		 * 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);			apic_printk(APIC_VERBOSE, "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.	 	 */		apic_printk(APIC_VERBOSE, 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)			printk("could not set ID!\n");		else			apic_printk(APIC_VERBOSE, " ok.\n");	}}#elsestatic void __init setup_ioapic_ids_from_mpc(void) { }#endifint no_timer_check __initdata;static int __init notimercheck(char *s){	no_timer_check = 1;	return 1;}__setup("no_timer_check", notimercheck);/* * 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;	unsigned long flags;	if (no_timer_check)		return 1;	local_save_flags(flags);	local_irq_enable();	/* Let ten ticks pass... */	mdelay((10 * 1000) / HZ);	local_irq_restore(flags);	/*	 * 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. *//* * Startup quirk: * * 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... * * (We do this for level-triggered IRQs too - it cannot hurt.) */static unsigned int startup_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;}static void ack_ioapic_irq(unsigned int irq){	move_native_irq(irq);	ack_APIC_irq();}static void ack_ioapic_quirk_irq(unsigned int irq){	unsigned long v;	int i;	move_native_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 = irq_vector[irq];	v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));	ack_APIC_irq();	if (!(v & (1 << (i & 0x1f)))) {		atomic_inc(&irq_mis_count);		spin_lock(&ioapic_lock);		__mask_and_edge_IO_APIC_irq(irq);		__unmask_and_level_IO_APIC_irq(irq);		spin_unlock(&ioapic_lock);	}}static int ioapic_retrigger_irq(unsigned int irq){	send_IPI_self(irq_vector[irq]);	return 1;}static struct irq_chip ioapic_chip __read_mostly = {	.name 		= "IO-APIC",	.startup 	= startup_ioapic_irq,	.mask	 	= mask_IO_APIC_irq,	.unmask	 	= unmask_IO_APIC_irq,	.ack 		= ack_ioapic_irq,	.eoi 		= ack_ioapic_quirk_irq,#ifdef CONFIG_SMP	.set_affinity 	= set_ioapic_affinity_irq,#endif	.retrigger	= ioapic_retrigger_irq,};static inline void init_IO_APIC_traps(void){	int irq;	/*	 * NOTE! The local APIC isn't very good at handling	 * multiple interrupts at the same interrupt level.	 * As the interrupt level is determined by taking the	 * vector number and shifting that right by 4, we	 * want to spread these out a bit so that they don't	 * all fall in the same interrupt level.	 *	 * Also, we've got to be careful not to trash gate	 * 0x80, because int 0x80 is hm, kind of importantish. ;)	 */	for (irq = 0; irq < NR_IRQS ; irq++) {		int tmp = irq;		if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) {			/*			 * Hmm.. We don't have an entry for this,			 * so default to an old-fashioned 8259			 * interrupt if we can..			 */			if (irq < 16)				make_8259A_irq(irq);			else				/* Strange. Oh, well.. */				irq_desc[irq].chip = &no_irq_chip;		}	}}/* * The local APIC irq-chip implementation: */static void ack_apic(unsigned int irq){	ack_APIC_irq();}static void mask_lapic_irq (unsigned int irq){	unsigned long v;	v = apic_read(APIC_LVT0);	apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);}static void unmask_lapic_irq (unsigned int irq){	unsigned long v;	v = apic_read(APIC_LVT0);	apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);}static struct irq_chip lapic_chip __read_mostly = {	.name		= "local-APIC-edge",	.mask		= mask_lapic_irq,	.unmask		= unmask_lapic_irq,	.eoi		= ack_apic,};static void setup_nmi (void){	/* 	 * Dirty trick to enable the NMI watchdog ...	 * We put the 8259A master into AEOI mode and	 * unmask on all local APICs LVT0 as NMI.	 *	 * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire')	 * is from Maciej W. Rozycki - so we do not have to EOI from	 * the NMI handler or the timer interrupt.	 */ 	apic_printk(APIC_VERBOSE, KERN_INFO "activating NMI Watchdog ...");	on_each_cpu(enable_NMI_through_LVT0, NULL, 1, 1);	apic_printk(APIC_VERBOSE, " done.\n");}/* * This looks a bit hackish but it's about the only one way of sending * a few INTA cycles to 8259As and any associated glue logic.  ICR does * not support the ExtINT mode, unfortunately.  We need to send these * cycles as some i82489DX-based boards have glue logic that keeps the * 8259A interrupt line asserted until INTA.  --macro */static inline void unlock_ExtINT_logic(void){	int apic, pin, i;	struct IO_APIC_route_entry entry0, entry1;	unsigned char save_control, save_freq_select;

⌨️ 快捷键说明

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