cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

palinfo.c (24403B)


      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
     40MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
     41MODULE_DESCRIPTION("/proc interface to IA-64 PAL");
     42MODULE_LICENSE("GPL");
     43
     44#define PALINFO_VERSION "0.5"
     45
     46typedef int (*palinfo_func_t)(struct seq_file *);
     47
     48typedef 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
     59static const char *cache_types[] = {
     60	"",			/* not used */
     61	"Instruction",
     62	"Data",
     63	"Data/Instruction"	/* unified */
     64};
     65
     66static const char *cache_mattrib[]={
     67	"WriteThrough",
     68	"WriteBack",
     69	"",		/* reserved */
     70	""		/* reserved */
     71};
     72
     73static 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
     84static 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
     95static 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
    104static 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 */
    127static 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 */
    151static 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
    183static 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
    212static 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
    290static 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
    420static 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
    459static 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
    491static 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
    511static 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
    519static 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
    552static 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
    575static 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
    601static 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
    627static 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
    651static 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
    671static 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 */
    772static 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
    786static 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 */
    795typedef 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 */
    811typedef 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 */
    822static void
    823palinfo_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 */
    835static
    836int 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 */
    855static
    856int 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 */
    866static 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
    883static 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
    905static 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
    914static enum cpuhp_state hp_online;
    915
    916static 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
    935static void __exit palinfo_exit(void)
    936{
    937	cpuhp_remove_state(hp_online);
    938	remove_proc_subtree("pal", NULL);
    939}
    940
    941module_init(palinfo_init);
    942module_exit(palinfo_exit);