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

📄 apic_64.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *	Local APIC handling, local APIC timers * *	(c) 1999, 2000 Ingo Molnar <mingo@redhat.com> * *	Fixes *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs; *					thanks to Eric Gilmore *					and Rolf G. Tews *					for testing these extensively. *	Maciej W. Rozycki	:	Various updates and fixes. *	Mikael Pettersson	:	Power Management for UP-APIC. *	Pavel Machek and *	Mikael Pettersson	:	PM converted to driver model. */#include <linux/init.h>#include <linux/mm.h>#include <linux/delay.h>#include <linux/bootmem.h>#include <linux/interrupt.h>#include <linux/mc146818rtc.h>#include <linux/kernel_stat.h>#include <linux/sysdev.h>#include <linux/module.h>#include <linux/ioport.h>#include <linux/clockchips.h>#include <asm/atomic.h>#include <asm/smp.h>#include <asm/mtrr.h>#include <asm/mpspec.h>#include <asm/pgalloc.h>#include <asm/mach_apic.h>#include <asm/nmi.h>#include <asm/idle.h>#include <asm/proto.h>#include <asm/timex.h>#include <asm/hpet.h>#include <asm/apic.h>int apic_verbosity;int disable_apic_timer __cpuinitdata;static int apic_calibrate_pmtmr __initdata;/* Local APIC timer works in C2? */int local_apic_timer_c2_ok;EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);static struct resource *ioapic_resources;static struct resource lapic_resource = {	.name = "Local APIC",	.flags = IORESOURCE_MEM | IORESOURCE_BUSY,};static unsigned int calibration_result;static int lapic_next_event(unsigned long delta,			    struct clock_event_device *evt);static void lapic_timer_setup(enum clock_event_mode mode,			      struct clock_event_device *evt);static void lapic_timer_broadcast(cpumask_t mask);static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen);static struct clock_event_device lapic_clockevent = {	.name		= "lapic",	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT			| CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,	.shift		= 32,	.set_mode	= lapic_timer_setup,	.set_next_event	= lapic_next_event,	.broadcast	= lapic_timer_broadcast,	.rating		= 100,	.irq		= -1,};static DEFINE_PER_CPU(struct clock_event_device, lapic_events);static int lapic_next_event(unsigned long delta,			    struct clock_event_device *evt){	apic_write(APIC_TMICT, delta);	return 0;}static void lapic_timer_setup(enum clock_event_mode mode,			      struct clock_event_device *evt){	unsigned long flags;	unsigned int v;	/* Lapic used as dummy for broadcast ? */	if (evt->features & CLOCK_EVT_FEAT_DUMMY)		return;	local_irq_save(flags);	switch (mode) {	case CLOCK_EVT_MODE_PERIODIC:	case CLOCK_EVT_MODE_ONESHOT:		__setup_APIC_LVTT(calibration_result,				  mode != CLOCK_EVT_MODE_PERIODIC, 1);		break;	case CLOCK_EVT_MODE_UNUSED:	case CLOCK_EVT_MODE_SHUTDOWN:		v = apic_read(APIC_LVTT);		v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);		apic_write(APIC_LVTT, v);		break;	case CLOCK_EVT_MODE_RESUME:		/* Nothing to do here */		break;	}	local_irq_restore(flags);}/* * Local APIC timer broadcast function */static void lapic_timer_broadcast(cpumask_t mask){#ifdef CONFIG_SMP	send_IPI_mask(mask, LOCAL_TIMER_VECTOR);#endif}static void apic_pm_activate(void);void apic_wait_icr_idle(void){	while (apic_read(APIC_ICR) & APIC_ICR_BUSY)		cpu_relax();}unsigned int safe_apic_wait_icr_idle(void){	unsigned int send_status;	int timeout;	timeout = 0;	do {		send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;		if (!send_status)			break;		udelay(100);	} while (timeout++ < 1000);	return send_status;}void enable_NMI_through_LVT0 (void * dummy){	unsigned int v;	/* unmask and set to NMI */	v = APIC_DM_NMI;	apic_write(APIC_LVT0, v);}int get_maxlvt(void){	unsigned int v, maxlvt;	v = apic_read(APIC_LVR);	maxlvt = GET_APIC_MAXLVT(v);	return maxlvt;}/* * 'what should we do if we get a hw irq event on an illegal vector'. * each architecture has to answer this themselves. */void ack_bad_irq(unsigned int irq){	printk("unexpected IRQ trap at vector %02x\n", irq);	/*	 * Currently unexpected vectors happen only on SMP and APIC.	 * We _must_ ack these because every local APIC has only N	 * irq slots per priority level, and a 'hanging, unacked' IRQ	 * holds up an irq slot - in excessive cases (when multiple	 * unexpected vectors occur) that might lock up the APIC	 * completely.	 * But don't ack when the APIC is disabled. -AK	 */	if (!disable_apic)		ack_APIC_irq();}void clear_local_APIC(void){	int maxlvt;	unsigned int v;	maxlvt = get_maxlvt();	/*	 * 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(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(APIC_LVTT, v | APIC_LVT_MASKED);	v = apic_read(APIC_LVT0);	apic_write(APIC_LVT0, v | APIC_LVT_MASKED);	v = apic_read(APIC_LVT1);	apic_write(APIC_LVT1, v | APIC_LVT_MASKED);	if (maxlvt >= 4) {		v = apic_read(APIC_LVTPC);		apic_write(APIC_LVTPC, v | APIC_LVT_MASKED);	}	/*	 * Clean APIC state for other OSs:	 */	apic_write(APIC_LVTT, APIC_LVT_MASKED);	apic_write(APIC_LVT0, APIC_LVT_MASKED);	apic_write(APIC_LVT1, APIC_LVT_MASKED);	if (maxlvt >= 3)		apic_write(APIC_LVTERR, APIC_LVT_MASKED);	if (maxlvt >= 4)		apic_write(APIC_LVTPC, APIC_LVT_MASKED);	apic_write(APIC_ESR, 0);	apic_read(APIC_ESR);}void disconnect_bsp_APIC(int virt_wire_setup){	/* Go back to Virtual Wire compatibility mode */	unsigned long value;	/* For the spurious interrupt use vector F, and enable it */	value = apic_read(APIC_SPIV);	value &= ~APIC_VECTOR_MASK;	value |= APIC_SPIV_APIC_ENABLED;	value |= 0xf;	apic_write(APIC_SPIV, value);	if (!virt_wire_setup) {		/*		 * For LVT0 make it edge triggered, active high,		 * external and enabled		 */		value = apic_read(APIC_LVT0);		value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |			APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |			APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED );		value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;		value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);		apic_write(APIC_LVT0, value);	} else {		/* Disable LVT0 */		apic_write(APIC_LVT0, APIC_LVT_MASKED);	}	/* For LVT1 make it edge triggered, active high, nmi and enabled */	value = apic_read(APIC_LVT1);	value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |			APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |			APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);	value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;	value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);	apic_write(APIC_LVT1, value);}void disable_local_APIC(void){	unsigned int value;	clear_local_APIC();	/*	 * Disable APIC (implies clearing of registers	 * for 82489DX!).	 */	value = apic_read(APIC_SPIV);	value &= ~APIC_SPIV_APIC_ENABLED;	apic_write(APIC_SPIV, value);}void lapic_shutdown(void){	unsigned long flags;	if (!cpu_has_apic)		return;	local_irq_save(flags);	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 = 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);	apic_write(APIC_ID, reg0 ^ APIC_ID_MASK);	reg1 = apic_read(APIC_ID);	apic_printk(APIC_DEBUG, "Getting ID: %x\n", reg1);	apic_write(APIC_ID, reg0);	if (reg1 != (reg0 ^ APIC_ID_MASK))		return 0;	/*	 * 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;}void __init sync_Arb_IDs(void){	/* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 */	unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR));	if (ver >= 0x14)	/* P4 or higher */		return;	/*	 * Wait for idle.	 */	apic_wait_icr_idle();	apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n");	apic_write(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 int 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;	value = apic_read(APIC_LVR);	/*	 * 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;	value |= APIC_SPIV_FOCUS_DISABLED;	value |= SPURIOUS_APIC_VECTOR;	apic_write(APIC_SPIV, value);	/*	 * Set up the virtual wire mode.	 */	apic_write(APIC_LVT0, APIC_DM_EXTINT);	value = APIC_DM_NMI;	apic_write(APIC_LVT1, value);}void __cpuinit setup_local_APIC (void){

⌨️ 快捷键说明

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