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

📄 voyager_smp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* -*- mode: c; c-basic-offset: 8 -*- *//* Copyright (C) 1999,2001 * * Author: J.E.J.Bottomley@HansenPartnership.com * * linux/arch/i386/kernel/voyager_smp.c * * This file provides all the same external entries as smp.c but uses * the voyager hal to provide the functionality */#include <linux/module.h>#include <linux/mm.h>#include <linux/kernel_stat.h>#include <linux/delay.h>#include <linux/mc146818rtc.h>#include <linux/cache.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/bootmem.h>#include <linux/completion.h>#include <asm/desc.h>#include <asm/voyager.h>#include <asm/vic.h>#include <asm/mtrr.h>#include <asm/pgalloc.h>#include <asm/tlbflush.h>#include <asm/arch_hooks.h>/* TLB state -- visible externally, indexed physically */DEFINE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate) = { &init_mm, 0 };/* CPU IRQ affinity -- set to all ones initially */static unsigned long cpu_irq_affinity[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1]  = ~0UL };/* per CPU data structure (for /proc/cpuinfo et al), visible externally * indexed physically */DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);EXPORT_PER_CPU_SYMBOL(cpu_info);/* physical ID of the CPU used to boot the system */unsigned char boot_cpu_id;/* The memory line addresses for the Quad CPIs */struct voyager_qic_cpi *voyager_quad_cpi_addr[NR_CPUS] __cacheline_aligned;/* The masks for the Extended VIC processors, filled in by cat_init */__u32 voyager_extended_vic_processors = 0;/* Masks for the extended Quad processors which cannot be VIC booted */__u32 voyager_allowed_boot_processors = 0;/* The mask for the Quad Processors (both extended and non-extended) */__u32 voyager_quad_processors = 0;/* Total count of live CPUs, used in process.c to display * the CPU information and in irq.c for the per CPU irq * activity count.  Finally exported by i386_ksyms.c */static int voyager_extended_cpus = 1;/* Have we found an SMP box - used by time.c to do the profiling   interrupt for timeslicing; do not set to 1 until the per CPU timer   interrupt is active */int smp_found_config = 0;/* Used for the invalidate map that's also checked in the spinlock */static volatile unsigned long smp_invalidate_needed;/* Bitmask of currently online CPUs - used by setup.c for   /proc/cpuinfo, visible externally but still physical */cpumask_t cpu_online_map = CPU_MASK_NONE;EXPORT_SYMBOL(cpu_online_map);/* Bitmask of CPUs present in the system - exported by i386_syms.c, used * by scheduler but indexed physically */cpumask_t phys_cpu_present_map = CPU_MASK_NONE;/* The internal functions */static void send_CPI(__u32 cpuset, __u8 cpi);static void ack_CPI(__u8 cpi);static int ack_QIC_CPI(__u8 cpi);static void ack_special_QIC_CPI(__u8 cpi);static void ack_VIC_CPI(__u8 cpi);static void send_CPI_allbutself(__u8 cpi);static void mask_vic_irq(unsigned int irq);static void unmask_vic_irq(unsigned int irq);static unsigned int startup_vic_irq(unsigned int irq);static void enable_local_vic_irq(unsigned int irq);static void disable_local_vic_irq(unsigned int irq);static void before_handle_vic_irq(unsigned int irq);static void after_handle_vic_irq(unsigned int irq);static void set_vic_irq_affinity(unsigned int irq, cpumask_t mask);static void ack_vic_irq(unsigned int irq);static void vic_enable_cpi(void);static void do_boot_cpu(__u8 cpuid);static void do_quad_bootstrap(void);int hard_smp_processor_id(void);int safe_smp_processor_id(void);/* Inline functions */static inline voidsend_one_QIC_CPI(__u8 cpu, __u8 cpi){	voyager_quad_cpi_addr[cpu]->qic_cpi[cpi].cpi =		(smp_processor_id() << 16) + cpi;}static inline voidsend_QIC_CPI(__u32 cpuset, __u8 cpi){	int cpu;	for_each_online_cpu(cpu) {		if(cpuset & (1<<cpu)) {#ifdef VOYAGER_DEBUG			if(!cpu_isset(cpu, cpu_online_map))				VDEBUG(("CPU%d sending cpi %d to CPU%d not in cpu_online_map\n", hard_smp_processor_id(), cpi, cpu));#endif			send_one_QIC_CPI(cpu, cpi - QIC_CPI_OFFSET);		}	}}static inline voidwrapper_smp_local_timer_interrupt(void){	irq_enter();	smp_local_timer_interrupt();	irq_exit();}static inline voidsend_one_CPI(__u8 cpu, __u8 cpi){	if(voyager_quad_processors & (1<<cpu))		send_one_QIC_CPI(cpu, cpi - QIC_CPI_OFFSET);	else		send_CPI(1<<cpu, cpi);}static inline voidsend_CPI_allbutself(__u8 cpi){	__u8 cpu = smp_processor_id();	__u32 mask = cpus_addr(cpu_online_map)[0] & ~(1 << cpu);	send_CPI(mask, cpi);}static inline intis_cpu_quad(void){	__u8 cpumask = inb(VIC_PROC_WHO_AM_I);	return ((cpumask & QUAD_IDENTIFIER) == QUAD_IDENTIFIER);}static inline intis_cpu_extended(void){	__u8 cpu = hard_smp_processor_id();	return(voyager_extended_vic_processors & (1<<cpu));}static inline intis_cpu_vic_boot(void){	__u8 cpu = hard_smp_processor_id();	return(voyager_extended_vic_processors	       & voyager_allowed_boot_processors & (1<<cpu));}static inline voidack_CPI(__u8 cpi){	switch(cpi) {	case VIC_CPU_BOOT_CPI:		if(is_cpu_quad() && !is_cpu_vic_boot())			ack_QIC_CPI(cpi);		else			ack_VIC_CPI(cpi);		break;	case VIC_SYS_INT:	case VIC_CMN_INT: 		/* These are slightly strange.  Even on the Quad card,		 * They are vectored as VIC CPIs */		if(is_cpu_quad())			ack_special_QIC_CPI(cpi);		else			ack_VIC_CPI(cpi);		break;	default:		printk("VOYAGER ERROR: CPI%d is in common CPI code\n", cpi);		break;	}}/* local variables *//* The VIC IRQ descriptors -- these look almost identical to the * 8259 IRQs except that masks and things must be kept per processor */static struct irq_chip vic_chip = {	.name		= "VIC",	.startup	= startup_vic_irq,	.mask		= mask_vic_irq,	.unmask		= unmask_vic_irq,	.set_affinity	= set_vic_irq_affinity,};/* used to count up as CPUs are brought on line (starts at 0) */static int cpucount = 0;/* steal a page from the bottom of memory for the trampoline and * squirrel its address away here.  This will be in kernel virtual * space */static __u32 trampoline_base;/* The per cpu profile stuff - used in smp_local_timer_interrupt */static DEFINE_PER_CPU(int, prof_multiplier) = 1;static DEFINE_PER_CPU(int, prof_old_multiplier) = 1;static DEFINE_PER_CPU(int, prof_counter) =  1;/* the map used to check if a CPU has booted */static __u32 cpu_booted_map;/* the synchronize flag used to hold all secondary CPUs spinning in * a tight loop until the boot sequence is ready for them */static cpumask_t smp_commenced_mask = CPU_MASK_NONE;/* This is for the new dynamic CPU boot code */cpumask_t cpu_callin_map = CPU_MASK_NONE;cpumask_t cpu_callout_map = CPU_MASK_NONE;EXPORT_SYMBOL(cpu_callout_map);cpumask_t cpu_possible_map = CPU_MASK_NONE;EXPORT_SYMBOL(cpu_possible_map);/* The per processor IRQ masks (these are usually kept in sync) */static __u16 vic_irq_mask[NR_CPUS] __cacheline_aligned;/* the list of IRQs to be enabled by the VIC_ENABLE_IRQ_CPI */static __u16 vic_irq_enable_mask[NR_CPUS] __cacheline_aligned = { 0 };/* Lock for enable/disable of VIC interrupts */static  __cacheline_aligned DEFINE_SPINLOCK(vic_irq_lock);/* The boot processor is correctly set up in PC mode when it  * comes up, but the secondaries need their master/slave 8259 * pairs initializing correctly *//* Interrupt counters (per cpu) and total - used to try to * even up the interrupt handling routines */static long vic_intr_total = 0;static long vic_intr_count[NR_CPUS] __cacheline_aligned = { 0 };static unsigned long vic_tick[NR_CPUS] __cacheline_aligned = { 0 };/* Since we can only use CPI0, we fake all the other CPIs */static unsigned long vic_cpi_mailbox[NR_CPUS] __cacheline_aligned;/* debugging routine to read the isr of the cpu's pic */static inline __u16vic_read_isr(void){	__u16 isr;	outb(0x0b, 0xa0);	isr = inb(0xa0) << 8;	outb(0x0b, 0x20);	isr |= inb(0x20);	return isr;}static __init voidqic_setup(void){	if(!is_cpu_quad()) {		/* not a quad, no setup */		return;	}	outb(QIC_DEFAULT_MASK0, QIC_MASK_REGISTER0);	outb(QIC_CPI_ENABLE, QIC_MASK_REGISTER1);		if(is_cpu_extended()) {		/* the QIC duplicate of the VIC base register */		outb(VIC_DEFAULT_CPI_BASE, QIC_VIC_CPI_BASE_REGISTER);		outb(QIC_DEFAULT_CPI_BASE, QIC_CPI_BASE_REGISTER);		/* FIXME: should set up the QIC timer and memory parity		 * error vectors here */	}}static __init voidvic_setup_pic(void){	outb(1, VIC_REDIRECT_REGISTER_1);	/* clear the claim registers for dynamic routing */	outb(0, VIC_CLAIM_REGISTER_0);	outb(0, VIC_CLAIM_REGISTER_1);	outb(0, VIC_PRIORITY_REGISTER);	/* Set the Primary and Secondary Microchannel vector	 * bases to be the same as the ordinary interrupts	 *	 * FIXME: This would be more efficient using separate	 * vectors. */	outb(FIRST_EXTERNAL_VECTOR, VIC_PRIMARY_MC_BASE);	outb(FIRST_EXTERNAL_VECTOR, VIC_SECONDARY_MC_BASE);	/* Now initiallise the master PIC belonging to this CPU by	 * sending the four ICWs */	/* ICW1: level triggered, ICW4 needed */	outb(0x19, 0x20);	/* ICW2: vector base */	outb(FIRST_EXTERNAL_VECTOR, 0x21);	/* ICW3: slave at line 2 */	outb(0x04, 0x21);	/* ICW4: 8086 mode */	outb(0x01, 0x21);	/* now the same for the slave PIC */	/* ICW1: level trigger, ICW4 needed */	outb(0x19, 0xA0);	/* ICW2: slave vector base */	outb(FIRST_EXTERNAL_VECTOR + 8, 0xA1);		/* ICW3: slave ID */	outb(0x02, 0xA1);	/* ICW4: 8086 mode */	outb(0x01, 0xA1);}static voiddo_quad_bootstrap(void){	if(is_cpu_quad() && is_cpu_vic_boot()) {		int i;		unsigned long flags;		__u8 cpuid = hard_smp_processor_id();		local_irq_save(flags);		for(i = 0; i<4; i++) {			/* FIXME: this would be >>3 &0x7 on the 32 way */			if(((cpuid >> 2) & 0x03) == i)				/* don't lower our own mask! */				continue;			/* masquerade as local Quad CPU */			outb(QIC_CPUID_ENABLE | i, QIC_PROCESSOR_ID);			/* enable the startup CPI */			outb(QIC_BOOT_CPI_MASK, QIC_MASK_REGISTER1);			/* restore cpu id */			outb(0, QIC_PROCESSOR_ID);		}		local_irq_restore(flags);	}}/* Set up all the basic stuff: read the SMP config and make all the * SMP information reflect only the boot cpu.  All others will be * brought on-line later. */void __init find_smp_config(void){	int i;	boot_cpu_id = hard_smp_processor_id();	printk("VOYAGER SMP: Boot cpu is %d\n", boot_cpu_id);	/* initialize the CPU structures (moved from smp_boot_cpus) */	for(i=0; i<NR_CPUS; i++) {		cpu_irq_affinity[i] = ~0;	}	cpu_online_map = cpumask_of_cpu(boot_cpu_id);	/* The boot CPU must be extended */	voyager_extended_vic_processors = 1<<boot_cpu_id;	/* initially, all of the first 8 CPUs can boot */	voyager_allowed_boot_processors = 0xff;	/* set up everything for just this CPU, we can alter	 * this as we start the other CPUs later */	/* now get the CPU disposition from the extended CMOS */	cpus_addr(phys_cpu_present_map)[0] = voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK);	cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 1) << 8;	cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 2) << 16;	cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 3) << 24;	cpu_possible_map = phys_cpu_present_map;	printk("VOYAGER SMP: phys_cpu_present_map = 0x%lx\n", cpus_addr(phys_cpu_present_map)[0]);	/* Here we set up the VIC to enable SMP */	/* enable the CPIs by writing the base vector to their register */	outb(VIC_DEFAULT_CPI_BASE, VIC_CPI_BASE_REGISTER);	outb(1, VIC_REDIRECT_REGISTER_1);	/* set the claim registers for static routing --- Boot CPU gets	 * all interrupts untill all other CPUs started */	outb(0xff, VIC_CLAIM_REGISTER_0);	outb(0xff, VIC_CLAIM_REGISTER_1);	/* Set the Primary and Secondary Microchannel vector	 * bases to be the same as the ordinary interrupts	 *	 * FIXME: This would be more efficient using separate	 * vectors. */	outb(FIRST_EXTERNAL_VECTOR, VIC_PRIMARY_MC_BASE);	outb(FIRST_EXTERNAL_VECTOR, VIC_SECONDARY_MC_BASE);	/* Finally tell the firmware that we're driving */	outb(inb(VOYAGER_SUS_IN_CONTROL_PORT) | VOYAGER_IN_CONTROL_FLAG,	     VOYAGER_SUS_IN_CONTROL_PORT);	current_thread_info()->cpu = boot_cpu_id;	x86_write_percpu(cpu_number, boot_cpu_id);}/* *	The bootstrap kernel entry code has set these up. Save them *	for a given CPU, id is physical */void __initsmp_store_cpu_info(int id){	struct cpuinfo_x86 *c = &cpu_data(id);	*c = boot_cpu_data;	identify_secondary_cpu(c);}/* set up the trampoline and return the physical address of the code */static __u32 __initsetup_trampoline(void){	/* these two are global symbols in trampoline.S */	extern const __u8 trampoline_end[];	extern const __u8 trampoline_data[];	memcpy((__u8 *)trampoline_base, trampoline_data,	       trampoline_end - trampoline_data);	return virt_to_phys((__u8 *)trampoline_base);}/* Routine initially called when a non-boot CPU is brought online */static void __initstart_secondary(void *unused){	__u8 cpuid = hard_smp_processor_id();	/* external functions not defined in the headers */	extern void calibrate_delay(void);	cpu_init();	/* OK, we're in the routine */	ack_CPI(VIC_CPU_BOOT_CPI);	/* setup the 8259 master slave pair belonging to this CPU ---         * we won't actually receive any until the boot CPU         * relinquishes it's static routing mask */	vic_setup_pic();	qic_setup();	if(is_cpu_quad() && !is_cpu_vic_boot()) {		/* clear the boot CPI */		__u8 dummy;		dummy = voyager_quad_cpi_addr[cpuid]->qic_cpi[VIC_CPU_BOOT_CPI].cpi;		printk("read dummy %d\n", dummy);	}	/* lower the mask to receive CPIs */	vic_enable_cpi();	VDEBUG(("VOYAGER SMP: CPU%d, stack at about %p\n", cpuid, &cpuid));	/* enable interrupts */	local_irq_enable();	/* get our bogomips */

⌨️ 快捷键说明

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