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

📄 palinfo.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
};static intprocessor_info(char *page){	char *p = page;	const char **v = proc_features;	u64 avail=1, status=1, control=1;	int i;	s64 ret;	if ((ret=ia64_pal_proc_get_features(&avail, &status, &control)) != 0) return 0;	for(i=0; i < 64; i++, v++,avail >>=1, status >>=1, control >>=1) {		if ( ! *v ) continue;		p += sprintf(p, "%-40s : %s%s %s\n", *v,				avail & 0x1 ? "" : "NotImpl",				avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "",				avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): "");	}	return p - page;}static const char *bus_features[]={	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,	NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,	NULL,NULL,	"Request  Bus Parking",	"Bus Lock Mask",	"Enable Half Transfer",	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,	NULL, NULL, NULL, NULL,	"Enable Cache Line Repl. Exclusive",	"Enable Cache Line Repl. Shared",	"Disable Transaction Queuing",	"Disable Reponse Error Checking",	"Disable Bus Error Checking",	"Disable Bus Requester Internal Error Signalling",	"Disable Bus Requester Error Signalling",	"Disable Bus Initialization Event Checking",	"Disable Bus Initialization Event Signalling",	"Disable Bus Address Error Checking",	"Disable Bus Address Error Signalling",	"Disable Bus Data Error Checking"};static intbus_info(char *page){	char *p = page;	const char **v = bus_features;	pal_bus_features_u_t av, st, ct;	u64 avail, status, control;	int i;	s64 ret;	if ((ret=ia64_pal_bus_get_features(&av, &st, &ct)) != 0) return 0;	avail   = av.pal_bus_features_val;	status  = st.pal_bus_features_val;	control = ct.pal_bus_features_val;	for(i=0; i < 64; i++, v++, avail >>=1, status >>=1, control >>=1) {		if ( ! *v ) continue;		p += sprintf(p, "%-48s : %s%s %s\n", *v,				avail & 0x1 ? "" : "NotImpl",				avail & 0x1 ? (status  & 0x1 ? "On" : "Off"): "",				avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): "");	}	return p - page;}static intversion_info(char *page){	pal_version_u_t min_ver, cur_ver;	char *p = page;	/* The PAL_VERSION call is advertised as being able to support	 * both physical and virtual mode calls. This seems to be a documentation	 * bug rather than firmware bug. In fact, it does only support physical mode.	 * So now the code reflects this fact and the pal_version() has been updated	 * accordingly.	 */	if (ia64_pal_version(&min_ver, &cur_ver) != 0) return 0;	p += sprintf(p, "PAL_vendor : 0x%02x (min=0x%02x)\n" \			"PAL_A      : %x.%x.%x (min=%x.%x.%x)\n" \			"PAL_B      : %x.%x.%x (min=%x.%x.%x)\n",			cur_ver.pal_version_s.pv_pal_vendor,			min_ver.pal_version_s.pv_pal_vendor,			cur_ver.pal_version_s.pv_pal_a_model>>4,			cur_ver.pal_version_s.pv_pal_a_model&0xf,			cur_ver.pal_version_s.pv_pal_a_rev,			min_ver.pal_version_s.pv_pal_a_model>>4,			min_ver.pal_version_s.pv_pal_a_model&0xf,			min_ver.pal_version_s.pv_pal_a_rev,			cur_ver.pal_version_s.pv_pal_b_model>>4,			cur_ver.pal_version_s.pv_pal_b_model&0xf,			cur_ver.pal_version_s.pv_pal_b_rev,			min_ver.pal_version_s.pv_pal_b_model>>4,			min_ver.pal_version_s.pv_pal_b_model&0xf,			min_ver.pal_version_s.pv_pal_b_rev);	return p - page;}static intperfmon_info(char *page){	char *p = page;	u64 pm_buffer[16];	pal_perf_mon_info_u_t pm_info;	if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0;	p += sprintf(p, "PMC/PMD pairs                 : %d\n" \			"Counter width                 : %d bits\n" \			"Cycle event number            : %d\n" \			"Retired event number          : %d\n" \			"Implemented PMC               : ",			pm_info.pal_perf_mon_info_s.generic,			pm_info.pal_perf_mon_info_s.width,			pm_info.pal_perf_mon_info_s.cycles,			pm_info.pal_perf_mon_info_s.retired);	p = bitregister_process(p, pm_buffer, 256);	p += sprintf(p, "\nImplemented PMD               : ");	p = bitregister_process(p, pm_buffer+4, 256);	p += sprintf(p, "\nCycles count capable          : ");	p = bitregister_process(p, pm_buffer+8, 256);	p += sprintf(p, "\nRetired bundles count capable : ");#ifdef CONFIG_ITANIUM	/*	 * PAL_PERF_MON_INFO reports that only PMC4 can be used to count CPU_CYCLES	 * which is wrong, both PMC4 and PMD5 support it.	 */	if (pm_buffer[12] == 0x10) pm_buffer[12]=0x30;#endif	p = bitregister_process(p, pm_buffer+12, 256);	p += sprintf(p, "\n");	return p - page;}static intfrequency_info(char *page){	char *p = page;	struct pal_freq_ratio proc, itc, bus;	u64 base;	if (ia64_pal_freq_base(&base) == -1)		p += sprintf(p, "Output clock            : not implemented\n");	else		p += sprintf(p, "Output clock            : %ld ticks/s\n", base);	if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0;	p += sprintf(p, "Processor/Clock ratio   : %ld/%ld\n" \			"Bus/Clock ratio         : %ld/%ld\n" \			"ITC/Clock ratio         : %ld/%ld\n",			proc.num, proc.den,			bus.num, bus.den,			itc.num, itc.den);	return p - page;}static inttr_info(char *page){	char *p = page;	s64 status;	pal_tr_valid_u_t tr_valid;	u64 tr_buffer[4];	pal_vm_info_1_u_t vm_info_1;	pal_vm_info_2_u_t vm_info_2;	int i, j;	u64 max[3], pgm;	struct ifa_reg {		u64 valid:1;		u64 ig:11;		u64 vpn:52;	} *ifa_reg;	struct itir_reg {		u64 rv1:2;		u64 ps:6;		u64 key:24;		u64 rv2:32;	} *itir_reg;	struct gr_reg {		u64 p:1;		u64 rv1:1;		u64 ma:3;		u64 a:1;		u64 d:1;		u64 pl:2;		u64 ar:3;		u64 ppn:38;		u64 rv2:2;		u64 ed:1;		u64 ig:11;	} *gr_reg;	struct rid_reg {		u64 ig1:1;		u64 rv1:1;		u64 ig2:6;		u64 rid:24;		u64 rv2:32;	} *rid_reg;	if ((status=ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {		printk("ia64_pal_vm_summary=%ld\n", status);		return 0;	}	max[0] = vm_info_1.pal_vm_info_1_s.max_itr_entry+1;	max[1] = vm_info_1.pal_vm_info_1_s.max_dtr_entry+1;	for (i=0; i < 2; i++ ) {		for (j=0; j < max[i]; j++) {		status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid);		if (status != 0) {			printk(__FUNCTION__ " pal call failed on tr[%d:%d]=%ld\n", i, j, status);			continue;		}		ifa_reg  = (struct ifa_reg *)&tr_buffer[2];		if (ifa_reg->valid == 0) continue;		gr_reg   = (struct gr_reg *)tr_buffer;		itir_reg = (struct itir_reg *)&tr_buffer[1];		rid_reg  = (struct rid_reg *)&tr_buffer[3];		pgm	 = -1 << (itir_reg->ps - 12);		p += sprintf(p, "%cTR%d: av=%d pv=%d dv=%d mv=%d\n" \				"\tppn  : 0x%lx\n" \				"\tvpn  : 0x%lx\n" \				"\tps   : ",				"ID"[i],				j,				tr_valid.pal_tr_valid_s.access_rights_valid,				tr_valid.pal_tr_valid_s.priv_level_valid,				tr_valid.pal_tr_valid_s.dirty_bit_valid,				tr_valid.pal_tr_valid_s.mem_attr_valid,				(gr_reg->ppn & pgm)<< 12,				(ifa_reg->vpn & pgm)<< 12);		p = bitvector_process(p, 1<< itir_reg->ps);		p += sprintf(p, "\n\tpl   : %d\n" \				"\tar   : %d\n" \				"\trid  : %x\n" \				"\tp    : %d\n" \				"\tma   : %d\n" \				"\td    : %d\n",				gr_reg->pl,				gr_reg->ar,				rid_reg->rid,				gr_reg->p,				gr_reg->ma,				gr_reg->d);		}	}	return p - page;}/* * List {name,function} pairs for every entry in /proc/palinfo/cpu* */static palinfo_entry_t palinfo_entries[]={	{ "version_info",	version_info, },	{ "vm_info",		vm_info, },	{ "cache_info",		cache_info, },	{ "power_info",		power_info, },	{ "register_info",	register_info, },	{ "processor_info",	processor_info, },	{ "perfmon_info",	perfmon_info, },	{ "frequency_info",	frequency_info, },	{ "bus_info",		bus_info },	{ "tr_info",		tr_info, }};#define NR_PALINFO_ENTRIES	(sizeof(palinfo_entries)/sizeof(palinfo_entry_t))/* * this array is used to keep track of the proc entries we create. This is * required in the module mode when we need to remove all entries. The procfs code * does not do recursion of deletion * * Notes: *	- first +1 accounts for the cpuN entry *	- second +1 account for toplevel palinfo * */#define NR_PALINFO_PROC_ENTRIES	(NR_CPUS*(NR_PALINFO_ENTRIES+1)+1)static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES];/* * This data structure is used to pass which cpu,function is being requested * It must fit in a 64bit quantity to be passed to the proc callback routine * * In SMP mode, when we get a request for another CPU, we must call that * other CPU using IPI and wait for the result before returning. */typedef union {	u64 value;	struct {		unsigned	req_cpu: 32;	/* for which CPU this info is */		unsigned	func_id: 32;	/* which function is requested */	} pal_func_cpu;} pal_func_cpu_u_t;#define req_cpu	pal_func_cpu.req_cpu#define func_id pal_func_cpu.func_id#ifdef CONFIG_SMP/* * used to hold information about final function to call */typedef struct {	palinfo_func_t	func;	/* pointer to function to call */	char		*page;	/* buffer to store results */	int		ret;	/* return value from call */} palinfo_smp_data_t;/* * this function does the actual final call and he called * from the smp code, i.e., this is the palinfo callback routine */static voidpalinfo_smp_call(void *info){	palinfo_smp_data_t *data = (palinfo_smp_data_t *)info;	/* printk(__FUNCTION__" called on CPU %d\n", smp_processor_id());*/	if (data == NULL) {		printk(KERN_ERR __FUNCTION__" data pointer is NULL\n");		data->ret = 0; /* no output */		return;	}	/* does this actual call */	data->ret = (*data->func)(data->page);}/* * function called to trigger the IPI, we need to access a remote CPU * Return: *	0 : error or nothing to output *	otherwise how many bytes in the "page" buffer were written */staticint palinfo_handle_smp(pal_func_cpu_u_t *f, char *page){	palinfo_smp_data_t ptr;	int ret;	ptr.func = palinfo_entries[f->func_id].proc_read;	ptr.page = page;	ptr.ret  = 0; /* just in case */	/*printk(__FUNCTION__" calling CPU %d from CPU %d for function %d\n", f->req_cpu,smp_processor_id(), f->func_id);*/	/* will send IPI to other CPU and wait for completion of remote call */	if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 0, 1))) {		printk(__FUNCTION__" remote CPU call from %d to %d on function %d: error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret);		return 0;	}	return ptr.ret;}#else /* ! CONFIG_SMP */staticint palinfo_handle_smp(pal_func_cpu_u_t *f, char *page){	printk(__FUNCTION__" should not be called with non SMP kernel\n");	return 0;}#endif /* CONFIG_SMP *//* * Entry point routine: all calls go through this function */static intpalinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data){	int len=0;	pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&data;	MOD_INC_USE_COUNT;	/*	 * in SMP mode, we may need to call another CPU to get correct	 * information. PAL, by definition, is processor specific	 */	if (f->req_cpu == smp_processor_id())		len = (*palinfo_entries[f->func_id].proc_read)(page);	else		len = palinfo_handle_smp(f, page);	if (len <= off+count) *eof = 1;	*start = page + off;	len   -= off;	if (len>count) len = count;	if (len<0) len = 0;	MOD_DEC_USE_COUNT;	return len;}static int __initpalinfo_init(void){#	define CPUSTR	"cpu%d"	pal_func_cpu_u_t f;	struct proc_dir_entry **pdir = palinfo_proc_entries;	struct proc_dir_entry *palinfo_dir, *cpu_dir;	int i, j;	char cpustr[sizeof(CPUSTR)];	printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);	palinfo_dir = proc_mkdir("pal", NULL);	/*	 * we keep track of created entries in a depth-first order for	 * cleanup purposes. Each entry is stored into palinfo_proc_entries	 */	for (i=0; i < NR_CPUS; i++) {		if (!cpu_is_online(i)) continue;		sprintf(cpustr,CPUSTR, i);		cpu_dir = proc_mkdir(cpustr, palinfo_dir);		f.req_cpu = i;		for (j=0; j < NR_PALINFO_ENTRIES; j++) {			f.func_id = j;			*pdir++ = create_proc_read_entry (palinfo_entries[j].name, 0, cpu_dir,						palinfo_read_entry, (void *)f.value);		}		*pdir++ = cpu_dir;	}	*pdir = palinfo_dir;	return 0;}static void __exitpalinfo_exit(void){	int i = 0;	/* remove all nodes: depth first pass. Could optimize this  */	for (i=0; i< NR_PALINFO_PROC_ENTRIES ; i++) {		if (palinfo_proc_entries[i])			remove_proc_entry (palinfo_proc_entries[i]->name, NULL);	}}module_init(palinfo_init);module_exit(palinfo_exit);

⌨️ 快捷键说明

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