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

📄 sn_hwperf.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
			return -EINVAL;		for (ordinal=0, p=objs; p != obj; p++) {			if (!SN_HWPERF_FOREIGN(p))				ordinal += p->ports;		}		for (pt = 0; pt < obj->ports; pt++) {			for (p = objs, i = 0; i < sn_hwperf_obj_cnt; i++, p++) {				if (ptdata[pt].conn_id == p->id) {					break;				}			}			seq_printf(s, "numalink %d %s-%d",			    ordinal+pt, obj->location, ptdata[pt].port);			if (i >= sn_hwperf_obj_cnt) {				/* no connection */				seq_puts(s, " local endpoint disconnected"					    ", protocol unknown\n");				continue;			}			if (obj->sn_hwp_this_part && p->sn_hwp_this_part)				/* both ends local to this partition */				seq_puts(s, " local");			else if (!obj->sn_hwp_this_part && !p->sn_hwp_this_part)				/* both ends of the link in foreign partiton */				seq_puts(s, " foreign");			else				/* link straddles a partition */				seq_puts(s, " shared");			/*			 * Unlikely, but strictly should query the LLP config			 * registers because an NL4R can be configured to run			 * NL3 protocol, even when not talking to an NL3 router.			 * Ditto for node-node.			 */			seq_printf(s, " endpoint %s-%d, protocol %s\n",				p->location, ptdata[pt].conn_port,				(SN_HWPERF_IS_NL3ROUTER(obj) ||				SN_HWPERF_IS_NL3ROUTER(p)) ?  "LLP3" : "LLP4");		}		vfree(ptdata);	}	return 0;}static void *sn_topology_start(struct seq_file *s, loff_t * pos){	struct sn_hwperf_object_info *objs = s->private;	if (*pos < sn_hwperf_obj_cnt)		return (void *)(objs + *pos);	return NULL;}static void *sn_topology_next(struct seq_file *s, void *v, loff_t * pos){	++*pos;	return sn_topology_start(s, pos);}static void sn_topology_stop(struct seq_file *m, void *v){	return;}/* * /proc/sgi_sn/sn_topology, read-only using seq_file */static struct seq_operations sn_topology_seq_ops = {	.start = sn_topology_start,	.next = sn_topology_next,	.stop = sn_topology_stop,	.show = sn_topology_show};struct sn_hwperf_op_info {	u64 op;	struct sn_hwperf_ioctl_args *a;	void *p;	int *v0;	int ret;};static void sn_hwperf_call_sal(void *info){	struct sn_hwperf_op_info *op_info = info;	int r;	r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op_info->op,		      op_info->a->arg, op_info->a->sz,		      (u64) op_info->p, 0, 0, op_info->v0);	op_info->ret = r;}static int sn_hwperf_op_cpu(struct sn_hwperf_op_info *op_info){	u32 cpu;	u32 use_ipi;	int r = 0;	cpumask_t save_allowed;		cpu = (op_info->a->arg & SN_HWPERF_ARG_CPU_MASK) >> 32;	use_ipi = op_info->a->arg & SN_HWPERF_ARG_USE_IPI_MASK;	op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK;	if (cpu != SN_HWPERF_ARG_ANY_CPU) {		if (cpu >= num_online_cpus() || !cpu_online(cpu)) {			r = -EINVAL;			goto out;		}	}	if (cpu == SN_HWPERF_ARG_ANY_CPU || cpu == get_cpu()) {		/* don't care, or already on correct cpu */		sn_hwperf_call_sal(op_info);	}	else {		if (use_ipi) {			/* use an interprocessor interrupt to call SAL */			smp_call_function_single(cpu, sn_hwperf_call_sal,				op_info, 1, 1);		}		else {			/* migrate the task before calling SAL */ 			save_allowed = current->cpus_allowed;			set_cpus_allowed(current, cpumask_of_cpu(cpu));			sn_hwperf_call_sal(op_info);			set_cpus_allowed(current, save_allowed);		}	}	r = op_info->ret;out:	return r;}/* map SAL hwperf error code to system error code */static int sn_hwperf_map_err(int hwperf_err){	int e;	switch(hwperf_err) {	case SN_HWPERF_OP_OK:		e = 0;		break;	case SN_HWPERF_OP_NOMEM:		e = -ENOMEM;		break;	case SN_HWPERF_OP_NO_PERM:		e = -EPERM;		break;	case SN_HWPERF_OP_IO_ERROR:		e = -EIO;		break;	case SN_HWPERF_OP_BUSY:		e = -EBUSY;		break;	case SN_HWPERF_OP_RECONFIGURE:		e = -EAGAIN;		break;	case SN_HWPERF_OP_INVAL:	default:		e = -EINVAL;		break;	}	return e;}/* * ioctl for "sn_hwperf" misc device */static intsn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg){	struct sn_hwperf_ioctl_args a;	struct cpuinfo_ia64 *cdata;	struct sn_hwperf_object_info *objs;	struct sn_hwperf_object_info *cpuobj;	struct sn_hwperf_op_info op_info;	void *p = NULL;	int nobj;	char slice;	int node;	int r;	int v0;	int i;	int j;	unlock_kernel();	/* only user requests are allowed here */	if ((op & SN_HWPERF_OP_MASK) < 10) {		r = -EINVAL;		goto error;	}	r = copy_from_user(&a, (const void __user *)arg,		sizeof(struct sn_hwperf_ioctl_args));	if (r != 0) {		r = -EFAULT;		goto error;	}	/*	 * Allocate memory to hold a kernel copy of the user buffer. The	 * buffer contents are either copied in or out (or both) of user	 * space depending on the flags encoded in the requested operation.	 */	if (a.ptr) {		p = vmalloc(a.sz);		if (!p) {			r = -ENOMEM;			goto error;		}	}	if (op & SN_HWPERF_OP_MEM_COPYIN) {		r = copy_from_user(p, (const void __user *)a.ptr, a.sz);		if (r != 0) {			r = -EFAULT;			goto error;		}	}	switch (op) {	case SN_HWPERF_GET_CPU_INFO:		if (a.sz == sizeof(u64)) {			/* special case to get size needed */			*(u64 *) p = (u64) num_online_cpus() *				sizeof(struct sn_hwperf_object_info);		} else		if (a.sz < num_online_cpus() * sizeof(struct sn_hwperf_object_info)) {			r = -ENOMEM;			goto error;		} else		if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {			memset(p, 0, a.sz);			for (i = 0; i < nobj; i++) {				int cpuobj_index = 0;				if (!SN_HWPERF_IS_NODE(objs + i))					continue;				node = sn_hwperf_obj_to_cnode(objs + i);				for_each_online_cpu(j) {					if (node != cpu_to_node(j))						continue;					cpuobj = (struct sn_hwperf_object_info *) p + cpuobj_index++;					slice = 'a' + cpuid_to_slice(j);					cdata = cpu_data(j);					cpuobj->id = j;					snprintf(cpuobj->name,						 sizeof(cpuobj->name),						 "CPU %luMHz %s",						 cdata->proc_freq / 1000000,						 cdata->vendor);					snprintf(cpuobj->location,						 sizeof(cpuobj->location),						 "%s%c", objs[i].location,						 slice);				}			}			vfree(objs);		}		break;	case SN_HWPERF_GET_NODE_NASID:		if (a.sz != sizeof(u64) ||		   (node = a.arg) < 0 || !node_possible(node)) {			r = -EINVAL;			goto error;		}		*(u64 *)p = (u64)cnodeid_to_nasid(node);		break;	case SN_HWPERF_GET_OBJ_NODE:		if (a.sz != sizeof(u64) || a.arg < 0) {			r = -EINVAL;			goto error;		}		if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {			if (a.arg >= nobj) {				r = -EINVAL;				vfree(objs);				goto error;			}			if (objs[(i = a.arg)].id != a.arg) {				for (i = 0; i < nobj; i++) {					if (objs[i].id == a.arg)						break;				}			}			if (i == nobj) {				r = -EINVAL;				vfree(objs);				goto error;			}			if (!SN_HWPERF_IS_NODE(objs + i) &&			    !SN_HWPERF_IS_IONODE(objs + i)) {			    	r = -ENOENT;				vfree(objs);				goto error;			}			*(u64 *)p = (u64)sn_hwperf_obj_to_cnode(objs + i);			vfree(objs);		}		break;	case SN_HWPERF_GET_MMRS:	case SN_HWPERF_SET_MMRS:	case SN_HWPERF_OBJECT_DISTANCE:		op_info.p = p;		op_info.a = &a;		op_info.v0 = &v0;		op_info.op = op;		r = sn_hwperf_op_cpu(&op_info);		if (r) {			r = sn_hwperf_map_err(r);			a.v0 = v0;			goto error;		}		break;	default:		/* all other ops are a direct SAL call */		r = ia64_sn_hwperf_op(sn_hwperf_master_nasid, op,			      a.arg, a.sz, (u64) p, 0, 0, &v0);		if (r) {			r = sn_hwperf_map_err(r);			goto error;		}		a.v0 = v0;		break;	}	if (op & SN_HWPERF_OP_MEM_COPYOUT) {		r = copy_to_user((void __user *)a.ptr, p, a.sz);		if (r != 0) {			r = -EFAULT;			goto error;		}	}error:	vfree(p);	lock_kernel();	return r;}static struct file_operations sn_hwperf_fops = {	.ioctl = sn_hwperf_ioctl,};static struct miscdevice sn_hwperf_dev = {	MISC_DYNAMIC_MINOR,	"sn_hwperf",	&sn_hwperf_fops};static int sn_hwperf_init(void){	u64 v;	int salr;	int e = 0;	/* single threaded, once-only initialization */	down(&sn_hwperf_init_mutex);	if (sn_hwperf_salheap) {		up(&sn_hwperf_init_mutex);		return e;	}	/*	 * The PROM code needs a fixed reference node. For convenience the	 * same node as the console I/O is used.	 */	sn_hwperf_master_nasid = (nasid_t) ia64_sn_get_console_nasid();	/*	 * Request the needed size and install the PROM scratch area.	 * The PROM keeps various tracking bits in this memory area.	 */	salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid,				 (u64) SN_HWPERF_GET_HEAPSIZE, 0,				 (u64) sizeof(u64), (u64) &v, 0, 0, NULL);	if (salr != SN_HWPERF_OP_OK) {		e = -EINVAL;		goto out;	}	if ((sn_hwperf_salheap = vmalloc(v)) == NULL) {		e = -ENOMEM;		goto out;	}	salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid,				 SN_HWPERF_INSTALL_HEAP, 0, v,				 (u64) sn_hwperf_salheap, 0, 0, NULL);	if (salr != SN_HWPERF_OP_OK) {		e = -EINVAL;		goto out;	}	salr = ia64_sn_hwperf_op(sn_hwperf_master_nasid,				 SN_HWPERF_OBJECT_COUNT, 0,				 sizeof(u64), (u64) &v, 0, 0, NULL);	if (salr != SN_HWPERF_OP_OK) {		e = -EINVAL;		goto out;	}	sn_hwperf_obj_cnt = (int)v;out:	if (e < 0 && sn_hwperf_salheap) {		vfree(sn_hwperf_salheap);		sn_hwperf_salheap = NULL;		sn_hwperf_obj_cnt = 0;	}	up(&sn_hwperf_init_mutex);	return e;}int sn_topology_open(struct inode *inode, struct file *file){	int e;	struct seq_file *seq;	struct sn_hwperf_object_info *objbuf;	int nobj;	if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) {		e = seq_open(file, &sn_topology_seq_ops);		seq = file->private_data;		seq->private = objbuf;	}	return e;}int sn_topology_release(struct inode *inode, struct file *file){	struct seq_file *seq = file->private_data;	vfree(seq->private);	return seq_release(inode, file);}int sn_hwperf_get_nearest_node(cnodeid_t node,	cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node){	int e;	int nobj;	struct sn_hwperf_object_info *objbuf;	if ((e = sn_hwperf_enum_objects(&nobj, &objbuf)) == 0) {		e = sn_hwperf_get_nearest_node_objdata(objbuf, nobj,			node, near_mem_node, near_cpu_node);		vfree(objbuf);	}	return e;}static int __devinit sn_hwperf_misc_register_init(void){	int e;	sn_hwperf_init();	/*	 * Register a dynamic misc device for hwperf ioctls. Platforms	 * supporting hotplug will create /dev/sn_hwperf, else user	 * can to look up the minor number in /proc/misc.	 */	if ((e = misc_register(&sn_hwperf_dev)) != 0) {		printk(KERN_ERR "sn_hwperf_misc_register_init: failed to "		"register misc device for \"%s\"\n", sn_hwperf_dev.name);	}	return e;}device_initcall(sn_hwperf_misc_register_init); /* after misc_init() */EXPORT_SYMBOL(sn_hwperf_get_nearest_node);

⌨️ 快捷键说明

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