/*
* palinfo.c
*
* Prints processor specific information reported by PAL.
* This code is based on specification of PAL as of the
* Intel IA-64 Architecture Software Developer's Manual v1.0.
*
*
* Copyright (C) 2000-2001, 2003 Hewlett-Packard Co
* Stephane Eranian <eranian@hpl.hp.com>
* Copyright (C) 2004 Intel Corporation
* Ashok Raj <ashok.raj@intel.com>
*
* 05/26/2000 S.Eranian initial release
* 08/21/2000 S.Eranian updated to July 2000 PAL specs
* 02/05/2001 S.Eranian fixed module support
* 10/23/2001 S.Eranian updated pal_perf_mon_info bug fixes
* 03/24/2004 Ashok Raj updated to work with CPU Hotplug
* 10/26/2006 Russ Anderson updated processor features to rev 2.2 spec
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/efi.h>
#include <linux/notifier.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <asm/pal.h>
#include <asm/sal.h>
#include <asm/page.h>
#include <asm/processor.h>
#include <linux/smp.h>
MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
MODULE_DESCRIPTION("/proc interface to IA-64 PAL");
MODULE_LICENSE("GPL");
#define PALINFO_VERSION "0.5"
typedef int (*palinfo_func_t)(struct seq_file *);
typedef struct {
const char *name; /* name of the proc entry */
palinfo_func_t proc_read; /* function to call for reading */
struct proc_dir_entry *entry; /* registered entry (removal) */
} palinfo_entry_t;
/*
* A bunch of string array to get pretty printing
*/
static const char *cache_types[] = {
"", /* not used */
"Instruction",
"Data",
"Data/Instruction" /* unified */
};
static const char *cache_mattrib[]={
"WriteThrough",
"WriteBack",
"", /* reserved */
"" /* reserved */
};
static const char *cache_st_hints[]={
"Temporal, level 1",
"Reserved",
"Reserved",
"Non-temporal, all levels",
"Reserved",
"Reserved",
"Reserved",
"Reserved"
};
static const char *cache_ld_hints[]={
"Temporal, level 1",
"Non-temporal, level 1",
"Reserved",
"Non-temporal, all levels",
"Reserved",
"Reserved",
"Reserved",
"Reserved"
};
static const char *rse_hints[]={
"enforced lazy",
"eager stores",
"eager loads",
"eager loads and stores"
};
#define RSE_HINTS_COUNT ARRAY_SIZE(rse_hints)
static const char *mem_attrib[]={
"WB", /* 000 */
"SW", /* 001 */
"010", /* 010 */
"011", /* 011 */
"UC", /* 100 */
"UCE", /* 101 */
"WC", /* 110 */
"NaTPage" /* 111 */
};
/*
* Take a 64bit vector and produces a string such that
* if bit n is set then 2^n in clear text is generated. The adjustment
* to the right unit is also done.
*
* Input:
* - a pointer to a buffer to hold the string
* - a 64-bit vector
* Ouput:
* - a pointer to the end of the buffer
*
*/
static void bitvector_process(struct seq_file *m, u64 vector)
{
int i,j;
static const char *units[]={ "", "K", "M", "G", "T" };
for (i=0, j=0; i < 64; i++ , j=i/10) {
if (vector & 0x1)
seq_printf(m, "%d%s ", 1 << (i-j*10), units[j]);
vector >>= 1;
}
}
/*
* Take a 64bit vector and produces a string such that
* if bit n is set then register n is present. The function
* takes into account consecutive registers and prints out ranges.
*
* Input:
* - a pointer to a buffer to hold the string
* - a 64-bit vector
* Ouput:
* - a pointer to the end of the buffer
*
*/
static void bitregister_process(struct seq_file *m, u64 *reg_info, int max)
{
int i, begin, skip = 0;
u64 value = reg_info[0];
value >>= i = begin = ffs(value) - 1;
for(; i < max; i++ ) {
if (i != 0 && (i%64) == 0) value = *++reg_info;
if ((value & 0x1) == 0 && skip == 0) {
if (begin <= i - 2)
seq_printf(m, "%d-%d ", begin, i-1);
else
seq_printf(m, "%d ", i-1);
skip = 1;
begin = -1;
} else if ((value & 0x1) && skip == 1) {
skip = 0;
begin = i;
}
value >>=1;
}
if (begin > -1) {
if (begin < 127)
seq_printf(m, "%d-127", begin);
else
seq_puts(m, "127");
}
}
static int