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