sn_hwperf.c

来自「h内核」· C语言 代码 · 共 691 行 · 第 1/2 页

C
691
字号
/*  * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2004-2005 Silicon Graphics, Inc. All rights reserved. * * SGI Altix topology and hardware performance monitoring API. * Mark Goodwin <markgw@sgi.com>.  * * Creates /proc/sgi_sn/sn_topology (read-only) to export * info about Altix nodes, routers, CPUs and NumaLink * interconnection/topology. * * Also creates a dynamic misc device named "sn_hwperf" * that supports an ioctl interface to call down into SAL * to discover hw objects, topology and to read/write * memory mapped registers, e.g. for performance monitoring. * The "sn_hwperf" device is registered only after the procfs * file is first opened, i.e. only if/when it's needed.  * * This API is used by SGI Performance Co-Pilot and other * tools, see http://oss.sgi.com/projects/pcp */#include <linux/fs.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/seq_file.h>#include <linux/miscdevice.h>#include <linux/cpumask.h>#include <linux/smp_lock.h>#include <linux/nodemask.h>#include <asm/processor.h>#include <asm/topology.h>#include <asm/smp.h>#include <asm/semaphore.h>#include <asm/segment.h>#include <asm/uaccess.h>#include <asm/sal.h>#include <asm/sn/io.h>#include <asm/sn/sn_sal.h>#include <asm/sn/module.h>#include <asm/sn/geo.h>#include <asm/sn/sn2/sn_hwperf.h>static void *sn_hwperf_salheap = NULL;static int sn_hwperf_obj_cnt = 0;static nasid_t sn_hwperf_master_nasid = INVALID_NASID;static int sn_hwperf_init(void);static DECLARE_MUTEX(sn_hwperf_init_mutex);static int sn_hwperf_enum_objects(int *nobj, struct sn_hwperf_object_info **ret){	int e;	u64 sz;	struct sn_hwperf_object_info *objbuf = NULL;	if ((e = sn_hwperf_init()) < 0) {		printk("sn_hwperf_init failed: err %d\n", e);		goto out;	}	sz = sn_hwperf_obj_cnt * sizeof(struct sn_hwperf_object_info);	if ((objbuf = (struct sn_hwperf_object_info *) vmalloc(sz)) == NULL) {		printk("sn_hwperf_enum_objects: vmalloc(%d) failed\n", (int)sz);		e = -ENOMEM;		goto out;	}	e = ia64_sn_hwperf_op(sn_hwperf_master_nasid, SN_HWPERF_ENUM_OBJECTS,		0, sz, (u64) objbuf, 0, 0, NULL);	if (e != SN_HWPERF_OP_OK) {		e = -EINVAL;		vfree(objbuf);	}out:	*nobj = sn_hwperf_obj_cnt;	*ret = objbuf;	return e;}static int sn_hwperf_geoid_to_cnode(char *location){	int cnode;	geoid_t geoid;	moduleid_t module_id;	char type;	int rack, slot, slab;	int this_rack, this_slot, this_slab;	if (sscanf(location, "%03d%c%02d#%d", &rack, &type, &slot, &slab) != 4)		return -1;	for (cnode = 0; cnode < numionodes; cnode++) {		geoid = cnodeid_get_geoid(cnode);		module_id = geo_module(geoid);		this_rack = MODULE_GET_RACK(module_id);		this_slot = MODULE_GET_BPOS(module_id);		this_slab = geo_slab(geoid);		if (rack == this_rack && slot == this_slot && slab == this_slab)			break;	}	return cnode < numionodes ? cnode : -1;}static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj){	if (!obj->sn_hwp_this_part)		return -1;	return sn_hwperf_geoid_to_cnode(obj->location);}static int sn_hwperf_generic_ordinal(struct sn_hwperf_object_info *obj,				struct sn_hwperf_object_info *objs){	int ordinal;	struct sn_hwperf_object_info *p;	for (ordinal=0, p=objs; p != obj; p++) {		if (SN_HWPERF_FOREIGN(p))			continue;		if (SN_HWPERF_SAME_OBJTYPE(p, obj))			ordinal++;	}	return ordinal;}static const char *slabname_node =	"node"; /* SHub asic */static const char *slabname_ionode =	"ionode"; /* TIO asic */static const char *slabname_router =	"router"; /* NL3R or NL4R */static const char *slabname_other =	"other"; /* unknown asic */static const char *sn_hwperf_get_slabname(struct sn_hwperf_object_info *obj,			struct sn_hwperf_object_info *objs, int *ordinal){	int isnode;	const char *slabname = slabname_other;	if ((isnode = SN_HWPERF_IS_NODE(obj)) || SN_HWPERF_IS_IONODE(obj)) {	    	slabname = isnode ? slabname_node : slabname_ionode;		*ordinal = sn_hwperf_obj_to_cnode(obj);	}	else {		*ordinal = sn_hwperf_generic_ordinal(obj, objs);		if (SN_HWPERF_IS_ROUTER(obj))			slabname = slabname_router;	}	return slabname;}static int sn_topology_show(struct seq_file *s, void *d){	int sz;	int pt;	int e;	int i;	int j;	const char *slabname;	int ordinal;	cpumask_t cpumask;	char slice;	struct cpuinfo_ia64 *c;	struct sn_hwperf_port_info *ptdata;	struct sn_hwperf_object_info *p;	struct sn_hwperf_object_info *obj = d;	/* this object */	struct sn_hwperf_object_info *objs = s->private; /* all objects */	if (obj == objs) {		seq_printf(s, "# sn_topology version 1\n");		seq_printf(s, "# objtype ordinal location partition"			" [attribute value [, ...]]\n");	}	if (SN_HWPERF_FOREIGN(obj)) {		/* private in another partition: not interesting */		return 0;	}	for (i = 0; obj->name[i]; i++) {		if (obj->name[i] == ' ')			obj->name[i] = '_';	}	slabname = sn_hwperf_get_slabname(obj, objs, &ordinal);	seq_printf(s, "%s %d %s %s asic %s", slabname, ordinal, obj->location,		obj->sn_hwp_this_part ? "local" : "shared", obj->name);	if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))		seq_putc(s, '\n');	else {		seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal));		for (i=0; i < numionodes; i++) {			seq_printf(s, i ? ":%d" : ", dist %d",				node_distance(ordinal, i));		}		seq_putc(s, '\n');		/*		 * CPUs on this node, if any		 */		cpumask = node_to_cpumask(ordinal);		for_each_online_cpu(i) {			if (cpu_isset(i, cpumask)) {				slice = 'a' + cpuid_to_slice(i);				c = cpu_data(i);				seq_printf(s, "cpu %d %s%c local"					" freq %luMHz, arch ia64",					i, obj->location, slice,					c->proc_freq / 1000000);				for_each_online_cpu(j) {					seq_printf(s, j ? ":%d" : ", dist %d",						node_distance(						    cpuid_to_cnodeid(i),						    cpuid_to_cnodeid(j)));				}				seq_putc(s, '\n');			}		}	}	if (obj->ports) {		/*		 * numalink ports		 */		sz = obj->ports * sizeof(struct sn_hwperf_port_info);		if ((ptdata = vmalloc(sz)) == NULL)			return -ENOMEM;		e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,				      SN_HWPERF_ENUM_PORTS, obj->id, sz,				      (u64) ptdata, 0, 0, NULL);		if (e != SN_HWPERF_OP_OK)			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) {

⌨️ 快捷键说明

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