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

📄 io_apic.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 4 页
字号:
	int i, j;	if (apic_verbosity == APIC_QUIET)		return;	printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG);	for (i = 0; i < 8; i++) {		v = apic_read(base + i*0x10);		for (j = 0; j < 32; j++) {			if (v & (1<<j))				printk("1");			else				printk("0");		}		printk("\n");	}}void __apicdebuginit print_local_APIC(void * dummy){	unsigned int v, ver, maxlvt;	if (apic_verbosity == APIC_QUIET)		return;	printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",		smp_processor_id(), hard_smp_processor_id());	v = apic_read(APIC_ID);	printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v, GET_APIC_ID(v));	v = apic_read(APIC_LVR);	printk(KERN_INFO "... APIC VERSION: %08x\n", v);	ver = GET_APIC_VERSION(v);	maxlvt = get_maxlvt();	v = apic_read(APIC_TASKPRI);	printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);	v = apic_read(APIC_ARBPRI);	printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v,		v & APIC_ARBPRI_MASK);	v = apic_read(APIC_PROCPRI);	printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v);	v = apic_read(APIC_EOI);	printk(KERN_DEBUG "... APIC EOI: %08x\n", v);	v = apic_read(APIC_RRR);	printk(KERN_DEBUG "... APIC RRR: %08x\n", v);	v = apic_read(APIC_LDR);	printk(KERN_DEBUG "... APIC LDR: %08x\n", v);	v = apic_read(APIC_DFR);	printk(KERN_DEBUG "... APIC DFR: %08x\n", v);	v = apic_read(APIC_SPIV);	printk(KERN_DEBUG "... APIC SPIV: %08x\n", v);	printk(KERN_DEBUG "... APIC ISR field:\n");	print_APIC_bitfield(APIC_ISR);	printk(KERN_DEBUG "... APIC TMR field:\n");	print_APIC_bitfield(APIC_TMR);	printk(KERN_DEBUG "... APIC IRR field:\n");	print_APIC_bitfield(APIC_IRR);	v = apic_read(APIC_ESR);	printk(KERN_DEBUG "... APIC ESR: %08x\n", v);	v = apic_read(APIC_ICR);	printk(KERN_DEBUG "... APIC ICR: %08x\n", v);	v = apic_read(APIC_ICR2);	printk(KERN_DEBUG "... APIC ICR2: %08x\n", v);	v = apic_read(APIC_LVTT);	printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);	if (maxlvt > 3) {                       /* PC is LVT#4. */		v = apic_read(APIC_LVTPC);		printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v);	}	v = apic_read(APIC_LVT0);	printk(KERN_DEBUG "... APIC LVT0: %08x\n", v);	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 __apicdebuginit 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 i;	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 (i = 0; i < nr_ioapics; i++) {		spin_lock_irqsave(&ioapic_lock, flags);		reg_01.raw = io_apic_read(i, 1);		spin_unlock_irqrestore(&ioapic_lock, flags);		nr_ioapic_registers[i] = reg_01.bits.entries+1;	}	/*	 * 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){	int pin;	/*	 * 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.	 */	pin = find_isa_irq_pin(0, mp_ExtINT);	if (pin != -1) {		struct IO_APIC_route_entry entry;		unsigned long flags;		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   = 7; /* ExtInt */		entry.vector          = 0;		entry.dest.physical.physical_dest = 0;		/*		 * Add it to the IO-APIC irq-routing table:		 */		spin_lock_irqsave(&ioapic_lock, flags);		io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));		io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));		spin_unlock_irqrestore(&ioapic_lock, flags);	}	disconnect_bsp_APIC(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 */static void __init setup_ioapic_ids_from_mpc (void){	union IO_APIC_reg_00 reg_00;	int apic;	int i;	unsigned char old_id;	unsigned long flags;	/*	 * 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;		printk(KERN_INFO "Using IO-APIC %d\n", mp_ioapics[apic].mpc_apicid);		/*		 * 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");	}}/* * 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;	local_irq_enable();	/* Let ten ticks pass... */	mdelay((10 * 1000) / HZ);	/*	 * 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.	 */	/* jiffies wrap? */	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. *//* * 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... */static unsigned int startup_edge_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;}/* * Once we have recorded IRQ_PENDING already, we can mask the * interrupt for real. This prevents IRQ storms from unhandled * devices. */static void ack_edge_ioapic_irq(unsigned int irq){	move_irq(irq);	if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))					== (IRQ_PENDING | IRQ_DISABLED))		mask_IO_APIC_irq(irq);	ack_APIC_irq();}/* * Level triggered interrupts can just be masked, * and shutting down and starting up the interrupt * is the same as enabling and disabling them -- except * with a startup need to return a "was pending" value. * * Level triggered interrupts are special because we * do not touch any IO-APIC register while handling * them. We ack the APIC in the end-IRQ handler, not * in the start-IRQ-handler. Protection against reentrance * from the same interrupt is still provided, both by the * generic IRQ layer and by the fact that an unacked local * APIC does not accept IRQs. */static unsigned int startup_level_ioapic_irq (unsigned int irq){	unmask_IO_APIC_irq(irq);	return 0; /* don't check for pending */}static void end_level_ioapic_irq (unsigned int irq){	move_irq(irq);	ack_APIC_irq();}#ifdef CONFIG_PCI_MSIstatic unsigned int startup_edge_ioapic_vector(unsigned int vector){	int irq = vector_to_irq(vector);	return startup_edge_ioapic_irq(irq);}static void ack_edge_ioapic_vector(unsigned int vector){	int irq = vector_to_irq(vector);	move_native_irq(vector);	ack_edge_ioapic_irq(irq);}static unsigned int startup_level_ioapic_vector (unsigned int vector){	int irq = vector_to_irq(vector);	return startup_level_ioapic_irq (irq);}static void end_level_ioapic_vector (unsigned int vector){	int irq = vector_to_irq(vector);	move_native_irq(vector);	end_level_ioapic_irq(irq);}static void mask_IO_APIC_vector (unsigned int vector){	int irq = vector_to_irq(vector);	mask_IO_APIC_irq(irq);}static void unmask_IO_APIC_vector (unsigned int vector){	int irq = vector_to_irq(vector);	unmask_IO_APIC_irq(irq);}#ifdef CONFIG_SMPstatic void set_ioapic_affinity_vector (unsigned int vector,					cpumask_t cpu_mask){	int irq = vector_to_irq(vector);	set_native_irq_info(vector, cpu_mask);	set_ioapic_affinity_irq(irq, cpu_mask);}#endif // CONFIG_SMP#endif // CONFIG_PCI_MSI/* * Level and edge triggered IO-APIC interrupts need different handling, * so we use two separate IRQ descriptors. Edge triggered IRQs can be * handled with the level-triggered descriptor, but that one has slightly * more overhead. Level-triggered interrupts cannot be handled with the * edge-triggered handler, without risking IRQ storms and other ugly * races. */static struct hw_interrupt_type ioapic_edge_type __read_mostly = {	.typename = "IO-APIC-edge",	.startup 	= startup_edge_ioapic,	.shutdown 	= shutdown_edge_ioapic,	.enable 	= enable_edge_ioapic,	.disable 	= disable_edge_ioapic,	.ack 		= ack_edge_ioapic,	.end 		= end_edge_ioapic,#ifdef CONFIG_SMP	.set_affinity = set_ioapic_affinity,#endif};static struct hw_interrupt_type ioapic_level_type __read_mostly = {	.typename = "IO-APIC-level",	.startup 	= startup_level_ioapic,	.shutdown 	= shutdown_level_ioapic,	.enable 	= enable_level_ioapic,	.disable 	= disable_level_ioapic,	.ack 		= mask_and_ack_level_ioapic,	.end 		= end_level_ioapic,#ifdef CONFIG_SMP	.set_affinity = set_ioapic_affinity,#endif};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++) {

⌨️ 快捷键说明

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