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

📄 apic_32.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
			lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;		else			printk(KERN_WARNING "APIC timer registered as dummy,"			       " due to nmi_watchdog=1!\n");	}	/* Setup the lapic or request the broadcast */	setup_APIC_timer();}void __devinit setup_secondary_APIC_clock(void){	setup_APIC_timer();}/* * The guts of the apic timer interrupt */static void local_apic_timer_interrupt(void){	int cpu = smp_processor_id();	struct clock_event_device *evt = &per_cpu(lapic_events, cpu);	/*	 * Normally we should not be here till LAPIC has been initialized but	 * in some cases like kdump, its possible that there is a pending LAPIC	 * timer interrupt from previous kernel's context and is delivered in	 * new kernel the moment interrupts are enabled.	 *	 * Interrupts are enabled early and LAPIC is setup much later, hence	 * its possible that when we get here evt->event_handler is NULL.	 * Check for event_handler being NULL and discard the interrupt as	 * spurious.	 */	if (!evt->event_handler) {		printk(KERN_WARNING		       "Spurious LAPIC timer interrupt on cpu %d\n", cpu);		/* Switch it off */		lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt);		return;	}	per_cpu(irq_stat, cpu).apic_timer_irqs++;	evt->event_handler(evt);}/* * Local APIC timer interrupt. This is the most natural way for doing * local interrupts, but local timer interrupts can be emulated by * broadcast interrupts too. [in case the hw doesn't support APIC timers] * * [ if a single-CPU system runs an SMP kernel then we call the local *   interrupt as well. Thus we cannot inline the local irq ... ] */void fastcall smp_apic_timer_interrupt(struct pt_regs *regs){	struct pt_regs *old_regs = set_irq_regs(regs);	/*	 * NOTE! We'd better ACK the irq immediately,	 * because timer handling can be slow.	 */	ack_APIC_irq();	/*	 * update_process_times() expects us to have done irq_enter().	 * Besides, if we don't timer interrupts ignore the global	 * interrupt lock, which is the WrongThing (tm) to do.	 */	irq_enter();	local_apic_timer_interrupt();	irq_exit();	set_irq_regs(old_regs);}int setup_profiling_timer(unsigned int multiplier){	return -EINVAL;}/* * Local APIC start and shutdown *//** * clear_local_APIC - shutdown the local APIC * * This is called, when a CPU is disabled and before rebooting, so the state of * the local APIC has no dangling leftovers. Also used to cleanout any BIOS * leftovers during boot. */void clear_local_APIC(void){	int maxlvt = lapic_get_maxlvt();	unsigned long v;	/*	 * Masking an LVT entry can trigger a local APIC error	 * if the vector is zero. Mask LVTERR first to prevent this.	 */	if (maxlvt >= 3) {		v = ERROR_APIC_VECTOR; /* any non-zero vector will do */		apic_write_around(APIC_LVTERR, v | APIC_LVT_MASKED);	}	/*	 * Careful: we have to set masks only first to deassert	 * any level-triggered sources.	 */	v = apic_read(APIC_LVTT);	apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);	v = apic_read(APIC_LVT0);	apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);	v = apic_read(APIC_LVT1);	apic_write_around(APIC_LVT1, v | APIC_LVT_MASKED);	if (maxlvt >= 4) {		v = apic_read(APIC_LVTPC);		apic_write_around(APIC_LVTPC, v | APIC_LVT_MASKED);	}	/* lets not touch this if we didn't frob it */#ifdef CONFIG_X86_MCE_P4THERMAL	if (maxlvt >= 5) {		v = apic_read(APIC_LVTTHMR);		apic_write_around(APIC_LVTTHMR, v | APIC_LVT_MASKED);	}#endif	/*	 * Clean APIC state for other OSs:	 */	apic_write_around(APIC_LVTT, APIC_LVT_MASKED);	apic_write_around(APIC_LVT0, APIC_LVT_MASKED);	apic_write_around(APIC_LVT1, APIC_LVT_MASKED);	if (maxlvt >= 3)		apic_write_around(APIC_LVTERR, APIC_LVT_MASKED);	if (maxlvt >= 4)		apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);#ifdef CONFIG_X86_MCE_P4THERMAL	if (maxlvt >= 5)		apic_write_around(APIC_LVTTHMR, APIC_LVT_MASKED);#endif	/* Integrated APIC (!82489DX) ? */	if (lapic_is_integrated()) {		if (maxlvt > 3)			/* Clear ESR due to Pentium errata 3AP and 11AP */			apic_write(APIC_ESR, 0);		apic_read(APIC_ESR);	}}/** * disable_local_APIC - clear and disable the local APIC */void disable_local_APIC(void){	unsigned long value;	clear_local_APIC();	/*	 * Disable APIC (implies clearing of registers	 * for 82489DX!).	 */	value = apic_read(APIC_SPIV);	value &= ~APIC_SPIV_APIC_ENABLED;	apic_write_around(APIC_SPIV, value);	/*	 * When LAPIC was disabled by the BIOS and enabled by the kernel,	 * restore the disabled state.	 */	if (enabled_via_apicbase) {		unsigned int l, h;		rdmsr(MSR_IA32_APICBASE, l, h);		l &= ~MSR_IA32_APICBASE_ENABLE;		wrmsr(MSR_IA32_APICBASE, l, h);	}}/* * If Linux enabled the LAPIC against the BIOS default disable it down before * re-entering the BIOS on shutdown.  Otherwise the BIOS may get confused and * not power-off.  Additionally clear all LVT entries before disable_local_APIC * for the case where Linux didn't enable the LAPIC. */void lapic_shutdown(void){	unsigned long flags;	if (!cpu_has_apic)		return;	local_irq_save(flags);	clear_local_APIC();	if (enabled_via_apicbase)		disable_local_APIC();	local_irq_restore(flags);}/* * This is to verify that we're looking at a real local APIC. * Check these against your board if the CPUs aren't getting * started for no apparent reason. */int __init verify_local_APIC(void){	unsigned int reg0, reg1;	/*	 * The version register is read-only in a real APIC.	 */	reg0 = apic_read(APIC_LVR);	apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg0);	apic_write(APIC_LVR, reg0 ^ APIC_LVR_MASK);	reg1 = apic_read(APIC_LVR);	apic_printk(APIC_DEBUG, "Getting VERSION: %x\n", reg1);	/*	 * The two version reads above should print the same	 * numbers.  If the second one is different, then we	 * poke at a non-APIC.	 */	if (reg1 != reg0)		return 0;	/*	 * Check if the version looks reasonably.	 */	reg1 = GET_APIC_VERSION(reg0);	if (reg1 == 0x00 || reg1 == 0xff)		return 0;	reg1 = lapic_get_maxlvt();	if (reg1 < 0x02 || reg1 == 0xff)		return 0;	/*	 * The ID register is read/write in a real APIC.	 */	reg0 = apic_read(APIC_ID);	apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg0);	/*	 * The next two are just to see if we have sane values.	 * They're only really relevant if we're in Virtual Wire	 * compatibility mode, but most boxes are anymore.	 */	reg0 = apic_read(APIC_LVT0);	apic_printk(APIC_DEBUG, "Getting LVT0: %x\n", reg0);	reg1 = apic_read(APIC_LVT1);	apic_printk(APIC_DEBUG, "Getting LVT1: %x\n", reg1);	return 1;}/** * sync_Arb_IDs - synchronize APIC bus arbitration IDs */void __init sync_Arb_IDs(void){	/*	 * Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 And not	 * needed on AMD.	 */	if (modern_apic() || boot_cpu_data.x86_vendor == X86_VENDOR_AMD)		return;	/*	 * Wait for idle.	 */	apic_wait_icr_idle();	apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n");	apic_write_around(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG				| APIC_DM_INIT);}/* * An initial setup of the virtual wire mode. */void __init init_bsp_APIC(void){	unsigned long value;	/*	 * Don't do the setup now if we have a SMP BIOS as the	 * through-I/O-APIC virtual wire mode might be active.	 */	if (smp_found_config || !cpu_has_apic)		return;	/*	 * Do not trust the local APIC being empty at bootup.	 */	clear_local_APIC();	/*	 * Enable APIC.	 */	value = apic_read(APIC_SPIV);	value &= ~APIC_VECTOR_MASK;	value |= APIC_SPIV_APIC_ENABLED;	/* This bit is reserved on P4/Xeon and should be cleared */	if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&	    (boot_cpu_data.x86 == 15))		value &= ~APIC_SPIV_FOCUS_DISABLED;	else		value |= APIC_SPIV_FOCUS_DISABLED;	value |= SPURIOUS_APIC_VECTOR;	apic_write_around(APIC_SPIV, value);	/*	 * Set up the virtual wire mode.	 */	apic_write_around(APIC_LVT0, APIC_DM_EXTINT);	value = APIC_DM_NMI;	if (!lapic_is_integrated())		/* 82489DX */		value |= APIC_LVT_LEVEL_TRIGGER;	apic_write_around(APIC_LVT1, value);}/** * setup_local_APIC - setup the local APIC */void __cpuinit setup_local_APIC(void){	unsigned long oldvalue, value, maxlvt, integrated;	int i, j;	/* Pound the ESR really hard over the head with a big hammer - mbligh */	if (esr_disable) {		apic_write(APIC_ESR, 0);		apic_write(APIC_ESR, 0);		apic_write(APIC_ESR, 0);		apic_write(APIC_ESR, 0);	}	integrated = lapic_is_integrated();	/*	 * Double-check whether this APIC is really registered.	 */	if (!apic_id_registered())		BUG();	/*	 * Intel recommends to set DFR, LDR and TPR before enabling	 * an APIC.  See e.g. "AP-388 82489DX User's Manual" (Intel	 * document number 292116).  So here it goes...	 */	init_apic_ldr();	/*	 * Set Task Priority to 'accept all'. We never change this	 * later on.	 */	value = apic_read(APIC_TASKPRI);	value &= ~APIC_TPRI_MASK;	apic_write_around(APIC_TASKPRI, value);	/*	 * After a crash, we no longer service the interrupts and a pending	 * interrupt from previous kernel might still have ISR bit set.	 *	 * Most probably by now CPU has serviced that pending interrupt and	 * it might not have done the ack_APIC_irq() because it thought,	 * interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it	 * does not clear the ISR bit and cpu thinks it has already serivced	 * the interrupt. Hence a vector might get locked. It was noticed	 * for timer irq (vector 0x31). Issue an extra EOI to clear ISR.	 */	for (i = APIC_ISR_NR - 1; i >= 0; i--) {		value = apic_read(APIC_ISR + i*0x10);		for (j = 31; j >= 0; j--) {			if (value & (1<<j))				ack_APIC_irq();		}	}	/*	 * Now that we are all set up, enable the APIC	 */	value = apic_read(APIC_SPIV);	value &= ~APIC_VECTOR_MASK;	/*	 * Enable APIC	 */	value |= APIC_SPIV_APIC_ENABLED;	/*	 * Some unknown Intel IO/APIC (or APIC) errata is biting us with	 * certain networking cards. If high frequency interrupts are	 * happening on a particular IOAPIC pin, plus the IOAPIC routing	 * entry is masked/unmasked at a high rate as well then sooner or	 * later IOAPIC line gets 'stuck', no more interrupts are received	 * from the device. If focus CPU is disabled then the hang goes	 * away, oh well :-(	 *	 * [ This bug can be reproduced easily with a level-triggered	 *   PCI Ne2000 networking cards and PII/PIII processors, dual	 *   BX chipset. ]	 */	/*	 * Actually disabling the focus CPU check just makes the hang less	 * frequent as it makes the interrupt distributon model be more	 * like LRU than MRU (the short-term load is more even across CPUs).	 * See also the comment in end_level_ioapic_irq().  --macro	 */	/* Enable focus processor (bit==0) */	value &= ~APIC_SPIV_FOCUS_DISABLED;	/*	 * Set spurious IRQ vector	 */	value |= SPURIOUS_APIC_VECTOR;	apic_write_around(APIC_SPIV, value);	/*	 * Set up LVT0, LVT1:	 *	 * set up through-local-APIC on the BP's LINT0. This is not	 * strictly necessary in pure symmetric-IO mode, but sometimes	 * we delegate interrupts to the 8259A.	 */	/*	 * TODO: set up through-local-APIC from through-I/O-APIC? --macro	 */	value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;	if (!smp_processor_id() && (pic_mode || !value)) {		value = APIC_DM_EXTINT;		apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n",				smp_processor_id());	} else {		value = APIC_DM_EXTINT | APIC_LVT_MASKED;		apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n",				smp_processor_id());	}	apic_write_around(APIC_LVT0, value);	/*	 * only the BP should see the LINT1 NMI signal, obviously.	 */	if (!smp_processor_id())		value = APIC_DM_NMI;	else		value = APIC_DM_NMI | APIC_LVT_MASKED;	if (!integrated)		/* 82489DX */		value |= APIC_LVT_LEVEL_TRIGGER;	apic_write_around(APIC_LVT1, value);	if (integrated && !esr_disable) {		/* !82489DX */		maxlvt = lapic_get_maxlvt();		if (maxlvt > 3)		/* Due to the Pentium erratum 3AP. */			apic_write(APIC_ESR, 0);		oldvalue = apic_read(APIC_ESR);		/* enables sending errors */		value = ERROR_APIC_VECTOR;		apic_write_around(APIC_LVTERR, value);		/*		 * spec says clear errors after enabling vector.		 */		if (maxlvt > 3)			apic_write(APIC_ESR, 0);		value = apic_read(APIC_ESR);		if (value != oldvalue)			apic_printk(APIC_VERBOSE, "ESR value before enabling "				"vector: 0x%08lx  after: 0x%08lx\n",				oldvalue, value);	} else {		if (esr_disable)			/*			 * Something untraceable is creating bad interrupts on			 * secondary quads ... for the moment, just leave the			 * ESR disabled - we can't do anything useful with the			 * errors anyway - mbligh			 */			printk(KERN_INFO "Leaving ESR disabled.\n");		else			printk(KERN_INFO "No ESR for 82489DX.\n");	}	/* Disable the local apic timer */	value = apic_read(APIC_LVTT);	value |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);	apic_write_around(APIC_LVTT, value);	setup_apic_nmi_watchdog(NULL);	apic_pm_activate();}/* * Detect and initialize APIC */static int __init detect_init_APIC (void){	u32 h, l, features;	/* Disabled by kernel option? */	if (enable_local_apic < 0)		return -1;	switch (boot_cpu_data.x86_vendor) {	case X86_VENDOR_AMD:		if ((boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1) ||		    (boot_cpu_data.x86 == 15))			break;		goto no_apic;	case X86_VENDOR_INTEL:		if (boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15 ||		    (boot_cpu_data.x86 == 5 && cpu_has_apic))			break;		goto no_apic;	default:		goto no_apic;	}	if (!cpu_has_apic) {

⌨️ 快捷键说明

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