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

📄 synergy.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
字号:
/* * SN1 Platform specific synergy Support * * Copyright (C) 2000-2002 Silicon Graphics, Inc. All rights reserved. *  * This program is free software; you can redistribute it and/or modify it  * under the terms of version 2 of the GNU General Public License  * as published by the Free Software Foundation. *  * This program is distributed in the hope that it would be useful, but  * WITHOUT ANY WARRANTY; without even the implied warranty of  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  *  * Further, this software is distributed without any warranty that it is  * free of the rightful claim of any third person regarding infringement  * or the like.  Any license provided herein, whether implied or  * otherwise, applies only to this software file.  Patent licenses, if  * any, provided herein do not apply to combinations of this program with  * other software, or any other product whatsoever. *  * You should have received a copy of the GNU General Public  * License along with this program; if not, write the Free Software  * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. *  * Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,  * Mountain View, CA  94043, or: *  * http://www.sgi.com  *  * For further information regarding this notice, see:  *  * http://oss.sgi.com/projects/GenInfo/NoticeExplan */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/spinlock.h>#include <linux/proc_fs.h>#include <asm/ptrace.h>#include <linux/devfs_fs_kernel.h>#include <asm/smp.h>#include <asm/sn/sn_cpuid.h>#include <asm/sn/sn1/bedrock.h>#include <asm/sn/intr.h>#include <asm/sn/addrs.h>#include <asm/sn/nodepda.h>#include <asm/sn/sn1/synergy.h>#include <asm/sn/sndrv.h>int bit_pos_to_irq(int bit);void setclear_mask_b(int irq, int cpuid, int set);void setclear_mask_a(int irq, int cpuid, int set);void * kmalloc(size_t size, int flags);static int synergy_perf_initialized = 0;voidsynergy_intr_alloc(int bit, int cpuid) {	return;}intsynergy_intr_connect(int bit, 		int cpuid){	int irq;	unsigned is_b;	irq = bit_pos_to_irq(bit);	is_b = (cpuid_to_slice(cpuid)) & 1;	if (is_b) {		setclear_mask_b(irq,cpuid,1);		setclear_mask_a(irq,cpuid, 0);	} else {		setclear_mask_a(irq, cpuid, 1);		setclear_mask_b(irq, cpuid, 0);	}	return 0;}voidsetclear_mask_a(int irq, int cpuid, int set){	int synergy;	int nasid;	int reg_num;	unsigned long mask;	unsigned long addr;	unsigned long reg;	unsigned long val;	int my_cnode, my_synergy;	int target_cnode, target_synergy;        /*         * Perform some idiot checks ..         */        if ( (irq < 0) || (irq > 255) ||                (cpuid < 0) || (cpuid > 512) ) {                printk("clear_mask_a: Invalid parameter irq %d cpuid %d\n", irq, cpuid);		return;	}	target_cnode = cpuid_to_cnodeid(cpuid);	target_synergy = cpuid_to_synergy(cpuid);	my_cnode = cpuid_to_cnodeid(smp_processor_id());	my_synergy = cpuid_to_synergy(smp_processor_id());	reg_num = irq / 64;	mask = 1;	mask <<= (irq % 64);	switch (reg_num) {		case 0: 			reg = VEC_MASK0A;			addr = VEC_MASK0A_ADDR;			break;		case 1: 			reg = VEC_MASK1A;			addr = VEC_MASK1A_ADDR;			break;		case 2: 			reg = VEC_MASK2A;			addr = VEC_MASK2A_ADDR;			break;		case 3: 			reg = VEC_MASK3A;			addr = VEC_MASK3A_ADDR;			break;		default:			reg = addr = 0;			break;	}	if (my_cnode == target_cnode && my_synergy == target_synergy) {		// local synergy		val = READ_LOCAL_SYNERGY_REG(addr);		if (set) {			val |= mask;		} else {			val &= ~mask;		}		WRITE_LOCAL_SYNERGY_REG(addr, val);		val = READ_LOCAL_SYNERGY_REG(addr);	} else { /* remote synergy */		synergy = cpuid_to_synergy(cpuid);		nasid = cpuid_to_nasid(cpuid);		val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg);		if (set) {			val |= mask;		} else {			val &= ~mask;		}		REMOTE_SYNERGY_STORE(nasid, synergy, reg, val);	}}voidsetclear_mask_b(int irq, int cpuid, int set){	int synergy;	int nasid;	int reg_num;	unsigned long mask;	unsigned long addr;	unsigned long reg;	unsigned long val;	int my_cnode, my_synergy;	int target_cnode, target_synergy;	/*	 * Perform some idiot checks ..	 */	if ( (irq < 0) || (irq > 255) ||		(cpuid < 0) || (cpuid > 512) ) {		printk("clear_mask_b: Invalid parameter irq %d cpuid %d\n", irq, cpuid);		return;	}	target_cnode = cpuid_to_cnodeid(cpuid);	target_synergy = cpuid_to_synergy(cpuid);	my_cnode = cpuid_to_cnodeid(smp_processor_id());	my_synergy = cpuid_to_synergy(smp_processor_id());	reg_num = irq / 64;	mask = 1;	mask <<= (irq % 64);	switch (reg_num) {		case 0: 			reg = VEC_MASK0B;			addr = VEC_MASK0B_ADDR;			break;		case 1: 			reg = VEC_MASK1B;			addr = VEC_MASK1B_ADDR;			break;		case 2: 			reg = VEC_MASK2B;			addr = VEC_MASK2B_ADDR;			break;		case 3: 			reg = VEC_MASK3B;			addr = VEC_MASK3B_ADDR;			break;		default:			reg = addr = 0;			break;	}	if (my_cnode == target_cnode && my_synergy == target_synergy) {		// local synergy		val = READ_LOCAL_SYNERGY_REG(addr);		if (set) {			val |= mask;		} else {			val &= ~mask;		}		WRITE_LOCAL_SYNERGY_REG(addr, val);		val = READ_LOCAL_SYNERGY_REG(addr);	} else { /* remote synergy */		synergy = cpuid_to_synergy(cpuid);		nasid = cpuid_to_nasid(cpuid);		val = REMOTE_SYNERGY_LOAD(nasid, synergy, reg);		if (set) {			val |= mask;		} else {			val &= ~mask;		}		REMOTE_SYNERGY_STORE(nasid, synergy, reg, val);	}}/* * Synergy perf stats. Multiplexed via timer_interrupt. */static intsynergy_perf_append(uint64_t modesel){	int		cnode;	nodepda_t       *npdap;	synergy_perf_t	*p;	int		checked = 0;	int		err = 0;	/* bit 45 is enable */	modesel |= (1UL << 45);	for (cnode=0; cnode < numnodes; cnode++) {		/* for each node, insert a new synergy_perf entry */		if ((npdap = NODEPDA(cnode)) == NULL) {			printk("synergy_perf_append: cnode=%d NODEPDA(cnode)==NULL, nodepda=%p\n", cnode, (void *)nodepda);			continue;		}		if (npdap->synergy_perf_enabled) {			/* user must disable counting to append new events */			err = -EBUSY;			break;		}		if (!checked && npdap->synergy_perf_data != NULL) {			checked = 1;			for (p = npdap->synergy_perf_first; ;) {				if (p->modesel == modesel)					return 0; /* event already registered */				if ((p = p->next) == npdap->synergy_perf_first)					break;			}		}		/* XX use kmem_alloc_node() when it is implemented */		p = (synergy_perf_t *)kmalloc(sizeof(synergy_perf_t), GFP_KERNEL);		if ((((uint64_t)p) & 7UL) != 0)			BUG(); /* bad alignment */		if (p == NULL) {			err = -ENOMEM;			break;		}		else {			memset(p, 0, sizeof(synergy_perf_t));			p->modesel = modesel;			spin_lock_irq(&npdap->synergy_perf_lock);			if (npdap->synergy_perf_data == NULL) {				/* circular list */				p->next = p;				npdap->synergy_perf_first = p;				npdap->synergy_perf_data = p;			}			else {				p->next = npdap->synergy_perf_data->next;				npdap->synergy_perf_data->next = p;			}			spin_unlock_irq(&npdap->synergy_perf_lock);		}	}	return err;}static voidsynergy_perf_set_freq(int freq){	int		cnode;	nodepda_t	*npdap;	for (cnode=0; cnode < numnodes; cnode++) {		if ((npdap = NODEPDA(cnode)) != NULL)			npdap->synergy_perf_freq = freq;	}}static voidsynergy_perf_set_enable(int enable){	int		cnode;	nodepda_t	*npdap;	for (cnode=0; cnode < numnodes; cnode++) {		if ((npdap = NODEPDA(cnode)) != NULL)			npdap->synergy_perf_enabled = enable;	}	printk("NOTICE: synergy perf counting %sabled on all nodes\n", enable ? "en" : "dis");}static intsynergy_perf_size(nodepda_t *npdap){	synergy_perf_t	*p;	int		n;	if (npdap->synergy_perf_enabled == 0) {		/* no stats to return */		return 0;	}	spin_lock_irq(&npdap->synergy_perf_lock);	for (n=0, p = npdap->synergy_perf_first; p;) {		n++;		p = p->next;		if (p == npdap->synergy_perf_first)			break;	}	spin_unlock_irq(&npdap->synergy_perf_lock);	/* bytes == n pairs of {event,counter} */	return n * 2 * sizeof(uint64_t);}static intsynergy_perf_ioctl(struct inode *inode, struct file *file,        unsigned int cmd, unsigned long arg){	int             cnode;	nodepda_t       *npdap;	synergy_perf_t	*p;	int		intarg;	int		fsb;	uint64_t	longarg;	uint64_t	*stats;	int		n;	devfs_handle_t	d;	arbitrary_info_t info;		if ((d = devfs_get_handle_from_inode(inode)) == NULL)		return -ENODEV;	info = hwgraph_fastinfo_get(d);	cnode = SYNERGY_PERF_INFO_CNODE(info);	fsb = SYNERGY_PERF_INFO_FSB(info);	npdap = NODEPDA(cnode);	switch (cmd) {	case SNDRV_GET_SYNERGY_VERSION:		/* return int, version of data structure for SNDRV_GET_SYNERGYINFO */		intarg = 1; /* version 1 */		if (copy_to_user((void *)arg, &intarg, sizeof(intarg)))		    return -EFAULT;		break;	case SNDRV_GET_INFOSIZE:		/* return int, sizeof buf needed for SYNERGY_PERF_GET_STATS */		intarg = synergy_perf_size(npdap);		if (copy_to_user((void *)arg, &intarg, sizeof(intarg)))		    return -EFAULT;		break;	case SNDRV_GET_SYNERGYINFO:		/* return array of event/value pairs, this node only */		if ((intarg = synergy_perf_size(npdap)) <= 0)			return -ENODATA;		if ((stats = (uint64_t *)kmalloc(intarg, GFP_KERNEL)) == NULL)			return -ENOMEM;		spin_lock_irq(&npdap->synergy_perf_lock);		for (n=0, p = npdap->synergy_perf_first; p;) {			stats[n++] = p->modesel;			if (p->intervals > 0)			    stats[n++] = p->counts[fsb] * p->total_intervals / p->intervals;			else			    stats[n++] = 0;			p = p->next;			if (p == npdap->synergy_perf_first)				break;		}		spin_unlock_irq(&npdap->synergy_perf_lock);		if (copy_to_user((void *)arg, stats, intarg)) {		    kfree(stats);		    return -EFAULT;		}		kfree(stats);		break;	case SNDRV_SYNERGY_APPEND:		/* reads 64bit event, append synergy perf event to all nodes  */		if (copy_from_user(&longarg, (void *)arg, sizeof(longarg)))		    return -EFAULT;		return synergy_perf_append(longarg);		break;	case SNDRV_GET_SYNERGY_STATUS:		/* return int, 1 if enabled else 0 */		intarg = npdap->synergy_perf_enabled;		if (copy_to_user((void *)arg, &intarg, sizeof(intarg)))		    return -EFAULT;		break;	case SNDRV_SYNERGY_ENABLE:		/* read int, if true enable counting else disable */		if (copy_from_user(&intarg, (void *)arg, sizeof(intarg)))		    return -EFAULT;		synergy_perf_set_enable(intarg);		break;	case SNDRV_SYNERGY_FREQ:		/* read int, set jiffies per update */ 		if (copy_from_user(&intarg, (void *)arg, sizeof(intarg)))		    return -EFAULT;		if (intarg < 0 || intarg >= HZ)			return -EINVAL;		synergy_perf_set_freq(intarg);		break;	default:		printk("Warning: invalid ioctl %d on synergy mon for cnode=%d fsb=%d\n", cmd, cnode, fsb);		return -EINVAL;	}	return(0);}struct file_operations synergy_mon_fops = {        ioctl:		synergy_perf_ioctl,};voidsynergy_perf_update(int cpu){	nasid_t		nasid;	cnodeid_t       cnode;	struct nodepda_s *npdap;	/*	 * synergy_perf_initialized is set by synergy_perf_init()	 * which is called last thing by sn_mp_setup(), i.e. well	 * after nodepda has been initialized.	 */	if (!synergy_perf_initialized)		return;	cnode = cpuid_to_cnodeid(cpu);	npdap = NODEPDA(cnode);	if (npdap == NULL || cnode < 0 || cnode >= numnodes)		/* this should not happen: still in early io init */		return;#if 0	/* use this to check nodepda initialization */	if (((uint64_t)npdap) & 0x7) {		printk("\nERROR on cpu %d : cnode=%d, npdap == %p, not aligned\n", cpu, cnode, npdap);		BUG();	}#endif	if (npdap->synergy_perf_enabled == 0 || npdap->synergy_perf_data == NULL) {		/* Not enabled, or no events to monitor */		return;	}	if (npdap->synergy_inactive_intervals++ % npdap->synergy_perf_freq != 0) {		/* don't multiplex on every timer interrupt */		return;	}	/*	 * Read registers for last interval and increment counters.	 * Hold the per-node synergy_perf_lock so concurrent readers get	 * consistent values.	 */	spin_lock_irq(&npdap->synergy_perf_lock);	nasid = cpuid_to_nasid(cpu);	npdap->synergy_active_intervals++;	npdap->synergy_perf_data->intervals++;	npdap->synergy_perf_data->total_intervals = npdap->synergy_active_intervals;	npdap->synergy_perf_data->counts[0] += 0xffffffffffUL &		REMOTE_SYNERGY_LOAD(nasid, 0, PERF_CNTR0_A);	npdap->synergy_perf_data->counts[1] += 0xffffffffffUL &		REMOTE_SYNERGY_LOAD(nasid, 1, PERF_CNTR0_B);	/* skip to next in circular list */	npdap->synergy_perf_data = npdap->synergy_perf_data->next;	spin_unlock_irq(&npdap->synergy_perf_lock);	/* set the counter 0 selection modes for both A and B */	REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTL0_A, npdap->synergy_perf_data->modesel);	REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTL0_B, npdap->synergy_perf_data->modesel);	/* and reset the counter registers to zero */	REMOTE_SYNERGY_STORE(nasid, 0, PERF_CNTR0_A, 0UL);	REMOTE_SYNERGY_STORE(nasid, 1, PERF_CNTR0_B, 0UL);}voidsynergy_perf_init(void){	printk("synergy_perf_init(), counting is initially disabled\n");	synergy_perf_initialized++;}

⌨️ 快捷键说明

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