xref: /openbmc/linux/arch/ia64/kernel/palinfo.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * palinfo.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Prints processor specific information reported by PAL.
61da177e4SLinus Torvalds  * This code is based on specification of PAL as of the
71da177e4SLinus Torvalds  * Intel IA-64 Architecture Software Developer's Manual v1.0.
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * Copyright (C) 2000-2001, 2003 Hewlett-Packard Co
111da177e4SLinus Torvalds  *	Stephane Eranian <eranian@hpl.hp.com>
121da177e4SLinus Torvalds  * Copyright (C) 2004 Intel Corporation
131da177e4SLinus Torvalds  *  Ashok Raj <ashok.raj@intel.com>
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  * 05/26/2000	S.Eranian	initial release
161da177e4SLinus Torvalds  * 08/21/2000	S.Eranian	updated to July 2000 PAL specs
171da177e4SLinus Torvalds  * 02/05/2001   S.Eranian	fixed module support
181da177e4SLinus Torvalds  * 10/23/2001	S.Eranian	updated pal_perf_mon_info bug fixes
191da177e4SLinus Torvalds  * 03/24/2004	Ashok Raj	updated to work with CPU Hotplug
20895309ffSRuss Anderson  * 10/26/2006   Russ Anderson	updated processor features to rev 2.2 spec
211da177e4SLinus Torvalds  */
221da177e4SLinus Torvalds #include <linux/types.h>
231da177e4SLinus Torvalds #include <linux/errno.h>
241da177e4SLinus Torvalds #include <linux/init.h>
251da177e4SLinus Torvalds #include <linux/proc_fs.h>
26e781c3d7SDavid Howells #include <linux/seq_file.h>
271da177e4SLinus Torvalds #include <linux/mm.h>
281da177e4SLinus Torvalds #include <linux/module.h>
291da177e4SLinus Torvalds #include <linux/efi.h>
301da177e4SLinus Torvalds #include <linux/notifier.h>
311da177e4SLinus Torvalds #include <linux/cpu.h>
321da177e4SLinus Torvalds #include <linux/cpumask.h>
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds #include <asm/pal.h>
351da177e4SLinus Torvalds #include <asm/sal.h>
361da177e4SLinus Torvalds #include <asm/page.h>
371da177e4SLinus Torvalds #include <asm/processor.h>
381da177e4SLinus Torvalds #include <linux/smp.h>
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
411da177e4SLinus Torvalds MODULE_DESCRIPTION("/proc interface to IA-64 PAL");
421da177e4SLinus Torvalds MODULE_LICENSE("GPL");
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds #define PALINFO_VERSION "0.5"
451da177e4SLinus Torvalds 
46e781c3d7SDavid Howells typedef int (*palinfo_func_t)(struct seq_file *);
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds typedef struct {
491da177e4SLinus Torvalds 	const char		*name;		/* name of the proc entry */
501da177e4SLinus Torvalds 	palinfo_func_t		proc_read;	/* function to call for reading */
511da177e4SLinus Torvalds 	struct proc_dir_entry	*entry;		/* registered entry (removal) */
521da177e4SLinus Torvalds } palinfo_entry_t;
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds /*
561da177e4SLinus Torvalds  *  A bunch of string array to get pretty printing
571da177e4SLinus Torvalds  */
581da177e4SLinus Torvalds 
59e781c3d7SDavid Howells static const char *cache_types[] = {
601da177e4SLinus Torvalds 	"",			/* not used */
611da177e4SLinus Torvalds 	"Instruction",
621da177e4SLinus Torvalds 	"Data",
631da177e4SLinus Torvalds 	"Data/Instruction"	/* unified */
641da177e4SLinus Torvalds };
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds static const char *cache_mattrib[]={
671da177e4SLinus Torvalds 	"WriteThrough",
681da177e4SLinus Torvalds 	"WriteBack",
691da177e4SLinus Torvalds 	"",		/* reserved */
701da177e4SLinus Torvalds 	""		/* reserved */
711da177e4SLinus Torvalds };
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds static const char *cache_st_hints[]={
741da177e4SLinus Torvalds 	"Temporal, level 1",
751da177e4SLinus Torvalds 	"Reserved",
761da177e4SLinus Torvalds 	"Reserved",
771da177e4SLinus Torvalds 	"Non-temporal, all levels",
781da177e4SLinus Torvalds 	"Reserved",
791da177e4SLinus Torvalds 	"Reserved",
801da177e4SLinus Torvalds 	"Reserved",
811da177e4SLinus Torvalds 	"Reserved"
821da177e4SLinus Torvalds };
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds static const char *cache_ld_hints[]={
851da177e4SLinus Torvalds 	"Temporal, level 1",
861da177e4SLinus Torvalds 	"Non-temporal, level 1",
871da177e4SLinus Torvalds 	"Reserved",
881da177e4SLinus Torvalds 	"Non-temporal, all levels",
891da177e4SLinus Torvalds 	"Reserved",
901da177e4SLinus Torvalds 	"Reserved",
911da177e4SLinus Torvalds 	"Reserved",
921da177e4SLinus Torvalds 	"Reserved"
931da177e4SLinus Torvalds };
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds static const char *rse_hints[]={
961da177e4SLinus Torvalds 	"enforced lazy",
971da177e4SLinus Torvalds 	"eager stores",
981da177e4SLinus Torvalds 	"eager loads",
991da177e4SLinus Torvalds 	"eager loads and stores"
1001da177e4SLinus Torvalds };
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds #define RSE_HINTS_COUNT ARRAY_SIZE(rse_hints)
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds static const char *mem_attrib[]={
1051da177e4SLinus Torvalds 	"WB",		/* 000 */
1061da177e4SLinus Torvalds 	"SW",		/* 001 */
1071da177e4SLinus Torvalds 	"010",		/* 010 */
1081da177e4SLinus Torvalds 	"011",		/* 011 */
1091da177e4SLinus Torvalds 	"UC",		/* 100 */
1101da177e4SLinus Torvalds 	"UCE",		/* 101 */
1111da177e4SLinus Torvalds 	"WC",		/* 110 */
1121da177e4SLinus Torvalds 	"NaTPage"	/* 111 */
1131da177e4SLinus Torvalds };
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds /*
1161da177e4SLinus Torvalds  * Take a 64bit vector and produces a string such that
1171da177e4SLinus Torvalds  * if bit n is set then 2^n in clear text is generated. The adjustment
1181da177e4SLinus Torvalds  * to the right unit is also done.
1191da177e4SLinus Torvalds  *
1201da177e4SLinus Torvalds  * Input:
1211da177e4SLinus Torvalds  *	- a pointer to a buffer to hold the string
1221da177e4SLinus Torvalds  *	- a 64-bit vector
123*0af96a02SJulia Lawall  * Output:
1241da177e4SLinus Torvalds  *	- a pointer to the end of the buffer
1251da177e4SLinus Torvalds  *
1261da177e4SLinus Torvalds  */
bitvector_process(struct seq_file * m,u64 vector)127e781c3d7SDavid Howells static void bitvector_process(struct seq_file *m, u64 vector)
1281da177e4SLinus Torvalds {
1291da177e4SLinus Torvalds 	int i,j;
130e781c3d7SDavid Howells 	static const char *units[]={ "", "K", "M", "G", "T" };
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 	for (i=0, j=0; i < 64; i++ , j=i/10) {
133e781c3d7SDavid Howells 		if (vector & 0x1)
134e781c3d7SDavid Howells 			seq_printf(m, "%d%s ", 1 << (i-j*10), units[j]);
1351da177e4SLinus Torvalds 		vector >>= 1;
1361da177e4SLinus Torvalds 	}
1371da177e4SLinus Torvalds }
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds /*
1401da177e4SLinus Torvalds  * Take a 64bit vector and produces a string such that
1411da177e4SLinus Torvalds  * if bit n is set then register n is present. The function
1421da177e4SLinus Torvalds  * takes into account consecutive registers and prints out ranges.
1431da177e4SLinus Torvalds  *
1441da177e4SLinus Torvalds  * Input:
1451da177e4SLinus Torvalds  *	- a pointer to a buffer to hold the string
1461da177e4SLinus Torvalds  *	- a 64-bit vector
1471da177e4SLinus Torvalds  * Ouput:
1481da177e4SLinus Torvalds  *	- a pointer to the end of the buffer
1491da177e4SLinus Torvalds  *
1501da177e4SLinus Torvalds  */
bitregister_process(struct seq_file * m,u64 * reg_info,int max)151e781c3d7SDavid Howells static void bitregister_process(struct seq_file *m, u64 *reg_info, int max)
1521da177e4SLinus Torvalds {
1531da177e4SLinus Torvalds 	int i, begin, skip = 0;
1541da177e4SLinus Torvalds 	u64 value = reg_info[0];
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	value >>= i = begin = ffs(value) - 1;
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds 	for(; i < max; i++ ) {
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 		if (i != 0 && (i%64) == 0) value = *++reg_info;
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 		if ((value & 0x1) == 0 && skip == 0) {
1631da177e4SLinus Torvalds 			if (begin  <= i - 2)
164e781c3d7SDavid Howells 				seq_printf(m, "%d-%d ", begin, i-1);
1651da177e4SLinus Torvalds 			else
166e781c3d7SDavid Howells 				seq_printf(m, "%d ", i-1);
1671da177e4SLinus Torvalds 			skip  = 1;
1681da177e4SLinus Torvalds 			begin = -1;
1691da177e4SLinus Torvalds 		} else if ((value & 0x1) && skip == 1) {
1701da177e4SLinus Torvalds 			skip = 0;
1711da177e4SLinus Torvalds 			begin = i;
1721da177e4SLinus Torvalds 		}
1731da177e4SLinus Torvalds 		value >>=1;
1741da177e4SLinus Torvalds 	}
1751da177e4SLinus Torvalds 	if (begin > -1) {
1761da177e4SLinus Torvalds 		if (begin < 127)
177e781c3d7SDavid Howells 			seq_printf(m, "%d-127", begin);
1781da177e4SLinus Torvalds 		else
179e781c3d7SDavid Howells 			seq_puts(m, "127");
180e781c3d7SDavid Howells 	}
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds 
power_info(struct seq_file * m)183e781c3d7SDavid Howells static int power_info(struct seq_file *m)
1841da177e4SLinus Torvalds {
1851da177e4SLinus Torvalds 	s64 status;
1861da177e4SLinus Torvalds 	u64 halt_info_buffer[8];
1871da177e4SLinus Torvalds 	pal_power_mgmt_info_u_t *halt_info =(pal_power_mgmt_info_u_t *)halt_info_buffer;
1881da177e4SLinus Torvalds 	int i;
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	status = ia64_pal_halt_info(halt_info);
1911da177e4SLinus Torvalds 	if (status != 0) return 0;
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds 	for (i=0; i < 8 ; i++ ) {
1941da177e4SLinus Torvalds 		if (halt_info[i].pal_power_mgmt_info_s.im == 1) {
195e781c3d7SDavid Howells 			seq_printf(m,
196e781c3d7SDavid Howells 				   "Power level %d:\n"
1971da177e4SLinus Torvalds 				   "\tentry_latency       : %d cycles\n"
1981da177e4SLinus Torvalds 				   "\texit_latency        : %d cycles\n"
1991da177e4SLinus Torvalds 				   "\tpower consumption   : %d mW\n"
2001da177e4SLinus Torvalds 				   "\tCache+TLB coherency : %s\n", i,
2011da177e4SLinus Torvalds 				   halt_info[i].pal_power_mgmt_info_s.entry_latency,
2021da177e4SLinus Torvalds 				   halt_info[i].pal_power_mgmt_info_s.exit_latency,
2031da177e4SLinus Torvalds 				   halt_info[i].pal_power_mgmt_info_s.power_consumption,
2041da177e4SLinus Torvalds 				   halt_info[i].pal_power_mgmt_info_s.co ? "Yes" : "No");
2051da177e4SLinus Torvalds 		} else {
206e781c3d7SDavid Howells 			seq_printf(m,"Power level %d: not implemented\n", i);
2071da177e4SLinus Torvalds 		}
2081da177e4SLinus Torvalds 	}
209e781c3d7SDavid Howells 	return 0;
2101da177e4SLinus Torvalds }
2111da177e4SLinus Torvalds 
cache_info(struct seq_file * m)212e781c3d7SDavid Howells static int cache_info(struct seq_file *m)
2131da177e4SLinus Torvalds {
214e088a4adSMatthew Wilcox 	unsigned long i, levels, unique_caches;
2151da177e4SLinus Torvalds 	pal_cache_config_info_t cci;
2161da177e4SLinus Torvalds 	int j, k;
217e088a4adSMatthew Wilcox 	long status;
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds 	if ((status = ia64_pal_cache_summary(&levels, &unique_caches)) != 0) {
2201da177e4SLinus Torvalds 		printk(KERN_ERR "ia64_pal_cache_summary=%ld\n", status);
2211da177e4SLinus Torvalds 		return 0;
2221da177e4SLinus Torvalds 	}
2231da177e4SLinus Torvalds 
224e781c3d7SDavid Howells 	seq_printf(m, "Cache levels  : %ld\nUnique caches : %ld\n\n",
225e781c3d7SDavid Howells 		   levels, unique_caches);
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds 	for (i=0; i < levels; i++) {
2281da177e4SLinus Torvalds 		for (j=2; j >0 ; j--) {
2291da177e4SLinus Torvalds 			/* even without unification some level may not be present */
230e781c3d7SDavid Howells 			if ((status=ia64_pal_cache_config_info(i,j, &cci)) != 0)
2311da177e4SLinus Torvalds 				continue;
232e781c3d7SDavid Howells 
233e781c3d7SDavid Howells 			seq_printf(m,
2341da177e4SLinus Torvalds 				   "%s Cache level %lu:\n"
2352ab9391dSTony Luck 				   "\tSize           : %u bytes\n"
2361da177e4SLinus Torvalds 				   "\tAttributes     : ",
2371da177e4SLinus Torvalds 				   cache_types[j+cci.pcci_unified], i+1,
2381da177e4SLinus Torvalds 				   cci.pcci_cache_size);
2391da177e4SLinus Torvalds 
240e781c3d7SDavid Howells 			if (cci.pcci_unified)
241e781c3d7SDavid Howells 				seq_puts(m, "Unified ");
2421da177e4SLinus Torvalds 
243e781c3d7SDavid Howells 			seq_printf(m, "%s\n", cache_mattrib[cci.pcci_cache_attr]);
2441da177e4SLinus Torvalds 
245e781c3d7SDavid Howells 			seq_printf(m,
2461da177e4SLinus Torvalds 				   "\tAssociativity  : %d\n"
2471da177e4SLinus Torvalds 				   "\tLine size      : %d bytes\n"
2481da177e4SLinus Torvalds 				   "\tStride         : %d bytes\n",
249e781c3d7SDavid Howells 				   cci.pcci_assoc,
250e781c3d7SDavid Howells 				   1<<cci.pcci_line_size,
251e781c3d7SDavid Howells 				   1<<cci.pcci_stride);
2521da177e4SLinus Torvalds 			if (j == 1)
253e781c3d7SDavid Howells 				seq_puts(m, "\tStore latency  : N/A\n");
2541da177e4SLinus Torvalds 			else
255e781c3d7SDavid Howells 				seq_printf(m, "\tStore latency  : %d cycle(s)\n",
2561da177e4SLinus Torvalds 					   cci.pcci_st_latency);
2571da177e4SLinus Torvalds 
258e781c3d7SDavid Howells 			seq_printf(m,
2591da177e4SLinus Torvalds 				   "\tLoad latency   : %d cycle(s)\n"
2601da177e4SLinus Torvalds 				   "\tStore hints    : ", cci.pcci_ld_latency);
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 			for(k=0; k < 8; k++ ) {
2631da177e4SLinus Torvalds 				if ( cci.pcci_st_hints & 0x1)
264e781c3d7SDavid Howells 					seq_printf(m, "[%s]", cache_st_hints[k]);
2651da177e4SLinus Torvalds 				cci.pcci_st_hints >>=1;
2661da177e4SLinus Torvalds 			}
267e781c3d7SDavid Howells 			seq_puts(m, "\n\tLoad hints     : ");
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds 			for(k=0; k < 8; k++ ) {
2701da177e4SLinus Torvalds 				if (cci.pcci_ld_hints & 0x1)
271e781c3d7SDavid Howells 					seq_printf(m, "[%s]", cache_ld_hints[k]);
2721da177e4SLinus Torvalds 				cci.pcci_ld_hints >>=1;
2731da177e4SLinus Torvalds 			}
274e781c3d7SDavid Howells 			seq_printf(m,
2751da177e4SLinus Torvalds 				   "\n\tAlias boundary : %d byte(s)\n"
2761da177e4SLinus Torvalds 				   "\tTag LSB        : %d\n"
2771da177e4SLinus Torvalds 				   "\tTag MSB        : %d\n",
2781da177e4SLinus Torvalds 				   1<<cci.pcci_alias_boundary, cci.pcci_tag_lsb,
2791da177e4SLinus Torvalds 				   cci.pcci_tag_msb);
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 			/* when unified, data(j=2) is enough */
282e781c3d7SDavid Howells 			if (cci.pcci_unified)
283e781c3d7SDavid Howells 				break;
2841da177e4SLinus Torvalds 		}
2851da177e4SLinus Torvalds 	}
286e781c3d7SDavid Howells 	return 0;
2871da177e4SLinus Torvalds }
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds 
vm_info(struct seq_file * m)290e781c3d7SDavid Howells static int vm_info(struct seq_file *m)
2911da177e4SLinus Torvalds {
2921da177e4SLinus Torvalds 	u64 tr_pages =0, vw_pages=0, tc_pages;
2931da177e4SLinus Torvalds 	u64 attrib;
2941da177e4SLinus Torvalds 	pal_vm_info_1_u_t vm_info_1;
2951da177e4SLinus Torvalds 	pal_vm_info_2_u_t vm_info_2;
2961da177e4SLinus Torvalds 	pal_tc_info_u_t	tc_info;
2971da177e4SLinus Torvalds 	ia64_ptce_info_t ptce;
2981da177e4SLinus Torvalds 	const char *sep;
2991da177e4SLinus Torvalds 	int i, j;
300e088a4adSMatthew Wilcox 	long status;
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds 	if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
3031da177e4SLinus Torvalds 		printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status);
304714d2dc1SPeter Chubb 	} else {
3051da177e4SLinus Torvalds 
306e781c3d7SDavid Howells 		seq_printf(m,
3071da177e4SLinus Torvalds 		     "Physical Address Space         : %d bits\n"
3081da177e4SLinus Torvalds 		     "Virtual Address Space          : %d bits\n"
3091da177e4SLinus Torvalds 		     "Protection Key Registers(PKR)  : %d\n"
3101da177e4SLinus Torvalds 		     "Implemented bits in PKR.key    : %d\n"
3111da177e4SLinus Torvalds 		     "Hash Tag ID                    : 0x%x\n"
3125b4d5681SRuss Anderson 		     "Size of RR.rid                 : %d\n"
3135b4d5681SRuss Anderson 		     "Max Purges                     : ",
3141da177e4SLinus Torvalds 		     vm_info_1.pal_vm_info_1_s.phys_add_size,
315714d2dc1SPeter Chubb 		     vm_info_2.pal_vm_info_2_s.impl_va_msb+1,
316714d2dc1SPeter Chubb 		     vm_info_1.pal_vm_info_1_s.max_pkr+1,
317714d2dc1SPeter Chubb 		     vm_info_1.pal_vm_info_1_s.key_size,
318714d2dc1SPeter Chubb 		     vm_info_1.pal_vm_info_1_s.hash_tag_id,
3191da177e4SLinus Torvalds 		     vm_info_2.pal_vm_info_2_s.rid_size);
3205b4d5681SRuss Anderson 		if (vm_info_2.pal_vm_info_2_s.max_purges == PAL_MAX_PURGES)
321e781c3d7SDavid Howells 			seq_puts(m, "unlimited\n");
3225b4d5681SRuss Anderson 		else
323e781c3d7SDavid Howells 			seq_printf(m, "%d\n",
3245b4d5681SRuss Anderson 		     		vm_info_2.pal_vm_info_2_s.max_purges ?
3255b4d5681SRuss Anderson 				vm_info_2.pal_vm_info_2_s.max_purges : 1);
326714d2dc1SPeter Chubb 	}
3271da177e4SLinus Torvalds 
328714d2dc1SPeter Chubb 	if (ia64_pal_mem_attrib(&attrib) == 0) {
329e781c3d7SDavid Howells 		seq_puts(m, "Supported memory attributes    : ");
3301da177e4SLinus Torvalds 		sep = "";
3311da177e4SLinus Torvalds 		for (i = 0; i < 8; i++) {
3321da177e4SLinus Torvalds 			if (attrib & (1 << i)) {
333e781c3d7SDavid Howells 				seq_printf(m, "%s%s", sep, mem_attrib[i]);
3341da177e4SLinus Torvalds 				sep = ", ";
3351da177e4SLinus Torvalds 			}
3361da177e4SLinus Torvalds 		}
337e781c3d7SDavid Howells 		seq_putc(m, '\n');
338714d2dc1SPeter Chubb 	}
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 	if ((status = ia64_pal_vm_page_size(&tr_pages, &vw_pages)) !=0) {
3411da177e4SLinus Torvalds 		printk(KERN_ERR "ia64_pal_vm_page_size=%ld\n", status);
342714d2dc1SPeter Chubb 	} else {
3431da177e4SLinus Torvalds 
344e781c3d7SDavid Howells 		seq_printf(m,
3451da177e4SLinus Torvalds 			   "\nTLB walker                     : %simplemented\n"
3461da177e4SLinus Torvalds 			   "Number of DTR                  : %d\n"
3471da177e4SLinus Torvalds 			   "Number of ITR                  : %d\n"
3481da177e4SLinus Torvalds 			   "TLB insertable page sizes      : ",
3491da177e4SLinus Torvalds 			   vm_info_1.pal_vm_info_1_s.vw ? "" : "not ",
3501da177e4SLinus Torvalds 			   vm_info_1.pal_vm_info_1_s.max_dtr_entry+1,
3511da177e4SLinus Torvalds 			   vm_info_1.pal_vm_info_1_s.max_itr_entry+1);
3521da177e4SLinus Torvalds 
353e781c3d7SDavid Howells 		bitvector_process(m, tr_pages);
3541da177e4SLinus Torvalds 
355e781c3d7SDavid Howells 		seq_puts(m, "\nTLB purgeable page sizes       : ");
3561da177e4SLinus Torvalds 
357e781c3d7SDavid Howells 		bitvector_process(m, vw_pages);
358714d2dc1SPeter Chubb 	}
359e781c3d7SDavid Howells 
3601da177e4SLinus Torvalds 	if ((status = ia64_get_ptce(&ptce)) != 0) {
3611da177e4SLinus Torvalds 		printk(KERN_ERR "ia64_get_ptce=%ld\n", status);
362714d2dc1SPeter Chubb 	} else {
363e781c3d7SDavid Howells 		seq_printf(m,
3641da177e4SLinus Torvalds 		     "\nPurge base address             : 0x%016lx\n"
3651da177e4SLinus Torvalds 		     "Purge outer loop count         : %d\n"
3661da177e4SLinus Torvalds 		     "Purge inner loop count         : %d\n"
3671da177e4SLinus Torvalds 		     "Purge outer loop stride        : %d\n"
3681da177e4SLinus Torvalds 		     "Purge inner loop stride        : %d\n",
369714d2dc1SPeter Chubb 		     ptce.base, ptce.count[0], ptce.count[1],
370714d2dc1SPeter Chubb 		     ptce.stride[0], ptce.stride[1]);
3711da177e4SLinus Torvalds 
372e781c3d7SDavid Howells 		seq_printf(m,
3731da177e4SLinus Torvalds 		     "TC Levels                      : %d\n"
3741da177e4SLinus Torvalds 		     "Unique TC(s)                   : %d\n",
3751da177e4SLinus Torvalds 		     vm_info_1.pal_vm_info_1_s.num_tc_levels,
3761da177e4SLinus Torvalds 		     vm_info_1.pal_vm_info_1_s.max_unique_tcs);
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds 		for(i=0; i < vm_info_1.pal_vm_info_1_s.num_tc_levels; i++) {
3791da177e4SLinus Torvalds 			for (j=2; j>0 ; j--) {
3801da177e4SLinus Torvalds 				tc_pages = 0; /* just in case */
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 				/* even without unification, some levels may not be present */
383e781c3d7SDavid Howells 				if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0)
3841da177e4SLinus Torvalds 					continue;
3851da177e4SLinus Torvalds 
386e781c3d7SDavid Howells 				seq_printf(m,
3871da177e4SLinus Torvalds 				     "\n%s Translation Cache Level %d:\n"
3881da177e4SLinus Torvalds 				     "\tHash sets           : %d\n"
3891da177e4SLinus Torvalds 				     "\tAssociativity       : %d\n"
3901da177e4SLinus Torvalds 				     "\tNumber of entries   : %d\n"
3911da177e4SLinus Torvalds 				     "\tFlags               : ",
392714d2dc1SPeter Chubb 				     cache_types[j+tc_info.tc_unified], i+1,
393714d2dc1SPeter Chubb 				     tc_info.tc_num_sets,
394714d2dc1SPeter Chubb 				     tc_info.tc_associativity,
395714d2dc1SPeter Chubb 				     tc_info.tc_num_entries);
3961da177e4SLinus Torvalds 
397714d2dc1SPeter Chubb 				if (tc_info.tc_pf)
398e781c3d7SDavid Howells 					seq_puts(m, "PreferredPageSizeOptimized ");
399714d2dc1SPeter Chubb 				if (tc_info.tc_unified)
400e781c3d7SDavid Howells 					seq_puts(m, "Unified ");
401714d2dc1SPeter Chubb 				if (tc_info.tc_reduce_tr)
402e781c3d7SDavid Howells 					seq_puts(m, "TCReduction");
4031da177e4SLinus Torvalds 
404e781c3d7SDavid Howells 				seq_puts(m, "\n\tSupported page sizes: ");
4051da177e4SLinus Torvalds 
406e781c3d7SDavid Howells 				bitvector_process(m, tc_pages);
4071da177e4SLinus Torvalds 
4081da177e4SLinus Torvalds 				/* when unified date (j=2) is enough */
409714d2dc1SPeter Chubb 				if (tc_info.tc_unified)
410714d2dc1SPeter Chubb 					break;
411714d2dc1SPeter Chubb 			}
4121da177e4SLinus Torvalds 		}
4131da177e4SLinus Torvalds 	}
4141da177e4SLinus Torvalds 
415e781c3d7SDavid Howells 	seq_putc(m, '\n');
416e781c3d7SDavid Howells 	return 0;
4171da177e4SLinus Torvalds }
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds 
register_info(struct seq_file * m)420e781c3d7SDavid Howells static int register_info(struct seq_file *m)
4211da177e4SLinus Torvalds {
4221da177e4SLinus Torvalds 	u64 reg_info[2];
4231da177e4SLinus Torvalds 	u64 info;
424e088a4adSMatthew Wilcox 	unsigned long phys_stacked;
4251da177e4SLinus Torvalds 	pal_hints_u_t hints;
426e088a4adSMatthew Wilcox 	unsigned long iregs, dregs;
427c216488cSJoe Perches 	static const char * const info_type[] = {
4281da177e4SLinus Torvalds 		"Implemented AR(s)",
4291da177e4SLinus Torvalds 		"AR(s) with read side-effects",
4301da177e4SLinus Torvalds 		"Implemented CR(s)",
4311da177e4SLinus Torvalds 		"CR(s) with read side-effects",
4321da177e4SLinus Torvalds 	};
4331da177e4SLinus Torvalds 
4341da177e4SLinus Torvalds 	for(info=0; info < 4; info++) {
435e781c3d7SDavid Howells 		if (ia64_pal_register_info(info, &reg_info[0], &reg_info[1]) != 0)
436e781c3d7SDavid Howells 			return 0;
437e781c3d7SDavid Howells 		seq_printf(m, "%-32s : ", info_type[info]);
438e781c3d7SDavid Howells 		bitregister_process(m, reg_info, 128);
439e781c3d7SDavid Howells 		seq_putc(m, '\n');
4401da177e4SLinus Torvalds 	}
4411da177e4SLinus Torvalds 
442e781c3d7SDavid Howells 	if (ia64_pal_rse_info(&phys_stacked, &hints) == 0)
443e781c3d7SDavid Howells 		seq_printf(m,
4441da177e4SLinus Torvalds 			   "RSE stacked physical registers   : %ld\n"
4451da177e4SLinus Torvalds 			   "RSE load/store hints             : %ld (%s)\n",
4461da177e4SLinus Torvalds 			   phys_stacked, hints.ph_data,
4471da177e4SLinus Torvalds 			   hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(??)");
448e781c3d7SDavid Howells 
4491da177e4SLinus Torvalds 	if (ia64_pal_debug_info(&iregs, &dregs))
4501da177e4SLinus Torvalds 		return 0;
4511da177e4SLinus Torvalds 
452e781c3d7SDavid Howells 	seq_printf(m,
4531da177e4SLinus Torvalds 		   "Instruction debug register pairs : %ld\n"
4541da177e4SLinus Torvalds 		   "Data debug register pairs        : %ld\n", iregs, dregs);
4551da177e4SLinus Torvalds 
456e781c3d7SDavid Howells 	return 0;
4571da177e4SLinus Torvalds }
4581da177e4SLinus Torvalds 
459e781c3d7SDavid Howells static const char *const proc_features_0[]={		/* Feature set 0 */
4601da177e4SLinus Torvalds 	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
4611da177e4SLinus Torvalds 	NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,
4621da177e4SLinus Torvalds 	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
4631da177e4SLinus Torvalds 	NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,
464895309ffSRuss Anderson 	"Unimplemented instruction address fault",
465895309ffSRuss Anderson 	"INIT, PMI, and LINT pins",
466895309ffSRuss Anderson 	"Simple unimplemented instr addresses",
467895309ffSRuss Anderson 	"Variable P-state performance",
468895309ffSRuss Anderson 	"Virtual machine features implemented",
4691da177e4SLinus Torvalds 	"XIP,XPSR,XFS implemented",
4701da177e4SLinus Torvalds 	"XR1-XR3 implemented",
4711da177e4SLinus Torvalds 	"Disable dynamic predicate prediction",
4721da177e4SLinus Torvalds 	"Disable processor physical number",
4731da177e4SLinus Torvalds 	"Disable dynamic data cache prefetch",
4741da177e4SLinus Torvalds 	"Disable dynamic inst cache prefetch",
4751da177e4SLinus Torvalds 	"Disable dynamic branch prediction",
476895309ffSRuss Anderson 	NULL, NULL, NULL, NULL,
477895309ffSRuss Anderson 	"Disable P-states",
478895309ffSRuss Anderson 	"Enable MCA on Data Poisoning",
479895309ffSRuss Anderson 	"Enable vmsw instruction",
480895309ffSRuss Anderson 	"Enable extern environmental notification",
4811da177e4SLinus Torvalds 	"Disable BINIT on processor time-out",
4821da177e4SLinus Torvalds 	"Disable dynamic power management (DPM)",
4831da177e4SLinus Torvalds 	"Disable coherency",
4841da177e4SLinus Torvalds 	"Disable cache",
4851da177e4SLinus Torvalds 	"Enable CMCI promotion",
4861da177e4SLinus Torvalds 	"Enable MCA to BINIT promotion",
4871da177e4SLinus Torvalds 	"Enable MCA promotion",
4881da177e4SLinus Torvalds 	"Enable BERR promotion"
4891da177e4SLinus Torvalds };
4901da177e4SLinus Torvalds 
491e781c3d7SDavid Howells static const char *const proc_features_16[]={		/* Feature set 16 */
492b8de471fSRuss Anderson 	"Disable ETM",
493b8de471fSRuss Anderson 	"Enable ETM",
494b8de471fSRuss Anderson 	"Enable MCA on half-way timer",
495b8de471fSRuss Anderson 	"Enable snoop WC",
496b8de471fSRuss Anderson 	NULL,
497b8de471fSRuss Anderson 	"Enable Fast Deferral",
498b8de471fSRuss Anderson 	"Disable MCA on memory aliasing",
499b8de471fSRuss Anderson 	"Enable RSB",
500b8de471fSRuss Anderson 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
501b8de471fSRuss Anderson 	"DP system processor",
502b8de471fSRuss Anderson 	"Low Voltage",
503b8de471fSRuss Anderson 	"HT supported",
504b8de471fSRuss Anderson 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
505b8de471fSRuss Anderson 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
506b8de471fSRuss Anderson 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
507b8de471fSRuss Anderson 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
508b8de471fSRuss Anderson 	NULL, NULL, NULL, NULL, NULL
509b8de471fSRuss Anderson };
510b8de471fSRuss Anderson 
511e781c3d7SDavid Howells static const char *const *const proc_features[]={
512b8de471fSRuss Anderson 	proc_features_0,
513b8de471fSRuss Anderson 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
514b8de471fSRuss Anderson 	NULL, NULL, NULL, NULL,
515b8de471fSRuss Anderson 	proc_features_16,
516b8de471fSRuss Anderson 	NULL, NULL, NULL, NULL,
517b8de471fSRuss Anderson };
518b8de471fSRuss Anderson 
feature_set_info(struct seq_file * m,u64 avail,u64 status,u64 control,unsigned long set)519e781c3d7SDavid Howells static void feature_set_info(struct seq_file *m, u64 avail, u64 status, u64 control,
520e088a4adSMatthew Wilcox 			     unsigned long set)
521b8de471fSRuss Anderson {
522e781c3d7SDavid Howells 	const char *const *vf, *const *v;
523b8de471fSRuss Anderson 	int i;
524b8de471fSRuss Anderson 
525b8de471fSRuss Anderson 	vf = v = proc_features[set];
526b8de471fSRuss Anderson 	for(i=0; i < 64; i++, avail >>=1, status >>=1, control >>=1) {
527b8de471fSRuss Anderson 
528b8de471fSRuss Anderson 		if (!(control))		/* No remaining bits set */
529b8de471fSRuss Anderson 			break;
530b8de471fSRuss Anderson 		if (!(avail & 0x1))	/* Print only bits that are available */
531b8de471fSRuss Anderson 			continue;
532b8de471fSRuss Anderson 		if (vf)
533b8de471fSRuss Anderson 			v = vf + i;
534b8de471fSRuss Anderson 		if ( v && *v ) {
535e781c3d7SDavid Howells 			seq_printf(m, "%-40s : %s %s\n", *v,
536b8de471fSRuss Anderson 				avail & 0x1 ? (status & 0x1 ?
537b8de471fSRuss Anderson 					      "On " : "Off"): "",
538b8de471fSRuss Anderson 				avail & 0x1 ? (control & 0x1 ?
539b8de471fSRuss Anderson 						"Ctrl" : "NoCtrl"): "");
540b8de471fSRuss Anderson 		} else {
541e781c3d7SDavid Howells 			seq_printf(m, "Feature set %2ld bit %2d\t\t\t"
542b8de471fSRuss Anderson 					" : %s %s\n",
543b8de471fSRuss Anderson 				set, i,
544b8de471fSRuss Anderson 				avail & 0x1 ? (status & 0x1 ?
545b8de471fSRuss Anderson 						"On " : "Off"): "",
546b8de471fSRuss Anderson 				avail & 0x1 ? (control & 0x1 ?
547b8de471fSRuss Anderson 						"Ctrl" : "NoCtrl"): "");
548b8de471fSRuss Anderson 		}
549b8de471fSRuss Anderson 	}
550b8de471fSRuss Anderson }
5511da177e4SLinus Torvalds 
processor_info(struct seq_file * m)552e781c3d7SDavid Howells static int processor_info(struct seq_file *m)
5531da177e4SLinus Torvalds {
554b8de471fSRuss Anderson 	u64 avail=1, status=1, control=1, feature_set=0;
5551da177e4SLinus Torvalds 	s64 ret;
5561da177e4SLinus Torvalds 
557b8de471fSRuss Anderson 	do {
558b8de471fSRuss Anderson 		ret = ia64_pal_proc_get_features(&avail, &status, &control,
559b8de471fSRuss Anderson 						feature_set);
560e781c3d7SDavid Howells 		if (ret < 0)
561e781c3d7SDavid Howells 			return 0;
562e781c3d7SDavid Howells 
563b8de471fSRuss Anderson 		if (ret == 1) {
564b8de471fSRuss Anderson 			feature_set++;
565b8de471fSRuss Anderson 			continue;
566b8de471fSRuss Anderson 		}
567b8de471fSRuss Anderson 
568e781c3d7SDavid Howells 		feature_set_info(m, avail, status, control, feature_set);
569b8de471fSRuss Anderson 		feature_set++;
570b8de471fSRuss Anderson 	} while(1);
571b8de471fSRuss Anderson 
572e781c3d7SDavid Howells 	return 0;
5731da177e4SLinus Torvalds }
5741da177e4SLinus Torvalds 
575e781c3d7SDavid Howells static const char *const bus_features[]={
5761da177e4SLinus Torvalds 	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
5771da177e4SLinus Torvalds 	NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,
5781da177e4SLinus Torvalds 	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
5791da177e4SLinus Torvalds 	NULL,NULL,
5801da177e4SLinus Torvalds 	"Request  Bus Parking",
5811da177e4SLinus Torvalds 	"Bus Lock Mask",
5821da177e4SLinus Torvalds 	"Enable Half Transfer",
5831da177e4SLinus Torvalds 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
5841da177e4SLinus Torvalds 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
5851da177e4SLinus Torvalds 	NULL, NULL, NULL, NULL,
5861da177e4SLinus Torvalds 	"Enable Cache Line Repl. Shared",
5871da177e4SLinus Torvalds 	"Enable Cache Line Repl. Exclusive",
5881da177e4SLinus Torvalds 	"Disable Transaction Queuing",
5891da177e4SLinus Torvalds 	"Disable Response Error Checking",
5901da177e4SLinus Torvalds 	"Disable Bus Error Checking",
5911da177e4SLinus Torvalds 	"Disable Bus Requester Internal Error Signalling",
5921da177e4SLinus Torvalds 	"Disable Bus Requester Error Signalling",
5931da177e4SLinus Torvalds 	"Disable Bus Initialization Event Checking",
5941da177e4SLinus Torvalds 	"Disable Bus Initialization Event Signalling",
5951da177e4SLinus Torvalds 	"Disable Bus Address Error Checking",
5961da177e4SLinus Torvalds 	"Disable Bus Address Error Signalling",
5971da177e4SLinus Torvalds 	"Disable Bus Data Error Checking"
5981da177e4SLinus Torvalds };
5991da177e4SLinus Torvalds 
6001da177e4SLinus Torvalds 
bus_info(struct seq_file * m)601e781c3d7SDavid Howells static int bus_info(struct seq_file *m)
6021da177e4SLinus Torvalds {
603e781c3d7SDavid Howells 	const char *const *v = bus_features;
6041da177e4SLinus Torvalds 	pal_bus_features_u_t av, st, ct;
6051da177e4SLinus Torvalds 	u64 avail, status, control;
6061da177e4SLinus Torvalds 	int i;
6071da177e4SLinus Torvalds 	s64 ret;
6081da177e4SLinus Torvalds 
609e781c3d7SDavid Howells 	if ((ret=ia64_pal_bus_get_features(&av, &st, &ct)) != 0)
610e781c3d7SDavid Howells 		return 0;
6111da177e4SLinus Torvalds 
6121da177e4SLinus Torvalds 	avail   = av.pal_bus_features_val;
6131da177e4SLinus Torvalds 	status  = st.pal_bus_features_val;
6141da177e4SLinus Torvalds 	control = ct.pal_bus_features_val;
6151da177e4SLinus Torvalds 
6161da177e4SLinus Torvalds 	for(i=0; i < 64; i++, v++, avail >>=1, status >>=1, control >>=1) {
617e781c3d7SDavid Howells 		if ( ! *v )
618e781c3d7SDavid Howells 			continue;
619e781c3d7SDavid Howells 		seq_printf(m, "%-48s : %s%s %s\n", *v,
6201da177e4SLinus Torvalds 			   avail & 0x1 ? "" : "NotImpl",
6211da177e4SLinus Torvalds 			   avail & 0x1 ? (status  & 0x1 ? "On" : "Off"): "",
6221da177e4SLinus Torvalds 			   avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): "");
6231da177e4SLinus Torvalds 	}
624e781c3d7SDavid Howells 	return 0;
6251da177e4SLinus Torvalds }
6261da177e4SLinus Torvalds 
version_info(struct seq_file * m)627e781c3d7SDavid Howells static int version_info(struct seq_file *m)
6281da177e4SLinus Torvalds {
6291da177e4SLinus Torvalds 	pal_version_u_t min_ver, cur_ver;
6301da177e4SLinus Torvalds 
6311bf1eba7SMatthew Wilcox 	if (ia64_pal_version(&min_ver, &cur_ver) != 0)
6321bf1eba7SMatthew Wilcox 		return 0;
6331da177e4SLinus Torvalds 
634e781c3d7SDavid Howells 	seq_printf(m,
6351da177e4SLinus Torvalds 		   "PAL_vendor : 0x%02x (min=0x%02x)\n"
6361bf1eba7SMatthew Wilcox 		   "PAL_A      : %02x.%02x (min=%02x.%02x)\n"
6371bf1eba7SMatthew Wilcox 		   "PAL_B      : %02x.%02x (min=%02x.%02x)\n",
6381bf1eba7SMatthew Wilcox 		   cur_ver.pal_version_s.pv_pal_vendor,
6391bf1eba7SMatthew Wilcox 		   min_ver.pal_version_s.pv_pal_vendor,
6401bf1eba7SMatthew Wilcox 		   cur_ver.pal_version_s.pv_pal_a_model,
6411bf1eba7SMatthew Wilcox 		   cur_ver.pal_version_s.pv_pal_a_rev,
6421bf1eba7SMatthew Wilcox 		   min_ver.pal_version_s.pv_pal_a_model,
6431bf1eba7SMatthew Wilcox 		   min_ver.pal_version_s.pv_pal_a_rev,
6441bf1eba7SMatthew Wilcox 		   cur_ver.pal_version_s.pv_pal_b_model,
6451bf1eba7SMatthew Wilcox 		   cur_ver.pal_version_s.pv_pal_b_rev,
6461bf1eba7SMatthew Wilcox 		   min_ver.pal_version_s.pv_pal_b_model,
6471bf1eba7SMatthew Wilcox 		   min_ver.pal_version_s.pv_pal_b_rev);
648e781c3d7SDavid Howells 	return 0;
6491da177e4SLinus Torvalds }
6501da177e4SLinus Torvalds 
frequency_info(struct seq_file * m)651e781c3d7SDavid Howells static int frequency_info(struct seq_file *m)
6521da177e4SLinus Torvalds {
6531da177e4SLinus Torvalds 	struct pal_freq_ratio proc, itc, bus;
654e088a4adSMatthew Wilcox 	unsigned long base;
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds 	if (ia64_pal_freq_base(&base) == -1)
657e781c3d7SDavid Howells 		seq_puts(m, "Output clock            : not implemented\n");
6581da177e4SLinus Torvalds 	else
659e781c3d7SDavid Howells 		seq_printf(m, "Output clock            : %ld ticks/s\n", base);
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds 	if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0;
6621da177e4SLinus Torvalds 
663e781c3d7SDavid Howells 	seq_printf(m,
6642ab9391dSTony Luck 		     "Processor/Clock ratio   : %d/%d\n"
6652ab9391dSTony Luck 		     "Bus/Clock ratio         : %d/%d\n"
6662ab9391dSTony Luck 		     "ITC/Clock ratio         : %d/%d\n",
6671da177e4SLinus Torvalds 		     proc.num, proc.den, bus.num, bus.den, itc.num, itc.den);
668e781c3d7SDavid Howells 	return 0;
6691da177e4SLinus Torvalds }
6701da177e4SLinus Torvalds 
tr_info(struct seq_file * m)671e781c3d7SDavid Howells static int tr_info(struct seq_file *m)
6721da177e4SLinus Torvalds {
673e088a4adSMatthew Wilcox 	long status;
6741da177e4SLinus Torvalds 	pal_tr_valid_u_t tr_valid;
6751da177e4SLinus Torvalds 	u64 tr_buffer[4];
6761da177e4SLinus Torvalds 	pal_vm_info_1_u_t vm_info_1;
6771da177e4SLinus Torvalds 	pal_vm_info_2_u_t vm_info_2;
678e088a4adSMatthew Wilcox 	unsigned long i, j;
679e088a4adSMatthew Wilcox 	unsigned long max[3], pgm;
6801da177e4SLinus Torvalds 	struct ifa_reg {
681e088a4adSMatthew Wilcox 		unsigned long valid:1;
682e088a4adSMatthew Wilcox 		unsigned long ig:11;
683e088a4adSMatthew Wilcox 		unsigned long vpn:52;
6841da177e4SLinus Torvalds 	} *ifa_reg;
6851da177e4SLinus Torvalds 	struct itir_reg {
686e088a4adSMatthew Wilcox 		unsigned long rv1:2;
687e088a4adSMatthew Wilcox 		unsigned long ps:6;
688e088a4adSMatthew Wilcox 		unsigned long key:24;
689e088a4adSMatthew Wilcox 		unsigned long rv2:32;
6901da177e4SLinus Torvalds 	} *itir_reg;
6911da177e4SLinus Torvalds 	struct gr_reg {
692e088a4adSMatthew Wilcox 		unsigned long p:1;
693e088a4adSMatthew Wilcox 		unsigned long rv1:1;
694e088a4adSMatthew Wilcox 		unsigned long ma:3;
695e088a4adSMatthew Wilcox 		unsigned long a:1;
696e088a4adSMatthew Wilcox 		unsigned long d:1;
697e088a4adSMatthew Wilcox 		unsigned long pl:2;
698e088a4adSMatthew Wilcox 		unsigned long ar:3;
699e088a4adSMatthew Wilcox 		unsigned long ppn:38;
700e088a4adSMatthew Wilcox 		unsigned long rv2:2;
701e088a4adSMatthew Wilcox 		unsigned long ed:1;
702e088a4adSMatthew Wilcox 		unsigned long ig:11;
7031da177e4SLinus Torvalds 	} *gr_reg;
7041da177e4SLinus Torvalds 	struct rid_reg {
705e088a4adSMatthew Wilcox 		unsigned long ig1:1;
706e088a4adSMatthew Wilcox 		unsigned long rv1:1;
707e088a4adSMatthew Wilcox 		unsigned long ig2:6;
708e088a4adSMatthew Wilcox 		unsigned long rid:24;
709e088a4adSMatthew Wilcox 		unsigned long rv2:32;
7101da177e4SLinus Torvalds 	} *rid_reg;
7111da177e4SLinus Torvalds 
7121da177e4SLinus Torvalds 	if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
7131da177e4SLinus Torvalds 		printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status);
7141da177e4SLinus Torvalds 		return 0;
7151da177e4SLinus Torvalds 	}
7161da177e4SLinus Torvalds 	max[0] = vm_info_1.pal_vm_info_1_s.max_itr_entry+1;
7171da177e4SLinus Torvalds 	max[1] = vm_info_1.pal_vm_info_1_s.max_dtr_entry+1;
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds 	for (i=0; i < 2; i++ ) {
7201da177e4SLinus Torvalds 		for (j=0; j < max[i]; j++) {
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds 		status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid);
7231da177e4SLinus Torvalds 		if (status != 0) {
7241da177e4SLinus Torvalds 			printk(KERN_ERR "palinfo: pal call failed on tr[%lu:%lu]=%ld\n",
7251da177e4SLinus Torvalds 			       i, j, status);
7261da177e4SLinus Torvalds 			continue;
7271da177e4SLinus Torvalds 		}
7281da177e4SLinus Torvalds 
7291da177e4SLinus Torvalds 		ifa_reg  = (struct ifa_reg *)&tr_buffer[2];
7301da177e4SLinus Torvalds 
731e781c3d7SDavid Howells 		if (ifa_reg->valid == 0)
732e781c3d7SDavid Howells 			continue;
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 		gr_reg   = (struct gr_reg *)tr_buffer;
7351da177e4SLinus Torvalds 		itir_reg = (struct itir_reg *)&tr_buffer[1];
7361da177e4SLinus Torvalds 		rid_reg  = (struct rid_reg *)&tr_buffer[3];
7371da177e4SLinus Torvalds 
7381da177e4SLinus Torvalds 		pgm	 = -1 << (itir_reg->ps - 12);
739e781c3d7SDavid Howells 		seq_printf(m,
7401da177e4SLinus Torvalds 			   "%cTR%lu: av=%d pv=%d dv=%d mv=%d\n"
7411da177e4SLinus Torvalds 			   "\tppn  : 0x%lx\n"
7421da177e4SLinus Torvalds 			   "\tvpn  : 0x%lx\n"
7431da177e4SLinus Torvalds 			   "\tps   : ",
7441da177e4SLinus Torvalds 			   "ID"[i], j,
7451da177e4SLinus Torvalds 			   tr_valid.pal_tr_valid_s.access_rights_valid,
7461da177e4SLinus Torvalds 			   tr_valid.pal_tr_valid_s.priv_level_valid,
7471da177e4SLinus Torvalds 			   tr_valid.pal_tr_valid_s.dirty_bit_valid,
7481da177e4SLinus Torvalds 			   tr_valid.pal_tr_valid_s.mem_attr_valid,
7491da177e4SLinus Torvalds 			   (gr_reg->ppn & pgm)<< 12, (ifa_reg->vpn & pgm)<< 12);
7501da177e4SLinus Torvalds 
751e781c3d7SDavid Howells 		bitvector_process(m, 1<< itir_reg->ps);
7521da177e4SLinus Torvalds 
753e781c3d7SDavid Howells 		seq_printf(m,
7541da177e4SLinus Torvalds 			   "\n\tpl   : %d\n"
7551da177e4SLinus Torvalds 			   "\tar   : %d\n"
7561da177e4SLinus Torvalds 			   "\trid  : %x\n"
7571da177e4SLinus Torvalds 			   "\tp    : %d\n"
7581da177e4SLinus Torvalds 			   "\tma   : %d\n"
7591da177e4SLinus Torvalds 			   "\td    : %d\n",
7601da177e4SLinus Torvalds 			   gr_reg->pl, gr_reg->ar, rid_reg->rid, gr_reg->p, gr_reg->ma,
7611da177e4SLinus Torvalds 			   gr_reg->d);
7621da177e4SLinus Torvalds 		}
7631da177e4SLinus Torvalds 	}
764e781c3d7SDavid Howells 	return 0;
7651da177e4SLinus Torvalds }
7661da177e4SLinus Torvalds 
7671da177e4SLinus Torvalds 
7681da177e4SLinus Torvalds 
7691da177e4SLinus Torvalds /*
7701da177e4SLinus Torvalds  * List {name,function} pairs for every entry in /proc/palinfo/cpu*
7711da177e4SLinus Torvalds  */
772e781c3d7SDavid Howells static const palinfo_entry_t palinfo_entries[]={
7731da177e4SLinus Torvalds 	{ "version_info",	version_info, },
7741da177e4SLinus Torvalds 	{ "vm_info",		vm_info, },
7751da177e4SLinus Torvalds 	{ "cache_info",		cache_info, },
7761da177e4SLinus Torvalds 	{ "power_info",		power_info, },
7771da177e4SLinus Torvalds 	{ "register_info",	register_info, },
7781da177e4SLinus Torvalds 	{ "processor_info",	processor_info, },
7791da177e4SLinus Torvalds 	{ "frequency_info",	frequency_info, },
7801da177e4SLinus Torvalds 	{ "bus_info",		bus_info },
7811da177e4SLinus Torvalds 	{ "tr_info",		tr_info, }
7821da177e4SLinus Torvalds };
7831da177e4SLinus Torvalds 
7841da177e4SLinus Torvalds #define NR_PALINFO_ENTRIES	(int) ARRAY_SIZE(palinfo_entries)
7851da177e4SLinus Torvalds 
7861da177e4SLinus Torvalds static struct proc_dir_entry *palinfo_dir;
7871da177e4SLinus Torvalds 
7881da177e4SLinus Torvalds /*
7891da177e4SLinus Torvalds  * This data structure is used to pass which cpu,function is being requested
7901da177e4SLinus Torvalds  * It must fit in a 64bit quantity to be passed to the proc callback routine
7911da177e4SLinus Torvalds  *
7921da177e4SLinus Torvalds  * In SMP mode, when we get a request for another CPU, we must call that
7931da177e4SLinus Torvalds  * other CPU using IPI and wait for the result before returning.
7941da177e4SLinus Torvalds  */
7951da177e4SLinus Torvalds typedef union {
7961da177e4SLinus Torvalds 	u64 value;
7971da177e4SLinus Torvalds 	struct {
7981da177e4SLinus Torvalds 		unsigned	req_cpu: 32;	/* for which CPU this info is */
7991da177e4SLinus Torvalds 		unsigned	func_id: 32;	/* which function is requested */
8001da177e4SLinus Torvalds 	} pal_func_cpu;
8011da177e4SLinus Torvalds } pal_func_cpu_u_t;
8021da177e4SLinus Torvalds 
8031da177e4SLinus Torvalds #define req_cpu	pal_func_cpu.req_cpu
8041da177e4SLinus Torvalds #define func_id pal_func_cpu.func_id
8051da177e4SLinus Torvalds 
8061da177e4SLinus Torvalds #ifdef CONFIG_SMP
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds /*
8091da177e4SLinus Torvalds  * used to hold information about final function to call
8101da177e4SLinus Torvalds  */
8111da177e4SLinus Torvalds typedef struct {
8121da177e4SLinus Torvalds 	palinfo_func_t	func;	/* pointer to function to call */
813e781c3d7SDavid Howells 	struct seq_file *m;	/* buffer to store results */
8141da177e4SLinus Torvalds 	int		ret;	/* return value from call */
8151da177e4SLinus Torvalds } palinfo_smp_data_t;
8161da177e4SLinus Torvalds 
8171da177e4SLinus Torvalds 
8181da177e4SLinus Torvalds /*
8191da177e4SLinus Torvalds  * this function does the actual final call and he called
8201da177e4SLinus Torvalds  * from the smp code, i.e., this is the palinfo callback routine
8211da177e4SLinus Torvalds  */
8221da177e4SLinus Torvalds static void
palinfo_smp_call(void * info)8231da177e4SLinus Torvalds palinfo_smp_call(void *info)
8241da177e4SLinus Torvalds {
8251da177e4SLinus Torvalds 	palinfo_smp_data_t *data = (palinfo_smp_data_t *)info;
826e781c3d7SDavid Howells 	data->ret = (*data->func)(data->m);
8271da177e4SLinus Torvalds }
8281da177e4SLinus Torvalds 
8291da177e4SLinus Torvalds /*
8301da177e4SLinus Torvalds  * function called to trigger the IPI, we need to access a remote CPU
8311da177e4SLinus Torvalds  * Return:
8321da177e4SLinus Torvalds  *	0 : error or nothing to output
8331da177e4SLinus Torvalds  *	otherwise how many bytes in the "page" buffer were written
8341da177e4SLinus Torvalds  */
8351da177e4SLinus Torvalds static
palinfo_handle_smp(struct seq_file * m,pal_func_cpu_u_t * f)836e781c3d7SDavid Howells int palinfo_handle_smp(struct seq_file *m, pal_func_cpu_u_t *f)
8371da177e4SLinus Torvalds {
8381da177e4SLinus Torvalds 	palinfo_smp_data_t ptr;
8391da177e4SLinus Torvalds 	int ret;
8401da177e4SLinus Torvalds 
8411da177e4SLinus Torvalds 	ptr.func = palinfo_entries[f->func_id].proc_read;
842e781c3d7SDavid Howells 	ptr.m = m;
8431da177e4SLinus Torvalds 	ptr.ret  = 0; /* just in case */
8441da177e4SLinus Torvalds 
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds 	/* will send IPI to other CPU and wait for completion of remote call */
8478691e5a8SJens Axboe 	if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 1))) {
8481da177e4SLinus Torvalds 		printk(KERN_ERR "palinfo: remote CPU call from %d to %d on function %d: "
8491da177e4SLinus Torvalds 		       "error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret);
8501da177e4SLinus Torvalds 		return 0;
8511da177e4SLinus Torvalds 	}
8521da177e4SLinus Torvalds 	return ptr.ret;
8531da177e4SLinus Torvalds }
8541da177e4SLinus Torvalds #else /* ! CONFIG_SMP */
8551da177e4SLinus Torvalds static
palinfo_handle_smp(struct seq_file * m,pal_func_cpu_u_t * f)856e781c3d7SDavid Howells int palinfo_handle_smp(struct seq_file *m, pal_func_cpu_u_t *f)
8571da177e4SLinus Torvalds {
8581da177e4SLinus Torvalds 	printk(KERN_ERR "palinfo: should not be called with non SMP kernel\n");
8591da177e4SLinus Torvalds 	return 0;
8601da177e4SLinus Torvalds }
8611da177e4SLinus Torvalds #endif /* CONFIG_SMP */
8621da177e4SLinus Torvalds 
8631da177e4SLinus Torvalds /*
8641da177e4SLinus Torvalds  * Entry point routine: all calls go through this function
8651da177e4SLinus Torvalds  */
proc_palinfo_show(struct seq_file * m,void * v)866e781c3d7SDavid Howells static int proc_palinfo_show(struct seq_file *m, void *v)
8671da177e4SLinus Torvalds {
868e781c3d7SDavid Howells 	pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&m->private;
8691da177e4SLinus Torvalds 
8701da177e4SLinus Torvalds 	/*
8711da177e4SLinus Torvalds 	 * in SMP mode, we may need to call another CPU to get correct
8721da177e4SLinus Torvalds 	 * information. PAL, by definition, is processor specific
8731da177e4SLinus Torvalds 	 */
8741da177e4SLinus Torvalds 	if (f->req_cpu == get_cpu())
875e781c3d7SDavid Howells 		(*palinfo_entries[f->func_id].proc_read)(m);
8761da177e4SLinus Torvalds 	else
877e781c3d7SDavid Howells 		palinfo_handle_smp(m, f);
8781da177e4SLinus Torvalds 
8791da177e4SLinus Torvalds 	put_cpu();
880e781c3d7SDavid Howells 	return 0;
8811da177e4SLinus Torvalds }
8821da177e4SLinus Torvalds 
palinfo_add_proc(unsigned int cpu)883715c3211SSebastian Andrzej Siewior static int palinfo_add_proc(unsigned int cpu)
8841da177e4SLinus Torvalds {
8851da177e4SLinus Torvalds 	pal_func_cpu_u_t f;
8861da177e4SLinus Torvalds 	struct proc_dir_entry *cpu_dir;
8871da177e4SLinus Torvalds 	int j;
888ccf93204SAl Viro 	char cpustr[3+4+1];	/* cpu numbers are up to 4095 on itanic */
889ccf93204SAl Viro 	sprintf(cpustr, "cpu%d", cpu);
8901da177e4SLinus Torvalds 
8911da177e4SLinus Torvalds 	cpu_dir = proc_mkdir(cpustr, palinfo_dir);
892ccf93204SAl Viro 	if (!cpu_dir)
893715c3211SSebastian Andrzej Siewior 		return -EINVAL;
8941da177e4SLinus Torvalds 
8951da177e4SLinus Torvalds 	f.req_cpu = cpu;
8961da177e4SLinus Torvalds 
8971da177e4SLinus Torvalds 	for (j=0; j < NR_PALINFO_ENTRIES; j++) {
8981da177e4SLinus Torvalds 		f.func_id = j;
8993f3942acSChristoph Hellwig 		proc_create_single_data(palinfo_entries[j].name, 0, cpu_dir,
9003f3942acSChristoph Hellwig 				proc_palinfo_show, (void *)f.value);
9011da177e4SLinus Torvalds 	}
902715c3211SSebastian Andrzej Siewior 	return 0;
9031da177e4SLinus Torvalds }
9041da177e4SLinus Torvalds 
palinfo_del_proc(unsigned int hcpu)905715c3211SSebastian Andrzej Siewior static int palinfo_del_proc(unsigned int hcpu)
9061da177e4SLinus Torvalds {
907ccf93204SAl Viro 	char cpustr[3+4+1];	/* cpu numbers are up to 4095 on itanic */
908715c3211SSebastian Andrzej Siewior 
909ccf93204SAl Viro 	sprintf(cpustr, "cpu%d", hcpu);
910ccf93204SAl Viro 	remove_proc_subtree(cpustr, palinfo_dir);
911715c3211SSebastian Andrzej Siewior 	return 0;
9121da177e4SLinus Torvalds }
9131da177e4SLinus Torvalds 
914715c3211SSebastian Andrzej Siewior static enum cpuhp_state hp_online;
9151da177e4SLinus Torvalds 
palinfo_init(void)916715c3211SSebastian Andrzej Siewior static int __init palinfo_init(void)
9171da177e4SLinus Torvalds {
9181da177e4SLinus Torvalds 	int i = 0;
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds 	printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);
9211da177e4SLinus Torvalds 	palinfo_dir = proc_mkdir("pal", NULL);
922ccf93204SAl Viro 	if (!palinfo_dir)
923ccf93204SAl Viro 		return -ENOMEM;
9241da177e4SLinus Torvalds 
925715c3211SSebastian Andrzej Siewior 	i = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "ia64/palinfo:online",
926715c3211SSebastian Andrzej Siewior 			      palinfo_add_proc, palinfo_del_proc);
927715c3211SSebastian Andrzej Siewior 	if (i < 0) {
928715c3211SSebastian Andrzej Siewior 		remove_proc_subtree("pal", NULL);
929715c3211SSebastian Andrzej Siewior 		return i;
9301da177e4SLinus Torvalds 	}
931715c3211SSebastian Andrzej Siewior 	hp_online = i;
9321da177e4SLinus Torvalds 	return 0;
9331da177e4SLinus Torvalds }
9341da177e4SLinus Torvalds 
palinfo_exit(void)935715c3211SSebastian Andrzej Siewior static void __exit palinfo_exit(void)
9361da177e4SLinus Torvalds {
937715c3211SSebastian Andrzej Siewior 	cpuhp_remove_state(hp_online);
938ccf93204SAl Viro 	remove_proc_subtree("pal", NULL);
9391da177e4SLinus Torvalds }
9401da177e4SLinus Torvalds 
9411da177e4SLinus Torvalds module_init(palinfo_init);
9421da177e4SLinus Torvalds module_exit(palinfo_exit);
943