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

📄 apic_32.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		/*		 * Over-ride BIOS and try to enable the local APIC only if		 * "lapic" specified.		 */		if (enable_local_apic <= 0) {			printk(KERN_INFO "Local APIC disabled by BIOS -- "			       "you can enable it with \"lapic\"\n");			return -1;		}		/*		 * Some BIOSes disable the local APIC in the APIC_BASE		 * MSR. This can only be done in software for Intel P6 or later		 * and AMD K7 (Model > 1) or later.		 */		rdmsr(MSR_IA32_APICBASE, l, h);		if (!(l & MSR_IA32_APICBASE_ENABLE)) {			printk(KERN_INFO			       "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(KERN_WARNING "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_DISABLED)		nmi_watchdog = NMI_LOCAL_APIC;	printk(KERN_INFO "Found and enabled local APIC!\n");	apic_pm_activate();	return 0;no_apic:	printk(KERN_INFO "No local APIC present or hardware disabled\n");	return -1;}/** * init_apic_mappings - initialize APIC mappings */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);	printk(KERN_DEBUG "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);			printk(KERN_DEBUG "mapped IOAPIC to %08lx (%08lx)\n",			       __fix_to_virt(idx), ioapic_phys);			idx++;		}	}#endif}/* * This initializes the IO-APIC and APIC hardware if this is * a UP kernel. */int __init APIC_init_uniprocessor (void){	if (enable_local_apic < 0)		clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);	if (!smp_found_config && !cpu_has_apic)		return -1;	/*	 * Complain if the BIOS pretends there is one.	 */	if (!cpu_has_apic &&	    APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {		printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",		       boot_cpu_physical_apicid);		clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);		return -1;	}	verify_local_APIC();	connect_bsp_APIC();	/*	 * Hack: In case of kdump, after a crash, kernel might be booting	 * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid	 * might be zero if read from MP tables. Get it from LAPIC.	 */#ifdef CONFIG_CRASH_DUMP	boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));#endif	phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);	setup_local_APIC();#ifdef CONFIG_X86_IO_APIC	if (smp_found_config)		if (!skip_ioapic_setup && nr_ioapics)			setup_IO_APIC();#endif	setup_boot_clock();	return 0;}/* * APIC command line parameters */static int __init parse_lapic(char *arg){	enable_local_apic = 1;	return 0;}early_param("lapic", parse_lapic);static int __init parse_nolapic(char *arg){	enable_local_apic = -1;	clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);	return 0;}early_param("nolapic", parse_nolapic);static int __init parse_disable_lapic_timer(char *arg){	local_apic_timer_disabled = 1;	return 0;}early_param("nolapic_timer", parse_disable_lapic_timer);static int __init parse_lapic_timer_c2_ok(char *arg){	local_apic_timer_c2_ok = 1;	return 0;}early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);static int __init apic_set_verbosity(char *str){	if (strcmp("debug", str) == 0)		apic_verbosity = APIC_DEBUG;	else if (strcmp("verbose", str) == 0)		apic_verbosity = APIC_VERBOSE;	return 1;}__setup("apic=", apic_set_verbosity);/* * Local APIC interrupts *//* * This interrupt should _never_ happen with our APIC/SMP architecture */void smp_spurious_interrupt(struct pt_regs *regs){	unsigned long v;	irq_enter();	/*	 * Check if this really is a spurious interrupt and ACK it	 * if it is a vectored one.  Just in case...	 * Spurious interrupts should not be ACKed.	 */	v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));	if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))		ack_APIC_irq();	/* see sw-dev-man vol 3, chapter 7.4.13.5 */	printk(KERN_INFO "spurious APIC interrupt on CPU#%d, "	       "should never happen.\n", smp_processor_id());	__get_cpu_var(irq_stat).irq_spurious_count++;	irq_exit();}/* * This interrupt should never happen with our APIC/SMP architecture */void smp_error_interrupt(struct pt_regs *regs){	unsigned long v, v1;	irq_enter();	/* First tickle the hardware, only then report what went on. -- REW */	v = apic_read(APIC_ESR);	apic_write(APIC_ESR, 0);	v1 = apic_read(APIC_ESR);	ack_APIC_irq();	atomic_inc(&irq_err_count);	/* Here is what the APIC error bits mean:	   0: Send CS error	   1: Receive CS error	   2: Send accept error	   3: Receive accept error	   4: Reserved	   5: Send illegal vector	   6: Received illegal vector	   7: Illegal register address	*/	printk (KERN_DEBUG "APIC error on CPU%d: %02lx(%02lx)\n",		smp_processor_id(), v , v1);	irq_exit();}/* * Initialize APIC interrupts */void __init apic_intr_init(void){#ifdef CONFIG_SMP	smp_intr_init();#endif	/* self generated IPI for local APIC timer */	set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);	/* IPI vectors for APIC spurious and error interrupts */	set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);	set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);	/* thermal monitor LVT interrupt */#ifdef CONFIG_X86_MCE_P4THERMAL	set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);#endif}/** * connect_bsp_APIC - attach the APIC to the interrupt system */void __init connect_bsp_APIC(void){	if (pic_mode) {		/*		 * Do not trust the local APIC being empty at bootup.		 */		clear_local_APIC();		/*		 * PIC mode, enable APIC mode in the IMCR, i.e.  connect BSP's		 * local APIC to INT and NMI lines.		 */		apic_printk(APIC_VERBOSE, "leaving PIC mode, "				"enabling APIC mode.\n");		outb(0x70, 0x22);		outb(0x01, 0x23);	}	enable_apic_mode();}/** * disconnect_bsp_APIC - detach the APIC from the interrupt system * @virt_wire_setup:	indicates, whether virtual wire mode is selected * * Virtual wire mode is necessary to deliver legacy interrupts even when the * APIC is disabled. */void disconnect_bsp_APIC(int virt_wire_setup){	if (pic_mode) {		/*		 * Put the board back into PIC mode (has an effect only on		 * certain older boards).  Note that APIC interrupts, including		 * IPIs, won't work beyond this point!  The only exception are		 * INIT IPIs.		 */		apic_printk(APIC_VERBOSE, "disabling APIC mode, "				"entering PIC mode.\n");		outb(0x70, 0x22);		outb(0x00, 0x23);	} else {		/* 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_around(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_around(APIC_LVT0, value);		} else {			/* Disable LVT0 */			apic_write_around(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_around(APIC_LVT1, value);	}}/* * Power management */#ifdef CONFIG_PMstatic struct {	int active;	/* 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;	unsigned int apic_thmr;} apic_pm_state;static int lapic_suspend(struct sys_device *dev, pm_message_t state){	unsigned long flags;	int maxlvt;	if (!apic_pm_state.active)		return 0;	maxlvt = lapic_get_maxlvt();	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);	if (maxlvt >= 4)		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);#ifdef CONFIG_X86_MCE_P4THERMAL	if (maxlvt >= 5)		apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);#endif	local_irq_save(flags);	disable_local_APIC();	local_irq_restore(flags);	return 0;}static int lapic_resume(struct sys_device *dev){	unsigned int l, h;	unsigned long flags;	int maxlvt;	if (!apic_pm_state.active)		return 0;	maxlvt = lapic_get_maxlvt();	local_irq_save(flags);	/*	 * 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);#ifdef CONFIG_X86_MCE_P4THERMAL	if (maxlvt >= 5)		apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);#endif	if (maxlvt >= 4)		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);	local_irq_restore(flags);	return 0;}/* * This device has no shutdown method - fully functioning local APICs * are needed on every CPU up until machine_halt/restart/poweroff. */static struct sysdev_class lapic_sysclass = {	set_kset_name("lapic"),	.resume		= lapic_resume,	.suspend	= lapic_suspend,};static struct sys_device device_lapic = {	.id	= 0,	.cls	= &lapic_sysclass,};static void __devinit apic_pm_activate(void){	apic_pm_state.active = 1;}static int __init init_lapic_sysfs(void){	int error;	if (!cpu_has_apic)		return 0;	/* XXX: remove suspend/resume procs if !apic_pm_state.active? */	error = sysdev_class_register(&lapic_sysclass);	if (!error)		error = sysdev_register(&device_lapic);	return error;}device_initcall(init_lapic_sysfs);#else	/* CONFIG_PM */static void apic_pm_activate(void) { }#endif	/* CONFIG_PM */

⌨️ 快捷键说明

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