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

📄 apic.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	apic_write_around(APIC_LVT1, value);	if (APIC_INTEGRATED(ver) && !esr_disable) {		/* !82489DX */		maxlvt = get_maxlvt();		if (maxlvt > 3)		/* Due to the Pentium erratum 3AP. */			apic_write(APIC_ESR, 0);		value = apic_read(APIC_ESR);		printk("ESR value before enabling vector: %08lx\n", value);		value = ERROR_APIC_VECTOR;      // enables sending errors		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);		printk("ESR value after enabling vector: %08lx\n", value);	} else {		if (esr_disable)				/* 			 * Something untraceble 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("Leaving ESR disabled.\n");		else 			printk("No ESR for 82489DX.\n");	}	if (nmi_watchdog == NMI_LOCAL_APIC)		setup_apic_nmi_watchdog();}#ifdef CONFIG_PM#include <linux/slab.h>#include <linux/pm.h>static struct {	/* 'active' is true if the local APIC was enabled by us and	   not the BIOS; this signifies that we are also responsible	   for disabling it before entering apm/acpi suspend */	int active;	/* 'perfctr_pmdev' is here because the current (2.4.1) PM	   callback system doesn't handle hierarchical dependencies */	struct pm_dev *perfctr_pmdev;	/* r/w apic fields */	unsigned int apic_id;	unsigned int apic_taskpri;	unsigned int apic_ldr;	unsigned int apic_dfr;	unsigned int apic_spiv;	unsigned int apic_lvtt;	unsigned int apic_lvtpc;	unsigned int apic_lvt0;	unsigned int apic_lvt1;	unsigned int apic_lvterr;	unsigned int apic_tmict;	unsigned int apic_tdcr;} apic_pm_state;static void apic_pm_suspend(void *data){	unsigned long flags;	if (apic_pm_state.perfctr_pmdev)		pm_send(apic_pm_state.perfctr_pmdev, PM_SUSPEND, data);	apic_pm_state.apic_id = apic_read(APIC_ID);	apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI);	apic_pm_state.apic_ldr = apic_read(APIC_LDR);	apic_pm_state.apic_dfr = apic_read(APIC_DFR);	apic_pm_state.apic_spiv = apic_read(APIC_SPIV);	apic_pm_state.apic_lvtt = apic_read(APIC_LVTT);	apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC);	apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0);	apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1);	apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);	apic_pm_state.apic_tmict = apic_read(APIC_TMICT);	apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);	__save_flags(flags);	__cli();	disable_local_APIC();	__restore_flags(flags);}static void apic_pm_resume(void *data){	unsigned int l, h;	unsigned long flags;	__save_flags(flags);	__cli();	/*	 * Make sure the APICBASE points to the right address	 *	 * FIXME! This will be wrong if we ever support suspend on	 * SMP! We'll need to do this as part of the CPU restore!	 */	rdmsr(MSR_IA32_APICBASE, l, h);	l &= ~MSR_IA32_APICBASE_BASE;	l |= MSR_IA32_APICBASE_ENABLE | mp_lapic_addr;	wrmsr(MSR_IA32_APICBASE, l, h);	apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);	apic_write(APIC_ID, apic_pm_state.apic_id);	apic_write(APIC_DFR, apic_pm_state.apic_dfr);	apic_write(APIC_LDR, apic_pm_state.apic_ldr);	apic_write(APIC_TASKPRI, apic_pm_state.apic_taskpri);	apic_write(APIC_SPIV, apic_pm_state.apic_spiv);	apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);	apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);	apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);	apic_write(APIC_LVTT, apic_pm_state.apic_lvtt);	apic_write(APIC_TDCR, apic_pm_state.apic_tdcr);	apic_write(APIC_TMICT, apic_pm_state.apic_tmict);	apic_write(APIC_ESR, 0);	apic_read(APIC_ESR);	apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr);	apic_write(APIC_ESR, 0);	apic_read(APIC_ESR);	__restore_flags(flags);	if (apic_pm_state.perfctr_pmdev)		pm_send(apic_pm_state.perfctr_pmdev, PM_RESUME, data);}static int apic_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data){	switch (rqst) {	case PM_SUSPEND:		apic_pm_suspend(data);		break;	case PM_RESUME:		apic_pm_resume(data);		break;	}	return 0;}/* perfctr driver should call this instead of pm_register() */struct pm_dev *apic_pm_register(pm_dev_t type,				unsigned long id,				pm_callback callback){	struct pm_dev *dev;	if (!apic_pm_state.active)		return pm_register(type, id, callback);	if (apic_pm_state.perfctr_pmdev)		return NULL;	/* we're busy */	dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL);	if (dev) {		memset(dev, 0, sizeof(*dev));		dev->type = type;		dev->id = id;		dev->callback = callback;		apic_pm_state.perfctr_pmdev = dev;	}	return dev;}/* perfctr driver should call this instead of pm_unregister() */void apic_pm_unregister(struct pm_dev *dev){	if (!apic_pm_state.active) {		pm_unregister(dev);	} else if (dev == apic_pm_state.perfctr_pmdev) {		apic_pm_state.perfctr_pmdev = NULL;		kfree(dev);	}}static void __init apic_pm_init1(void){	/* can't pm_register() at this early stage in the boot process	   (causes an immediate reboot), so just set the flag */	apic_pm_state.active = 1;}static void __init apic_pm_init2(void){	if (apic_pm_state.active)		pm_register(PM_SYS_DEV, 0, apic_pm_callback);}#else	/* CONFIG_PM */static inline void apic_pm_init1(void) { }static inline void apic_pm_init2(void) { }#endif	/* CONFIG_PM *//* * Detect and enable local APICs on non-SMP boards. * Original code written by Keir Fraser. *//* * Knob to control our willingness to enable the local APIC. */int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */static int __init lapic_disable(char *str){	enable_local_apic = -1;	clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);	return 0;}__setup("nolapic", lapic_disable);static int __init lapic_enable(char *str){	enable_local_apic = 1;	return 0;}__setup("lapic", lapic_enable);static int __init detect_init_APIC (void){	u32 h, l, features;	extern void get_cpu_vendor(struct cpuinfo_x86*);	/* Disabled by DMI scan or kernel option? */	if (enable_local_apic < 0)		return -1;	/* Workaround for us being called before identify_cpu(). */	get_cpu_vendor(&boot_cpu_data);	switch (boot_cpu_data.x86_vendor) {	case X86_VENDOR_AMD:		if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1)			break;		if (boot_cpu_data.x86 == 15 && cpu_has_apic)			break;		goto no_apic;	case X86_VENDOR_INTEL:		if (boot_cpu_data.x86 == 6 ||		    (boot_cpu_data.x86 == 15 && (cpu_has_apic || enable_local_apic > 0)) ||		    (boot_cpu_data.x86 == 5 && cpu_has_apic))			break;		goto no_apic;	default:		goto no_apic;	}	if (!cpu_has_apic) {		/*		 * Over-ride BIOS and try to enable LAPIC		 * only if "lapic" specified		 */		if (enable_local_apic != 1)			goto no_apic;		/*		 * Some BIOSes disable the local APIC in the		 * APIC_BASE MSR. This can only be done in		 * software for Intel P6 and AMD K7 (Model > 1).		 */		rdmsr(MSR_IA32_APICBASE, l, h);		if (!(l & MSR_IA32_APICBASE_ENABLE)) {			printk("Local APIC disabled by BIOS -- reenabling.\n");			l &= ~MSR_IA32_APICBASE_BASE;			l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;			wrmsr(MSR_IA32_APICBASE, l, h);			enabled_via_apicbase = 1;		}	}	/*	 * The APIC feature bit should now be enabled	 * in `cpuid'	 */	features = cpuid_edx(1);	if (!(features & (1 << X86_FEATURE_APIC))) {		printk("Could not enable APIC!\n");		return -1;	}	set_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability);	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;	/* The BIOS may have set up the APIC at some other address */	rdmsr(MSR_IA32_APICBASE, l, h);	if (l & MSR_IA32_APICBASE_ENABLE)		mp_lapic_addr = l & MSR_IA32_APICBASE_BASE;	if (nmi_watchdog != NMI_NONE)		nmi_watchdog = NMI_LOCAL_APIC;	printk("Found and enabled local APIC!\n");	apic_pm_init1();	return 0;no_apic:	printk("No local APIC present or hardware disabled\n");	return -1;}void __init init_apic_mappings(void){	unsigned long apic_phys;	/*	 * If no local APIC can be found then set up a fake all	 * zeroes page to simulate the local APIC and another	 * one for the IO-APIC.	 */	if (!smp_found_config && detect_init_APIC()) {		apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);		apic_phys = __pa(apic_phys);	} else		apic_phys = mp_lapic_addr;	set_fixmap_nocache(FIX_APIC_BASE, apic_phys);	Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys);	/*	 * Fetch the APIC ID of the BSP in case we have a	 * default configuration (or the MP table is broken).	 */	if (boot_cpu_physical_apicid == -1U)		boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));#ifdef CONFIG_X86_IO_APIC	{		unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;		int i;		for (i = 0; i < nr_ioapics; i++) {			if (smp_found_config) {				ioapic_phys = mp_ioapics[i].mpc_apicaddr;				if (!ioapic_phys) {					printk(KERN_ERR "WARNING: bogus zero IO-APIC address found in MPTABLE, disabling IO/APIC support!\n");					smp_found_config = 0;					skip_ioapic_setup = 1;					goto fake_ioapic_page;				}			} else {fake_ioapic_page:				ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);				ioapic_phys = __pa(ioapic_phys);			}			set_fixmap_nocache(idx, ioapic_phys);			Dprintk("mapped IOAPIC to %08lx (%08lx)\n",					__fix_to_virt(idx), ioapic_phys);			idx++;		}	}#endif}/* * This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts * per second. We assume that the caller has already set up the local * APIC. * * The APIC timer is not exactly sync with the external timer chip, it * closely follows bus clocks. *//* * The timer chip is already set up at HZ interrupts per second here, * but we do not accept timer interrupts yet. We only allow the BP * to calibrate. */static unsigned int __init get_8254_timer_count(void){	extern spinlock_t i8253_lock;	unsigned long flags;	unsigned int count;	spin_lock_irqsave(&i8253_lock, flags);	outb_p(0x00, 0x43);	count = inb_p(0x40);	count |= inb_p(0x40) << 8;	spin_unlock_irqrestore(&i8253_lock, flags);	return count;}void __init wait_8254_wraparound(void){	unsigned int curr_count, prev_count=~0;	int delta;	curr_count = get_8254_timer_count();	do {		prev_count = curr_count;		curr_count = get_8254_timer_count();		delta = curr_count-prev_count;	/*	 * This limit for delta seems arbitrary, but it isn't, it's	 * slightly above the level of error a buggy Mercury/Neptune	 * chipset timer can cause.	 */	} while (delta < 300);}/* * This function sets up the local APIC timer, with a timeout of * 'clocks' APIC bus clock. During calibration we actually call

⌨️ 快捷键说明

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