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

📄 smp.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * $Id: smp.c,v 1.68 1999/09/17 19:38:05 cort Exp $ * * Smp support for ppc. * * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great * deal of code from the sparc and intel versions. * * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu> * * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes * (troy@microux.com, hozer@drgw.net) */#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/interrupt.h>#include <linux/kernel_stat.h>#include <linux/delay.h>#define __KERNEL_SYSCALLS__#include <linux/unistd.h>#include <linux/init.h>#include <linux/openpic.h>#include <linux/spinlock.h>#include <asm/ptrace.h>#include <asm/atomic.h>#include <asm/irq.h>#include <asm/page.h>#include <asm/pgtable.h>#include <asm/hardirq.h>#include <asm/softirq.h>#include <asm/init.h>#include <asm/io.h>#include <asm/prom.h>#include <asm/smp.h>#include <asm/gemini.h>#include <asm/time.h>#include "open_pic.h"int smp_threads_ready;volatile int smp_commenced;int smp_num_cpus = 1;struct cpuinfo_PPC cpu_data[NR_CPUS];struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };volatile unsigned char active_kernel_processor = NO_PROC_ID;	/* Processor holding kernel spinlock		*/volatile unsigned long ipi_count;spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;unsigned int prof_multiplier[NR_CPUS];unsigned int prof_counter[NR_CPUS];cycles_t cacheflush_time;/* this has to go in the data section because it is accessed from prom_init */int smp_hw_index[NR_CPUS];/* all cpu mappings are 1-1 -- Cort */volatile unsigned long cpu_callin_map[NR_CPUS];int start_secondary(void *);extern int cpu_idle(void *unused);u_int openpic_read(volatile u_int *addr);void smp_call_function_interrupt(void);void smp_message_pass(int target, int msg, unsigned long data, int wait);/* register for interrupting the primary processor on the powersurge *//* N.B. this is actually the ethernet ROM! */#define PSURGE_PRI_INTR	0xf3019000/* register for interrupting the secondary processor on the powersurge */#define PSURGE_SEC_INTR	0xf80000c0/* register for storing the start address for the secondary processor */#define PSURGE_START	0xf2800000/* virtual addresses for the above */volatile u32 *psurge_pri_intr;volatile u32 *psurge_sec_intr;volatile u32 *psurge_start;/* Since OpenPIC has only 4 IPIs, we use slightly different message numbers. */#define PPC_MSG_CALL_FUNCTION	0#define PPC_MSG_RESCHEDULE	1#define PPC_MSG_INVALIDATE_TLB	2#define PPC_MSG_XMON_BREAK	3static inline void set_tb(unsigned int upper, unsigned int lower){	mtspr(SPRN_TBWU, upper);	mtspr(SPRN_TBWL, lower);}void smp_local_timer_interrupt(struct pt_regs * regs){	int cpu = smp_processor_id();	if (!--prof_counter[cpu]) {		update_process_times(user_mode(regs));		prof_counter[cpu]=prof_multiplier[cpu];	}}void smp_message_recv(int msg, struct pt_regs *regs){	ipi_count++;		switch( msg ) {	case PPC_MSG_CALL_FUNCTION:		smp_call_function_interrupt();		break;	case PPC_MSG_RESCHEDULE: 		current->need_resched = 1;		break;	case PPC_MSG_INVALIDATE_TLB:		_tlbia();		break;#ifdef CONFIG_XMON	case PPC_MSG_XMON_BREAK:		xmon(regs);		break;#endif /* CONFIG_XMON */	default:		printk("SMP %d: smp_message_recv(): unknown msg %d\n",		       smp_processor_id(), msg);		break;	}}/* * As it is now, if we're sending two message at the same time * we have race conditions on Pmac.  The PowerSurge doesn't easily * allow us to send IPI messages so we put the messages in * smp_message[]. * * This is because don't have several IPI's on the PowerSurge even though * we do on the chrp.  It would be nice to use actual IPI's such as with * openpic rather than this. *  -- Cort */int pmac_smp_message[NR_CPUS];void pmac_smp_message_recv(struct pt_regs *regs){	int cpu = smp_processor_id();	int msg;	/* clear interrupt */	if (cpu == 1)		out_be32(psurge_sec_intr, ~0);	if (smp_num_cpus < 2)		return;	/* make sure there is a message there */	msg = pmac_smp_message[cpu];	if (msg == 0)		return; 	/* reset message */	pmac_smp_message[cpu] = 0;	smp_message_recv(msg - 1, regs);}voidpmac_primary_intr(int irq, void *d, struct pt_regs *regs){	pmac_smp_message_recv(regs);}/* * 750's don't broadcast tlb invalidates so * we have to emulate that behavior. *   -- Cort */void smp_send_tlb_invalidate(int cpu){	if ( (_get_PVR()>>16) == 8 )		smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_INVALIDATE_TLB, 0, 0);}void smp_send_reschedule(int cpu){	/*	 * This is only used if `cpu' is running an idle task,	 * so it will reschedule itself anyway...	 *	 * This isn't the case anymore since the other CPU could be	 * sleeping and won't reschedule until the next interrupt (such	 * as the timer).	 *  -- Cort	 */	/* This is only used if `cpu' is running an idle task,	   so it will reschedule itself anyway... */	smp_message_pass(cpu, PPC_MSG_RESCHEDULE, 0, 0);}#ifdef CONFIG_XMONvoid smp_send_xmon_break(int cpu){	smp_message_pass(cpu, PPC_MSG_XMON_BREAK, 0, 0);}#endif /* CONFIG_XMON */static void stop_this_cpu(void *dummy){	__cli();	while (1)		;}void smp_send_stop(void){	smp_call_function(stop_this_cpu, NULL, 1, 0);	smp_num_cpus = 1;}/* * Structure and data for smp_call_function(). This is designed to minimise * static memory requirements. It also looks cleaner. * Stolen from the i386 version. */static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;static volatile struct call_data_struct {	void (*func) (void *info);	void *info;	atomic_t started;	atomic_t finished;	int wait;} *call_data;/* * this function sends a 'generic call function' IPI to all other CPUs * in the system. */int smp_call_function (void (*func) (void *info), void *info, int nonatomic,			int wait)/* * [SUMMARY] Run a function on all other CPUs. * <func> The function to run. This must be fast and non-blocking. * <info> An arbitrary pointer to pass to the function. * <nonatomic> currently unused. * <wait> If true, wait (atomically) until function has completed on other CPUs. * [RETURNS] 0 on success, else a negative status code. Does not return until * remote CPUs are nearly ready to execute <<func>> or are or have executed. * * You must not call this function with disabled interrupts or from a * hardware interrupt handler, you may call it from a bottom half handler. */{	struct call_data_struct data;	int ret = -1, cpus = smp_num_cpus-1;	int timeout;	if (!cpus)		return 0;	data.func = func;	data.info = info;	atomic_set(&data.started, 0);	data.wait = wait;	if (wait)		atomic_set(&data.finished, 0);	spin_lock_bh(&call_lock);	call_data = &data;	/* Send a message to all other CPUs and wait for them to respond */	smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION, 0, 0);	/* Wait for response */	timeout = 1000000;	while (atomic_read(&data.started) != cpus) {		if (--timeout == 0) {			printk("smp_call_function on cpu %d: other cpus not responding (%d)\n",			       smp_processor_id(), atomic_read(&data.started));			goto out;		}		barrier();		udelay(1);	}	if (wait) {		timeout = 1000000;		while (atomic_read(&data.finished) != cpus) {			if (--timeout == 0) {				printk("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n",				       smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started));				goto out;			}			barrier();			udelay(1);		}	}	ret = 0; out:	spin_unlock_bh(&call_lock);	return ret;}void smp_call_function_interrupt(void){	void (*func) (void *info) = call_data->func;	void *info = call_data->info;	int wait = call_data->wait;	/*	 * Notify initiating CPU that I've grabbed the data and am	 * about to execute the function	 */	atomic_inc(&call_data->started);	/*	 * At this point the info structure may be out of scope unless wait==1	 */

⌨️ 快捷键说明

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