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, ®_info[0], ®_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