File: /usr/src/linux/arch/ia64/kernel/palinfo.c

1     /*
2      * palinfo.c
3      *
4      * Prints processor specific information reported by PAL.
5      * This code is based on specification of PAL as of the
6      * Intel IA-64 Architecture Software Developer's Manual v1.0.
7      *
8      *
9      * Copyright (C) 2000 Hewlett-Packard Co
10      * Copyright (C) 2000 Stephane Eranian <eranian@hpl.hp.com>
11      *
12      * 05/26/2000	S.Eranian	initial release
13      * 08/21/2000	S.Eranian	updated to July 2000 PAL specs
14      * 02/05/2001   S.Eranian	fixed module support
15      */
16     #include <linux/config.h>
17     #include <linux/types.h>
18     #include <linux/errno.h>
19     #include <linux/init.h>
20     #include <linux/proc_fs.h>
21     #include <linux/mm.h>
22     #include <linux/module.h>
23     
24     #include <asm/pal.h>
25     #include <asm/sal.h>
26     #include <asm/efi.h>
27     #include <asm/page.h>
28     #include <asm/processor.h>
29     #ifdef CONFIG_SMP
30     #include <linux/smp.h>
31     #endif
32     
33     MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
34     MODULE_DESCRIPTION("/proc interface to IA-64 PAL");
35     
36     #define PALINFO_VERSION "0.4"
37     
38     #ifdef CONFIG_SMP
39     #define cpu_is_online(i) (cpu_online_map & (1UL << i))
40     #else
41     #define cpu_is_online(i)	1
42     #endif
43     
44     typedef int (*palinfo_func_t)(char*);
45     
46     typedef struct {
47     	const char		*name;		/* name of the proc entry */
48     	palinfo_func_t		proc_read;	/* function to call for reading */
49     	struct proc_dir_entry	*entry;		/* registered entry (removal) */
50     } palinfo_entry_t;
51     
52     
53     /*
54      *  A bunch of string array to get pretty printing
55      */
56     
57     static char *cache_types[] = {
58     	"",			/* not used */
59     	"Instruction",
60     	"Data",
61     	"Data/Instruction"	/* unified */
62     };
63     
64     static const char *cache_mattrib[]={
65     	"WriteThrough",
66     	"WriteBack",
67     	"",		/* reserved */
68     	""		/* reserved */
69     };
70     
71     static const char *cache_st_hints[]={
72     	"Temporal, level 1",
73     	"Reserved",
74     	"Reserved",
75     	"Non-temporal, all levels",
76     	"Reserved",
77     	"Reserved",
78     	"Reserved",
79     	"Reserved"
80     };
81     
82     static const char *cache_ld_hints[]={
83     	"Temporal, level 1",
84     	"Non-temporal, level 1",
85     	"Reserved",
86     	"Non-temporal, all levels",
87     	"Reserved",
88     	"Reserved",
89     	"Reserved",
90     	"Reserved"
91     };
92     
93     static const char *rse_hints[]={
94     	"enforced lazy",
95     	"eager stores",
96     	"eager loads",
97     	"eager loads and stores"
98     };
99     
100     #define RSE_HINTS_COUNT (sizeof(rse_hints)/sizeof(const char *))
101     
102     /*
103      * The current revision of the Volume 2 (July 2000) of
104      * IA-64 Architecture Software Developer's Manual is wrong.
105      * Table 4-10 has invalid information concerning the ma field:
106      * Correct table is:
107      *      bit 0 - 001 - UC
108      *      bit 4 - 100 - UC
109      *      bit 5 - 101 - UCE
110      *      bit 6 - 110 - WC
111      *      bit 7 - 111 - NatPage
112      */
113     static const char *mem_attrib[]={
114     	"Write Back (WB)",		/* 000 */
115     	"Uncacheable (UC)",		/* 001 */
116     	"Reserved",			/* 010 */
117     	"Reserved",			/* 011 */
118     	"Uncacheable (UC)",		/* 100 */
119     	"Uncacheable Exported (UCE)",	/* 101 */
120     	"Write Coalescing (WC)",	/* 110 */
121     	"NaTPage"			/* 111 */
122     };
123     
124     /*
125      * Take a 64bit vector and produces a string such that
126      * if bit n is set then 2^n in clear text is generated. The adjustment
127      * to the right unit is also done.
128      *
129      * Input:
130      *	- a pointer to a buffer to hold the string
131      *	- a 64-bit vector
132      * Ouput:
133      *	- a pointer to the end of the buffer
134      *
135      */
136     static char *
137     bitvector_process(char *p, u64 vector)
138     {
139     	int i,j;
140     	const char *units[]={ "", "K", "M", "G", "T" };
141     
142     	for (i=0, j=0; i < 64; i++ , j=i/10) {
143     		if (vector & 0x1) {
144     			p += sprintf(p, "%d%s ", 1 << (i-j*10), units[j]);
145     		}
146     		vector >>= 1;
147     	}
148     	return p;
149     }
150     
151     /*
152      * Take a 64bit vector and produces a string such that
153      * if bit n is set then register n is present. The function
154      * takes into account consecutive registers and prints out ranges.
155      *
156      * Input:
157      *	- a pointer to a buffer to hold the string
158      *	- a 64-bit vector
159      * Ouput:
160      *	- a pointer to the end of the buffer
161      *
162      */
163     static char *
164     bitregister_process(char *p, u64 *reg_info, int max)
165     {
166     	int i, begin, skip = 0;
167     	u64 value = reg_info[0];
168     
169     	value >>= i = begin = ffs(value) - 1;
170     
171     	for(; i < max; i++ ) {
172     
173     		if (i != 0 && (i%64) == 0) value = *++reg_info;
174     
175     		if ((value & 0x1) == 0 && skip == 0) {
176     			if (begin  <= i - 2)
177     				p += sprintf(p, "%d-%d ", begin, i-1);
178     			else
179     				p += sprintf(p, "%d ", i-1);
180     			skip  = 1;
181     			begin = -1;
182     		} else if ((value & 0x1) && skip == 1) {
183     			skip = 0;
184     			begin = i;
185     		}
186     		value >>=1;
187     	}
188     	if (begin > -1) {
189     		if (begin < 127)
190     			p += sprintf(p, "%d-127", begin);
191     		else
192     			p += sprintf(p, "127");
193     	}
194     
195     	return p;
196     }
197     
198     static int
199     power_info(char *page)
200     {
201     	s64 status;
202     	char *p = page;
203     	u64 halt_info_buffer[8];
204     	pal_power_mgmt_info_u_t *halt_info =(pal_power_mgmt_info_u_t *)halt_info_buffer;
205     	int i;
206     
207     	status = ia64_pal_halt_info(halt_info);
208     	if (status != 0) return 0;
209     
210     	for (i=0; i < 8 ; i++ ) {
211     		if (halt_info[i].pal_power_mgmt_info_s.im == 1) {
212     			p += sprintf(p,	"Power level %d:\n" 
213     					"\tentry_latency       : %d cycles\n" 
214     					"\texit_latency        : %d cycles\n" 
215     					"\tpower consumption   : %d mW\n" 
216     					"\tCache+TLB coherency : %s\n", i,
217     				halt_info[i].pal_power_mgmt_info_s.entry_latency,
218     				halt_info[i].pal_power_mgmt_info_s.exit_latency,
219     				halt_info[i].pal_power_mgmt_info_s.power_consumption,
220     				halt_info[i].pal_power_mgmt_info_s.co ? "Yes" : "No");
221     		} else {
222     			p += sprintf(p,"Power level %d: not implemented\n",i);
223     		}
224     	}
225     	return p - page;
226     }
227     
228     static int
229     cache_info(char *page)
230     {
231     	char *p = page;
232     	u64 levels, unique_caches;
233     	pal_cache_config_info_t cci;
234     	int i,j, k;
235     	s64 status;
236     
237     	if ((status=ia64_pal_cache_summary(&levels, &unique_caches)) != 0) {
238     			printk("ia64_pal_cache_summary=%ld\n", status);
239     			return 0;
240     	}
241     
242     	p += sprintf(p, "Cache levels  : %ld\n" 
243     			"Unique caches : %ld\n\n",
244     			levels,
245     			unique_caches);
246     
247     	for (i=0; i < levels; i++) {
248     
249     		for (j=2; j >0 ; j--) {
250     
251     			/* even without unification some level may not be present */
252     			if ((status=ia64_pal_cache_config_info(i,j, &cci)) != 0) {
253     				continue;
254     			}
255     			p += sprintf(p, "%s Cache level %d:\n" 
256     					"\tSize           : %ld bytes\n" 
257     					"\tAttributes     : ",
258     					cache_types[j+cci.pcci_unified], i+1,
259     					cci.pcci_cache_size);
260     
261     			if (cci.pcci_unified) p += sprintf(p, "Unified ");
262     
263     			p += sprintf(p, "%s\n", cache_mattrib[cci.pcci_cache_attr]);
264     
265     			p += sprintf(p, "\tAssociativity  : %d\n" 
266     					"\tLine size      : %d bytes\n" 
267     					"\tStride         : %d bytes\n",
268     					cci.pcci_assoc,
269     					1<<cci.pcci_line_size,
270     					1<<cci.pcci_stride);
271     			if (j == 1)
272     				p += sprintf(p, "\tStore latency  : N/A\n");
273     			else
274     				p += sprintf(p, "\tStore latency  : %d cycle(s)\n",
275     						cci.pcci_st_latency);
276     
277     			p += sprintf(p, "\tLoad latency   : %d cycle(s)\n" 
278     					"\tStore hints    : ",
279     					cci.pcci_ld_latency);
280     
281     			for(k=0; k < 8; k++ ) {
282     				if ( cci.pcci_st_hints & 0x1) p += sprintf(p, "[%s]", cache_st_hints[k]);
283     				cci.pcci_st_hints >>=1;
284     			}
285     			p += sprintf(p, "\n\tLoad hints     : ");
286     
287     			for(k=0; k < 8; k++ ) {
288     				if ( cci.pcci_ld_hints & 0x1) p += sprintf(p, "[%s]", cache_ld_hints[k]);
289     				cci.pcci_ld_hints >>=1;
290     			}
291     			p += sprintf(p, "\n\tAlias boundary : %d byte(s)\n" 
292     					"\tTag LSB        : %d\n" 
293     					"\tTag MSB        : %d\n",
294     					1<<cci.pcci_alias_boundary,
295     					cci.pcci_tag_lsb,
296     					cci.pcci_tag_msb);
297     
298     			/* when unified, data(j=2) is enough */
299     			if (cci.pcci_unified) break;
300     		}
301     	}
302     	return p - page;
303     }
304     
305     
306     static int
307     vm_info(char *page)
308     {
309     	char *p = page;
310     	u64 tr_pages =0, vw_pages=0, tc_pages;
311     	u64 attrib;
312     	pal_vm_info_1_u_t vm_info_1;
313     	pal_vm_info_2_u_t vm_info_2;
314     	pal_tc_info_u_t	tc_info;
315     	ia64_ptce_info_t ptce;
316     	int i, j;
317     	s64 status;
318     
319     	if ((status=ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
320     		printk("ia64_pal_vm_summary=%ld\n", status);
321     		return 0;
322     	}
323     
324     
325     	p += sprintf(p, "Physical Address Space         : %d bits\n" 
326     			"Virtual Address Space          : %d bits\n" 
327     			"Protection Key Registers(PKR)  : %d\n" 
328     			"Implemented bits in PKR.key    : %d\n" 
329     			"Hash Tag ID                    : 0x%x\n" 
330     			"Size of RR.rid                 : %d\n",
331     			vm_info_1.pal_vm_info_1_s.phys_add_size,
332     			vm_info_2.pal_vm_info_2_s.impl_va_msb+1,
333     			vm_info_1.pal_vm_info_1_s.max_pkr+1,
334     			vm_info_1.pal_vm_info_1_s.key_size,
335     			vm_info_1.pal_vm_info_1_s.hash_tag_id,
336     			vm_info_2.pal_vm_info_2_s.rid_size);
337     
338     	if (ia64_pal_mem_attrib(&attrib) != 0) return 0;
339     
340     	p += sprintf(p, "Supported memory attributes    : %s\n", mem_attrib[attrib&0x7]);
341     
342     	if ((status=ia64_pal_vm_page_size(&tr_pages, &vw_pages)) !=0) {
343     		printk("ia64_pal_vm_page_size=%ld\n", status);
344     		return 0;
345     	}
346     
347     	p += sprintf(p, "\nTLB walker                     : %s implemented\n" 
348     			"Number of DTR                  : %d\n" 
349     			"Number of ITR                  : %d\n" 
350     			"TLB insertable page sizes      : ",
351     			vm_info_1.pal_vm_info_1_s.vw ? "\b":"not",
352     			vm_info_1.pal_vm_info_1_s.max_dtr_entry+1,
353     			vm_info_1.pal_vm_info_1_s.max_itr_entry+1);
354     
355     
356     	p = bitvector_process(p, tr_pages);
357     
358     	p += sprintf(p, "\nTLB purgeable page sizes       : ");
359     
360     	p = bitvector_process(p, vw_pages);
361     
362     	if ((status=ia64_get_ptce(&ptce)) != 0) {
363     		printk("ia64_get_ptce=%ld\n",status);
364     		return 0;
365     	}
366     
367     	p += sprintf(p, "\nPurge base address             : 0x%016lx\n" 
368     			"Purge outer loop count         : %d\n" 
369     			"Purge inner loop count         : %d\n" 
370     			"Purge outer loop stride        : %d\n" 
371     			"Purge inner loop stride        : %d\n",
372     			ptce.base,
373     			ptce.count[0],
374     			ptce.count[1],
375     			ptce.stride[0],
376     			ptce.stride[1]);
377     
378     	p += sprintf(p, "TC Levels                      : %d\n" 
379     			"Unique TC(s)                   : %d\n",
380     			vm_info_1.pal_vm_info_1_s.num_tc_levels,
381     			vm_info_1.pal_vm_info_1_s.max_unique_tcs);
382     
383     	for(i=0; i < vm_info_1.pal_vm_info_1_s.num_tc_levels; i++) {
384     		for (j=2; j>0 ; j--) {
385     			tc_pages = 0; /* just in case */
386     
387     
388     			/* even without unification, some levels may not be present */
389     			if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) {
390     				continue;
391     			}
392     
393     			p += sprintf(p, "\n%s Translation Cache Level %d:\n" 
394     					"\tHash sets           : %d\n" 
395     					"\tAssociativity       : %d\n" 
396     					"\tNumber of entries   : %d\n" 
397     					"\tFlags               : ",
398     					cache_types[j+tc_info.tc_unified], i+1,
399     					tc_info.tc_num_sets,
400     					tc_info.tc_associativity,
401     					tc_info.tc_num_entries);
402     
403     			if (tc_info.tc_pf) p += sprintf(p, "PreferredPageSizeOptimized ");
404     			if (tc_info.tc_unified) p += sprintf(p, "Unified ");
405     			if (tc_info.tc_reduce_tr) p += sprintf(p, "TCReduction");
406     
407     			p += sprintf(p, "\n\tSupported page sizes: ");
408     
409     			p = bitvector_process(p, tc_pages);
410     
411     			/* when unified date (j=2) is enough */
412     			if (tc_info.tc_unified) break;
413     		}
414     	}
415     	p += sprintf(p, "\n");
416     
417     	return p - page;
418     }
419     
420     
421     static int
422     register_info(char *page)
423     {
424     	char *p = page;
425     	u64 reg_info[2];
426     	u64 info;
427     	u64 phys_stacked;
428     	pal_hints_u_t hints;
429     	u64 iregs, dregs;
430     	char *info_type[]={
431     		"Implemented AR(s)",
432     		"AR(s) with read side-effects",
433     		"Implemented CR(s)",
434     		"CR(s) with read side-effects",
435     	};
436     
437     	for(info=0; info < 4; info++) {
438     
439     		if (ia64_pal_register_info(info, &reg_info[0], &reg_info[1]) != 0) return 0;
440     
441     		p += sprintf(p, "%-32s : ", info_type[info]);
442     
443     		p = bitregister_process(p, reg_info, 128);
444     
445     		p += sprintf(p, "\n");
446     	}
447     
448     	if (ia64_pal_rse_info(&phys_stacked, &hints) != 0) return 0;
449     
450     	p += sprintf(p, "RSE stacked physical registers   : %ld\n" 
451     			"RSE load/store hints             : %ld (%s)\n",
452     			phys_stacked,
453     			hints.ph_data,
454     			hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)");
455     
456     	if (ia64_pal_debug_info(&iregs, &dregs)) return 0;
457     
458     	p += sprintf(p, "Instruction debug register pairs : %ld\n" 
459     			"Data debug register pairs        : %ld\n",
460     			iregs, dregs);
461     
462     	return p - page;
463     }
464     
465     static const char *proc_features[]={
466     	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
467     	NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,
468     	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
469     	NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,
470     	NULL,NULL,NULL,NULL,NULL,
471     	"XIP,XPSR,XFS implemented",
472     	"XR1-XR3 implemented",
473     	"Disable dynamic predicate prediction",
474     	"Disable processor physical number",
475     	"Disable dynamic data cache prefetch",
476     	"Disable dynamic inst cache prefetch",
477     	"Disable dynamic branch prediction",
478     	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
479     	"Disable BINIT on processor time-out",
480     	"Disable dynamic power management (DPM)",
481     	"Disable coherency",
482     	"Disable cache",
483     	"Enable CMCI promotion",
484     	"Enable MCA to BINIT promotion",
485     	"Enable MCA promotion",
486     	"Enable BEER promotion"
487     };
488     
489     
490     static int
491     processor_info(char *page)
492     {
493     	char *p = page;
494     	const char **v = proc_features;
495     	u64 avail=1, status=1, control=1;
496     	int i;
497     	s64 ret;
498     
499     	if ((ret=ia64_pal_proc_get_features(&avail, &status, &control)) != 0) return 0;
500     
501     	for(i=0; i < 64; i++, v++,avail >>=1, status >>=1, control >>=1) {
502     		if ( ! *v ) continue;
503     		p += sprintf(p, "%-40s : %s%s %s\n", *v,
504     				avail & 0x1 ? "" : "NotImpl",
505     				avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "",
506     				avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): "");
507     	}
508     	return p - page;
509     }
510     
511     static const char *bus_features[]={
512     	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
513     	NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,
514     	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
515     	NULL,NULL,
516     	"Request  Bus Parking",
517     	"Bus Lock Mask",
518     	"Enable Half Transfer",
519     	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
520     	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
521     	NULL, NULL, NULL, NULL,
522     	"Enable Cache Line Repl. Exclusive",
523     	"Enable Cache Line Repl. Shared",
524     	"Disable Transaction Queuing",
525     	"Disable Reponse Error Checking",
526     	"Disable Bus Error Checking",
527     	"Disable Bus Requester Internal Error Signalling",
528     	"Disable Bus Requester Error Signalling",
529     	"Disable Bus Initialization Event Checking",
530     	"Disable Bus Initialization Event Signalling",
531     	"Disable Bus Address Error Checking",
532     	"Disable Bus Address Error Signalling",
533     	"Disable Bus Data Error Checking"
534     };
535     
536     
537     static int
538     bus_info(char *page)
539     {
540     	char *p = page;
541     	const char **v = bus_features;
542     	pal_bus_features_u_t av, st, ct;
543     	u64 avail, status, control;
544     	int i;
545     	s64 ret;
546     
547     	if ((ret=ia64_pal_bus_get_features(&av, &st, &ct)) != 0) return 0;
548     
549     	avail   = av.pal_bus_features_val;
550     	status  = st.pal_bus_features_val;
551     	control = ct.pal_bus_features_val;
552     
553     	for(i=0; i < 64; i++, v++, avail >>=1, status >>=1, control >>=1) {
554     		if ( ! *v ) continue;
555     		p += sprintf(p, "%-48s : %s%s %s\n", *v,
556     				avail & 0x1 ? "" : "NotImpl",
557     				avail & 0x1 ? (status  & 0x1 ? "On" : "Off"): "",
558     				avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): "");
559     	}
560     	return p - page;
561     }
562     
563     static int
564     version_info(char *page)
565     {
566     	pal_version_u_t min_ver, cur_ver;
567     	char *p = page;
568     
569     	/* The PAL_VERSION call is advertised as being able to support
570     	 * both physical and virtual mode calls. This seems to be a documentation
571     	 * bug rather than firmware bug. In fact, it does only support physical mode.
572     	 * So now the code reflects this fact and the pal_version() has been updated
573     	 * accordingly.
574     	 */
575     	if (ia64_pal_version(&min_ver, &cur_ver) != 0) return 0;
576     
577     	p += sprintf(p, "PAL_vendor : 0x%02x (min=0x%02x)\n" 
578     			"PAL_A      : %x.%x.%x (min=%x.%x.%x)\n" 
579     			"PAL_B      : %x.%x.%x (min=%x.%x.%x)\n",
580     			cur_ver.pal_version_s.pv_pal_vendor,
581     			min_ver.pal_version_s.pv_pal_vendor,
582     
583     			cur_ver.pal_version_s.pv_pal_a_model>>4,
584     			cur_ver.pal_version_s.pv_pal_a_model&0xf,
585     			cur_ver.pal_version_s.pv_pal_a_rev,
586     			min_ver.pal_version_s.pv_pal_a_model>>4,
587     			min_ver.pal_version_s.pv_pal_a_model&0xf,
588     			min_ver.pal_version_s.pv_pal_a_rev,
589     
590     			cur_ver.pal_version_s.pv_pal_b_model>>4,
591     			cur_ver.pal_version_s.pv_pal_b_model&0xf,
592     			cur_ver.pal_version_s.pv_pal_b_rev,
593     			min_ver.pal_version_s.pv_pal_b_model>>4,
594     			min_ver.pal_version_s.pv_pal_b_model&0xf,
595     			min_ver.pal_version_s.pv_pal_b_rev);
596     
597     	return p - page;
598     }
599     
600     static int
601     perfmon_info(char *page)
602     {
603     	char *p = page;
604     	u64 pm_buffer[16];
605     	pal_perf_mon_info_u_t pm_info;
606     
607     	if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0;
608     
609     #ifdef IA64_PAL_PERF_MON_INFO_BUG
610     	/*
611     	 * This bug has been fixed in PAL 2.2.9 and higher
612     	 */
613     	pm_buffer[5]=0x3;
614     	pm_info.pal_perf_mon_info_s.cycles  = 0x12;
615     	pm_info.pal_perf_mon_info_s.retired = 0x08;
616     #endif
617     
618     	p += sprintf(p, "PMC/PMD pairs                 : %d\n" 
619     			"Counter width                 : %d bits\n" 
620     			"Cycle event number            : %d\n" 
621     			"Retired event number          : %d\n" 
622     			"Implemented PMC               : ",
623     			pm_info.pal_perf_mon_info_s.generic,
624     			pm_info.pal_perf_mon_info_s.width,
625     			pm_info.pal_perf_mon_info_s.cycles,
626     			pm_info.pal_perf_mon_info_s.retired);
627     
628     	p = bitregister_process(p, pm_buffer, 256);
629     
630     	p += sprintf(p, "\nImplemented PMD               : ");
631     
632     	p = bitregister_process(p, pm_buffer+4, 256);
633     
634     	p += sprintf(p, "\nCycles count capable          : ");
635     
636     	p = bitregister_process(p, pm_buffer+8, 256);
637     
638     	p += sprintf(p, "\nRetired bundles count capable : ");
639     
640     	p = bitregister_process(p, pm_buffer+12, 256);
641     
642     	p += sprintf(p, "\n");
643     
644     	return p - page;
645     }
646     
647     static int
648     frequency_info(char *page)
649     {
650     	char *p = page;
651     	struct pal_freq_ratio proc, itc, bus;
652     	u64 base;
653     
654     	if (ia64_pal_freq_base(&base) == -1)
655     		p += sprintf(p, "Output clock            : not implemented\n");
656     	else
657     		p += sprintf(p, "Output clock            : %ld ticks/s\n", base);
658     
659     	if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0;
660     
661     	p += sprintf(p, "Processor/Clock ratio   : %ld/%ld\n" 
662     			"Bus/Clock ratio         : %ld/%ld\n" 
663     			"ITC/Clock ratio         : %ld/%ld\n",
664     			proc.num, proc.den,
665     			bus.num, bus.den,
666     			itc.num, itc.den);
667     
668     	return p - page;
669     }
670     
671     static int
672     tr_info(char *page)
673     {
674     	char *p = page;
675     	s64 status;
676     	pal_tr_valid_u_t tr_valid;
677     	u64 tr_buffer[4];
678     	pal_vm_info_1_u_t vm_info_1;
679     	pal_vm_info_2_u_t vm_info_2;
680     	int i, j;
681     	u64 max[3], pgm;
682     	struct ifa_reg {
683     		u64 valid:1;
684     		u64 ig:11;
685     		u64 vpn:52;
686     	} *ifa_reg;
687     	struct itir_reg {
688     		u64 rv1:2;
689     		u64 ps:6;
690     		u64 key:24;
691     		u64 rv2:32;
692     	} *itir_reg;
693     	struct gr_reg {
694     		u64 p:1;
695     		u64 rv1:1;
696     		u64 ma:3;
697     		u64 a:1;
698     		u64 d:1;
699     		u64 pl:2;
700     		u64 ar:3;
701     		u64 ppn:38;
702     		u64 rv2:2;
703     		u64 ed:1;
704     		u64 ig:11;
705     	} *gr_reg;
706     	struct rid_reg {
707     		u64 ig1:1;
708     		u64 rv1:1;
709     		u64 ig2:6;
710     		u64 rid:24;
711     		u64 rv2:32;
712     	} *rid_reg;
713     
714     	if ((status=ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
715     		printk("ia64_pal_vm_summary=%ld\n", status);
716     		return 0;
717     	}
718     	max[0] = vm_info_1.pal_vm_info_1_s.max_itr_entry+1;
719     	max[1] = vm_info_1.pal_vm_info_1_s.max_dtr_entry+1;
720     
721     	for (i=0; i < 2; i++ ) {
722     		for (j=0; j < max[i]; j++) {
723     
724     		status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid);
725     		if (status != 0) {
726     			printk(__FUNCTION__ " pal call failed on tr[%d:%d]=%ld\n", i, j, status);
727     			continue;
728     		}
729     
730     		ifa_reg  = (struct ifa_reg *)&tr_buffer[2];
731     
732     		if (ifa_reg->valid == 0) continue;
733     
734     		gr_reg   = (struct gr_reg *)tr_buffer;
735     		itir_reg = (struct itir_reg *)&tr_buffer[1];
736     		rid_reg  = (struct rid_reg *)&tr_buffer[3];
737     
738     		pgm	 = -1 << (itir_reg->ps - 12);
739     		p += sprintf(p, "%cTR%d: av=%d pv=%d dv=%d mv=%d\n" 
740     				"\tppn  : 0x%lx\n" 
741     				"\tvpn  : 0x%lx\n" 
742     				"\tps   : ",
743     
744     				"ID"[i],
745     				j,
746     				tr_valid.pal_tr_valid_s.access_rights_valid,
747     				tr_valid.pal_tr_valid_s.priv_level_valid,
748     				tr_valid.pal_tr_valid_s.dirty_bit_valid,
749     				tr_valid.pal_tr_valid_s.mem_attr_valid,
750     				(gr_reg->ppn & pgm)<< 12,
751     				(ifa_reg->vpn & pgm)<< 12);
752     
753     		p = bitvector_process(p, 1<< itir_reg->ps);
754     
755     		p += sprintf(p, "\n\tpl   : %d\n" 
756     				"\tar   : %d\n" 
757     				"\trid  : %x\n" 
758     				"\tp    : %d\n" 
759     				"\tma   : %d\n" 
760     				"\td    : %d\n",
761     				gr_reg->pl,
762     				gr_reg->ar,
763     				rid_reg->rid,
764     				gr_reg->p,
765     				gr_reg->ma,
766     				gr_reg->d);
767     		}
768     	}
769     	return p - page;
770     }
771     
772     
773     
774     /*
775      * List {name,function} pairs for every entry in /proc/palinfo/cpu*
776      */
777     static palinfo_entry_t palinfo_entries[]={
778     	{ "version_info",	version_info, },
779     	{ "vm_info",		vm_info, },
780     	{ "cache_info",		cache_info, },
781     	{ "power_info",		power_info, },
782     	{ "register_info",	register_info, },
783     	{ "processor_info",	processor_info, },
784     	{ "perfmon_info",	perfmon_info, },
785     	{ "frequency_info",	frequency_info, },
786     	{ "bus_info",		bus_info },
787     	{ "tr_info",		tr_info, }
788     };
789     
790     #define NR_PALINFO_ENTRIES	(sizeof(palinfo_entries)/sizeof(palinfo_entry_t))
791     
792     /*
793      * this array is used to keep track of the proc entries we create. This is
794      * required in the module mode when we need to remove all entries. The procfs code
795      * does not do recursion of deletion
796      *
797      * Notes:
798      *	- first +1 accounts for the cpuN entry
799      *	- second +1 account for toplevel palinfo
800      *
801      */
802     #define NR_PALINFO_PROC_ENTRIES	(NR_CPUS*(NR_PALINFO_ENTRIES+1)+1)
803     
804     static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES];
805     
806     /*
807      * This data structure is used to pass which cpu,function is being requested
808      * It must fit in a 64bit quantity to be passed to the proc callback routine
809      *
810      * In SMP mode, when we get a request for another CPU, we must call that
811      * other CPU using IPI and wait for the result before returning.
812      */
813     typedef union {
814     	u64 value;
815     	struct {
816     		unsigned	req_cpu: 32;	/* for which CPU this info is */
817     		unsigned	func_id: 32;	/* which function is requested */
818     	} pal_func_cpu;
819     } pal_func_cpu_u_t;
820     
821     #define req_cpu	pal_func_cpu.req_cpu
822     #define func_id pal_func_cpu.func_id
823     
824     #ifdef CONFIG_SMP
825     
826     /*
827      * used to hold information about final function to call
828      */
829     typedef struct {
830     	palinfo_func_t	func;	/* pointer to function to call */
831     	char		*page;	/* buffer to store results */
832     	int		ret;	/* return value from call */
833     } palinfo_smp_data_t;
834     
835     
836     /*
837      * this function does the actual final call and he called
838      * from the smp code, i.e., this is the palinfo callback routine
839      */
840     static void
841     palinfo_smp_call(void *info)
842     {
843     	palinfo_smp_data_t *data = (palinfo_smp_data_t *)info;
844     	/* printk(__FUNCTION__" called on CPU %d\n", smp_processor_id());*/
845     	if (data == NULL) {
846     		printk(KERN_ERR __FUNCTION__" data pointer is NULL\n");
847     		data->ret = 0; /* no output */
848     		return;
849     	}
850     	/* does this actual call */
851     	data->ret = (*data->func)(data->page);
852     }
853     
854     /*
855      * function called to trigger the IPI, we need to access a remote CPU
856      * Return:
857      *	0 : error or nothing to output
858      *	otherwise how many bytes in the "page" buffer were written
859      */
860     static
861     int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
862     {
863     	palinfo_smp_data_t ptr;
864     	int ret;
865     
866     	ptr.func = palinfo_entries[f->func_id].proc_read;
867     	ptr.page = page;
868     	ptr.ret  = 0; /* just in case */
869     
870     	/*printk(__FUNCTION__" calling CPU %d from CPU %d for function %d\n", f->req_cpu,smp_processor_id(), f->func_id);*/
871     
872     	/* will send IPI to other CPU and wait for completion of remote call */
873     	if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 0, 1))) {
874     		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);
875     		return 0;
876     	}
877     	return ptr.ret;
878     }
879     #else /* ! CONFIG_SMP */
880     static
881     int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
882     {
883     	printk(__FUNCTION__" should not be called with non SMP kernel\n");
884     	return 0;
885     }
886     #endif /* CONFIG_SMP */
887     
888     /*
889      * Entry point routine: all calls go through this function
890      */
891     static int
892     palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
893     {
894     	int len=0;
895     	pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&data;
896     
897     	MOD_INC_USE_COUNT;
898     	/*
899     	 * in SMP mode, we may need to call another CPU to get correct
900     	 * information. PAL, by definition, is processor specific
901     	 */
902     	if (f->req_cpu == smp_processor_id())
903     		len = (*palinfo_entries[f->func_id].proc_read)(page);
904     	else
905     		len = palinfo_handle_smp(f, page);
906     
907     	if (len <= off+count) *eof = 1;
908     
909     	*start = page + off;
910     	len   -= off;
911     
912     	if (len>count) len = count;
913     	if (len<0) len = 0;
914     
915     	MOD_DEC_USE_COUNT;
916     
917     	return len;
918     }
919     
920     static int __init
921     palinfo_init(void)
922     {
923     #	define CPUSTR	"cpu%d"
924     
925     	pal_func_cpu_u_t f;
926     	struct proc_dir_entry **pdir = palinfo_proc_entries;
927     	struct proc_dir_entry *palinfo_dir, *cpu_dir;
928     	int i, j;
929     	char cpustr[sizeof(CPUSTR)];
930     
931     	printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);
932     
933     	palinfo_dir = proc_mkdir("pal", NULL);
934     
935     	/*
936     	 * we keep track of created entries in a depth-first order for
937     	 * cleanup purposes. Each entry is stored into palinfo_proc_entries
938     	 */
939     	for (i=0; i < NR_CPUS; i++) {
940     
941     		if (!cpu_is_online(i)) continue;
942     
943     		sprintf(cpustr,CPUSTR, i);
944     
945     		cpu_dir = proc_mkdir(cpustr, palinfo_dir);
946     
947     		f.req_cpu = i;
948     
949     		for (j=0; j < NR_PALINFO_ENTRIES; j++) {
950     			f.func_id = j;
951     			*pdir++ = create_proc_read_entry (palinfo_entries[j].name, 0, cpu_dir,
952     						palinfo_read_entry, (void *)f.value);
953     		}
954     		*pdir++ = cpu_dir;
955     	}
956     	*pdir = palinfo_dir;
957     
958     	return 0;
959     }
960     
961     static void __exit
962     palinfo_exit(void)
963     {
964     	int i = 0;
965     
966     	/* remove all nodes: depth first pass. Could optimize this  */
967     	for (i=0; i< NR_PALINFO_PROC_ENTRIES ; i++) {
968     		if (palinfo_proc_entries[i])
969     			remove_proc_entry (palinfo_proc_entries[i]->name, NULL);
970     	}
971     }
972     
973     module_init(palinfo_init);
974     module_exit(palinfo_exit);
975