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

📄 sn_hwperf.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * 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-2006 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/utsname.h>#include <linux/cpumask.h>#include <linux/smp_lock.h>#include <linux/nodemask.h>#include <linux/smp.h>#include <asm/processor.h>#include <asm/topology.h>#include <asm/semaphore.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>#include <asm/sn/addrs.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);#define cnode_possible(n)	((n) < num_cnodes)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(KERN_ERR "sn_hwperf_init failed: err %d\n", e);		goto out;	}	sz = sn_hwperf_obj_cnt * sizeof(struct sn_hwperf_object_info);	objbuf = vmalloc(sz);	if (objbuf == 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_location_to_bpos(char *location,	int *rack, int *bay, int *slot, int *slab){	char type;	/* first scan for an old style geoid string */	if (sscanf(location, "%03d%c%02d#%d",		rack, &type, bay, slab) == 4)		*slot = 0; 	else /* scan for a new bladed geoid string */	if (sscanf(location, "%03d%c%02d^%02d#%d",		rack, &type, bay, slot, slab) != 5)		return -1; 	/* success */	return 0;}static int sn_hwperf_geoid_to_cnode(char *location){	int cnode;	geoid_t geoid;	moduleid_t module_id;	int rack, bay, slot, slab;	int this_rack, this_bay, this_slot, this_slab;	if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab))		return -1;	/*	 * FIXME: replace with cleaner for_each_XXX macro which addresses	 * both compute and IO nodes once ACPI3.0 is available.	 */	for (cnode = 0; cnode < num_cnodes; cnode++) {		geoid = cnodeid_get_geoid(cnode);		module_id = geo_module(geoid);		this_rack = MODULE_GET_RACK(module_id);		this_bay = MODULE_GET_BPOS(module_id);		this_slot = geo_slot(geoid);		this_slab = geo_slab(geoid);		if (rack == this_rack && bay == this_bay &&			slot == this_slot && slab == this_slab) {			break;		}	}	return cnode_possible(cnode) ? cnode : -1;}static int sn_hwperf_obj_to_cnode(struct sn_hwperf_object_info * obj){	if (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj))		BUG();	if (SN_HWPERF_FOREIGN(obj))		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 void print_pci_topology(struct seq_file *s){	char *p;	size_t sz;	int e;	for (sz = PAGE_SIZE; sz < 16 * PAGE_SIZE; sz += PAGE_SIZE) {		if (!(p = kmalloc(sz, GFP_KERNEL)))			break;		e = ia64_sn_ioif_get_pci_topology(__pa(p), sz);		if (e == SALRET_OK)			seq_puts(s, p);		kfree(p);		if (e == SALRET_OK || e == SALRET_NOT_IMPLEMENTED)			break;	}}static inline int sn_hwperf_has_cpus(cnodeid_t node){	return node < MAX_NUMNODES && node_online(node) && nr_cpus_node(node);}static inline int sn_hwperf_has_mem(cnodeid_t node){	return node < MAX_NUMNODES && node_online(node) && NODE_DATA(node)->node_present_pages;}static struct sn_hwperf_object_info *sn_hwperf_findobj_id(struct sn_hwperf_object_info *objbuf,	int nobj, int id){	int i;	struct sn_hwperf_object_info *p = objbuf;	for (i=0; i < nobj; i++, p++) {		if (p->id == id)			return p;	}	return NULL;}static int sn_hwperf_get_nearest_node_objdata(struct sn_hwperf_object_info *objbuf,	int nobj, cnodeid_t node, cnodeid_t *near_mem_node, cnodeid_t *near_cpu_node){	int e;	struct sn_hwperf_object_info *nodeobj = NULL;	struct sn_hwperf_object_info *op;	struct sn_hwperf_object_info *dest;	struct sn_hwperf_object_info *router;	struct sn_hwperf_port_info ptdata[16];	int sz, i, j;	cnodeid_t c;	int found_mem = 0;	int found_cpu = 0;	if (!cnode_possible(node))		return -EINVAL;	if (sn_hwperf_has_cpus(node)) {		if (near_cpu_node)			*near_cpu_node = node;		found_cpu++;	}	if (sn_hwperf_has_mem(node)) {		if (near_mem_node)			*near_mem_node = node;		found_mem++;	}	if (found_cpu && found_mem)		return 0; /* trivially successful */	/* find the argument node object */	for (i=0, op=objbuf; i < nobj; i++, op++) {		if (!SN_HWPERF_IS_NODE(op) && !SN_HWPERF_IS_IONODE(op))			continue;		if (node == sn_hwperf_obj_to_cnode(op)) {			nodeobj = op;			break;		}	}	if (!nodeobj) {		e = -ENOENT;		goto err;	}	/* get it's interconnect topology */	sz = op->ports * sizeof(struct sn_hwperf_port_info);	if (sz > sizeof(ptdata))		BUG();	e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,			      SN_HWPERF_ENUM_PORTS, nodeobj->id, sz,			      (u64)&ptdata, 0, 0, NULL);	if (e != SN_HWPERF_OP_OK) {		e = -EINVAL;		goto err;	}	/* find nearest node with cpus and nearest memory */	for (router=NULL, j=0; j < op->ports; j++) {		dest = sn_hwperf_findobj_id(objbuf, nobj, ptdata[j].conn_id);		if (dest && SN_HWPERF_IS_ROUTER(dest))			router = dest;		if (!dest || SN_HWPERF_FOREIGN(dest) ||		    !SN_HWPERF_IS_NODE(dest) || SN_HWPERF_IS_IONODE(dest)) {			continue;		}		c = sn_hwperf_obj_to_cnode(dest);		if (!found_cpu && sn_hwperf_has_cpus(c)) {			if (near_cpu_node)				*near_cpu_node = c;			found_cpu++;		}		if (!found_mem && sn_hwperf_has_mem(c)) {			if (near_mem_node)				*near_mem_node = c;			found_mem++;		}	}	if (router && (!found_cpu || !found_mem)) {		/* search for a node connected to the same router */		sz = router->ports * sizeof(struct sn_hwperf_port_info);		if (sz > sizeof(ptdata))			BUG();		e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,				      SN_HWPERF_ENUM_PORTS, router->id, sz,				      (u64)&ptdata, 0, 0, NULL);		if (e != SN_HWPERF_OP_OK) {			e = -EINVAL;			goto err;		}		for (j=0; j < router->ports; j++) {			dest = sn_hwperf_findobj_id(objbuf, nobj,				ptdata[j].conn_id);			if (!dest || dest->id == node ||			    SN_HWPERF_FOREIGN(dest) ||			    !SN_HWPERF_IS_NODE(dest) ||			    SN_HWPERF_IS_IONODE(dest)) {				continue;			}			c = sn_hwperf_obj_to_cnode(dest);			if (!found_cpu && sn_hwperf_has_cpus(c)) {				if (near_cpu_node)					*near_cpu_node = c;				found_cpu++;			}			if (!found_mem && sn_hwperf_has_mem(c)) {				if (near_mem_node)					*near_mem_node = c;				found_mem++;			}			if (found_cpu && found_mem)				break;		}	}	if (!found_cpu || !found_mem) {		/* resort to _any_ node with CPUs and memory */		for (i=0, op=objbuf; i < nobj; i++, op++) {			if (SN_HWPERF_FOREIGN(op) ||			    SN_HWPERF_IS_IONODE(op) ||			    !SN_HWPERF_IS_NODE(op)) {				continue;			}			c = sn_hwperf_obj_to_cnode(op);			if (!found_cpu && sn_hwperf_has_cpus(c)) {				if (near_cpu_node)					*near_cpu_node = c;				found_cpu++;			}			if (!found_mem && sn_hwperf_has_mem(c)) {				if (near_mem_node)					*near_mem_node = c;				found_mem++;			}			if (found_cpu && found_mem)				break;		}	}	if (!found_cpu || !found_mem)		e = -ENODATA;err:	return e;}static int sn_topology_show(struct seq_file *s, void *d){	int sz;	int pt;	int e = 0;	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 */	u8 shubtype;	u8 system_size;	u8 sharing_size;	u8 partid;	u8 coher;	u8 nasid_shift;	u8 region_size;	u16 nasid_mask;	int nasid_msb;	if (obj == objs) {		seq_printf(s, "# sn_topology version 2\n");		seq_printf(s, "# objtype ordinal location partition"			" [attribute value [, ...]]\n");		if (ia64_sn_get_sn_info(0,			&shubtype, &nasid_mask, &nasid_shift, &system_size,			&sharing_size, &partid, &coher, &region_size))			BUG();		for (nasid_msb=63; nasid_msb > 0; nasid_msb--) {			if (((u64)nasid_mask << nasid_shift) & (1ULL << nasid_msb))				break;		}		seq_printf(s, "partition %u %s local "			"shubtype %s, "			"nasid_mask 0x%016lx, "			"nasid_bits %d:%d, "			"system_size %d, "			"sharing_size %d, "			"coherency_domain %d, "			"region_size %d\n",			partid, utsname()->nodename,			shubtype ? "shub2" : "shub1", 			(u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift,			system_size, sharing_size, coher, region_size);		print_pci_topology(s);	}	if (SN_HWPERF_FOREIGN(obj)) {		/* private in another partition: not interesting */		return 0;	}	for (i = 0; i < SN_HWPERF_MAXSTRING && 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 (ordinal < 0 || (!SN_HWPERF_IS_NODE(obj) && !SN_HWPERF_IS_IONODE(obj)))		seq_putc(s, '\n');	else {		cnodeid_t near_mem = -1;		cnodeid_t near_cpu = -1;		seq_printf(s, ", nasid 0x%x", cnodeid_to_nasid(ordinal));		if (sn_hwperf_get_nearest_node_objdata(objs, sn_hwperf_obj_cnt,			ordinal, &near_mem, &near_cpu) == 0) {			seq_printf(s, ", near_mem_nodeid %d, near_cpu_nodeid %d",				near_mem, near_cpu);		}		if (!SN_HWPERF_IS_IONODE(obj)) {			for_each_online_node(i) {				seq_printf(s, i ? ":%d" : ", dist %d",					node_distance(ordinal, i));			}		}		seq_putc(s, '\n');		/*		 * CPUs on this node, if any		 */		if (!SN_HWPERF_IS_IONODE(obj)) {			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(						    	cpu_to_node(i),						    	cpu_to_node(j)));					}					seq_putc(s, '\n');				}			}		}	}	if (obj->ports) {		/*		 * numalink ports		 */		sz = obj->ports * sizeof(struct sn_hwperf_port_info);		if ((ptdata = kmalloc(sz, GFP_KERNEL)) == NULL)			return -ENOMEM;		e = ia64_sn_hwperf_op(sn_hwperf_master_nasid,

⌨️ 快捷键说明

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