Commit 30ffc51d authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Cleanup ppc64 procfs code

From: Anton Blanchard <anton@samba.org>

Cleanup ppc64 procfs code:

- Use initcalls everywhere. This allowed us to remove the iseries proc
  callback interface.
- Kill proc_pmc.c. Most of it wasnt used (and we are planning to export the
  PMCs via sysfs). The few things left were iseries specific so they
  got moved into iSeries_proc.c.
- Kill pmc.c. We dont use those statistics and the ones that are left
  can be gained via PMCs.
- Create /proc/iSeries and /proc/ppc64 very early. This means we no
  longer have to call proc_ppc64_init in all the drivers, we can
  assume its there.
- Fix some error return cases in rtas-proc.c and rtas-flash
- Dont even try some pseries specific drivers on pmac.
parent 7836b827
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/init.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/bitops.h> #include <asm/bitops.h>
...@@ -194,18 +195,18 @@ int check_location (char *c, int idx, char * buf); ...@@ -194,18 +195,18 @@ int check_location (char *c, int idx, char * buf);
/* ****************************************************************** */ /* ****************************************************************** */
/* MAIN */ /* MAIN */
/* ****************************************************************** */ /* ****************************************************************** */
void proc_rtas_init(void) static int __init proc_rtas_init(void)
{ {
struct proc_dir_entry *entry; struct proc_dir_entry *entry;
rtas = find_devices("rtas"); rtas = find_devices("rtas");
if ((rtas == 0) || (_machine != _MACH_chrp)) { if ((rtas == 0) || (_machine != _MACH_chrp)) {
return; return 1;
} }
proc_rtas = proc_mkdir("rtas", 0); proc_rtas = proc_mkdir("rtas", 0);
if (proc_rtas == 0) if (proc_rtas == 0)
return; return 1;
/* /proc/rtas entries */ /* /proc/rtas entries */
...@@ -226,7 +227,10 @@ void proc_rtas_init(void) ...@@ -226,7 +227,10 @@ void proc_rtas_init(void)
entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas); entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_rtas);
if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations; if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations;
return 0;
} }
__initcall(proc_rtas_init);
/* ****************************************************************** */ /* ****************************************************************** */
/* POWER-ON-TIME */ /* POWER-ON-TIME */
......
...@@ -9,7 +9,7 @@ obj-y := setup.o entry.o traps.o irq.o idle.o dma.o \ ...@@ -9,7 +9,7 @@ obj-y := setup.o entry.o traps.o irq.o idle.o dma.o \
time.o process.o signal.o syscalls.o misc.o ptrace.o \ time.o process.o signal.o syscalls.o misc.o ptrace.o \
align.o semaphore.o bitops.o stab.o pacaData.o \ align.o semaphore.o bitops.o stab.o pacaData.o \
udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \
ptrace32.o signal32.o pmc.o rtc.o init_task.o \ ptrace32.o signal32.o rtc.o init_task.o \
lmb.o cputable.o cpu_setup_power4.o idle_power4.o \ lmb.o cputable.o cpu_setup_power4.o idle_power4.o \
iommu.o iommu.o
...@@ -29,7 +29,7 @@ obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \ ...@@ -29,7 +29,7 @@ obj-$(CONFIG_PPC_ISERIES) += iSeries_irq.o \
HvCall.o HvLpConfig.o LparData.o mf_proc.o \ HvCall.o HvLpConfig.o LparData.o mf_proc.o \
iSeries_setup.o ItLpQueue.o hvCall.o \ iSeries_setup.o ItLpQueue.o hvCall.o \
mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \
proc_pmc.o iSeries_iommu.o iSeries_iommu.o
obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \
eeh.o nvram.o pSeries_nvram.o rtasd.o ras.o \ eeh.o nvram.o pSeries_nvram.o rtasd.o ras.o \
......
/* /*
* iSeries_proc.c * iSeries_proc.c
* Copyright (C) 2001 Kyle A. Lucke IBM Corporation * Copyright (C) 2001 Kyle A. Lucke IBM Corporation
* * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by * This program is free software; you can redistribute it and/or modify
* the Free Software Foundation; either version 2 of the License, or * it under the terms of the GNU General Public License as published by
* (at your option) any later version. * the Free Software Foundation; either version 2 of the License, or
* * (at your option) any later version.
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of * This program is distributed in the hope that it will be useful,
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * but WITHOUT ANY WARRANTY; without even the implied warranty of
* GNU General Public License for more details. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software * You should have received a copy of the GNU General Public License
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * along with this program; if not, write to the Free Software
*/ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <linux/proc_fs.h> */
#include <linux/spinlock.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/paca.h>
#include <asm/processor.h>
#include <asm/time.h>
#include <asm/naca.h>
#include <asm/iSeries/ItLpPaca.h>
#include <asm/iSeries/ItLpQueue.h>
#include <asm/iSeries/HvCallXm.h>
#include <asm/iSeries/IoHriMainStore.h>
#include <asm/iSeries/LparData.h>
#include <asm/iSeries/iSeries_proc.h> #include <asm/iSeries/iSeries_proc.h>
static struct proc_dir_entry *iSeries_proc_root; static int __init iseries_proc_create(void)
static int iSeries_proc_initializationDone; {
static spinlock_t iSeries_proc_lock; struct proc_dir_entry *e = proc_mkdir("iSeries", 0);
if (!e)
return 1;
struct iSeries_proc_registration { return 0;
struct iSeries_proc_registration *next; }
iSeriesProcFunction functionMember; core_initcall(iseries_proc_create);
static char *event_types[9] = {
"Hypervisor\t\t",
"Machine Facilities\t",
"Session Manager\t",
"SPD I/O\t\t",
"Virtual Bus\t\t",
"PCI I/O\t\t",
"RIO I/O\t\t",
"Virtual Lan\t\t",
"Virtual I/O\t\t"
}; };
struct iSeries_proc_registration preallocated[16]; static int proc_lpevents_show(struct seq_file *m, void *v)
#define MYQUEUETYPE(T) struct MYQueue##T
#define MYQUEUE(T) \
MYQUEUETYPE(T) \
{ \
struct T *head; \
struct T *tail; \
}
#define MYQUEUECTOR(q) do { (q)->head = NULL; (q)->tail = NULL; } while(0)
#define MYQUEUEENQ(q, p) \
do { \
(p)->next = NULL; \
if ((q)->head != NULL) { \
(q)->head->next = (p); \
(q)->head = (p); \
} else { \
(q)->tail = (q)->head = (p); \
} \
} while(0)
#define MYQUEUEDEQ(q,p) \
do { \
(p) = (q)->tail; \
if ((p) != NULL) { \
(q)->tail = (p)->next; \
(p)->next = NULL; \
} \
if ((q)->tail == NULL) \
(q)->head = NULL; \
} while(0)
MYQUEUE(iSeries_proc_registration);
typedef MYQUEUETYPE(iSeries_proc_registration) aQueue;
static aQueue iSeries_free;
static aQueue iSeries_queued;
void iSeries_proc_early_init(void)
{ {
int i = 0; unsigned int i;
unsigned long flags;
seq_printf(m, "LpEventQueue 0\n");
iSeries_proc_initializationDone = 0; seq_printf(m, " events processed:\t%lu\n",
spin_lock_init(&iSeries_proc_lock); (unsigned long)xItLpQueue.xLpIntCount);
MYQUEUECTOR(&iSeries_free);
MYQUEUECTOR(&iSeries_queued); for (i = 0; i < 9; ++i)
seq_printf(m, " %s %10lu\n", event_types[i],
spin_lock_irqsave(&iSeries_proc_lock, flags); (unsigned long)xItLpQueue.xLpIntCountByType[i]);
for (i = 0; i < 16; ++i)
MYQUEUEENQ(&iSeries_free, preallocated + i); seq_printf(m, "\n events processed by processor:\n");
spin_unlock_irqrestore(&iSeries_proc_lock, flags);
for_each_online_cpu(i)
seq_printf(m, " CPU%02d %10u\n", i, paca[i].lpEvent_count);
return 0;
} }
static int iSeries_proc_create(void) static int proc_lpevents_open(struct inode *inode, struct file *file)
{ {
unsigned long flags; return single_open(file, proc_lpevents_show, NULL);
struct iSeries_proc_registration *reg; }
printk("iSeries_proc: Creating /proc/iSeries\n"); static struct file_operations proc_lpevents_operations = {
.open = proc_lpevents_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
spin_lock_irqsave(&iSeries_proc_lock, flags); static unsigned long startTitan = 0;
iSeries_proc_root = proc_mkdir("iSeries", 0); static unsigned long startTb = 0;
if (!iSeries_proc_root)
goto out;
MYQUEUEDEQ(&iSeries_queued, reg); static int proc_titantod_show(struct seq_file *m, void *v)
while (reg != NULL) { {
(*(reg->functionMember))(iSeries_proc_root); unsigned long tb0, titan_tod;
MYQUEUEDEQ(&iSeries_queued, reg);
tb0 = get_tb();
titan_tod = HvCallXm_loadTod();
seq_printf(m, "Titan\n" );
seq_printf(m, " time base = %016lx\n", tb0);
seq_printf(m, " titan tod = %016lx\n", titan_tod);
seq_printf(m, " xProcFreq = %016x\n",
xIoHriProcessorVpd[0].xProcFreq);
seq_printf(m, " xTimeBaseFreq = %016x\n",
xIoHriProcessorVpd[0].xTimeBaseFreq);
seq_printf(m, " tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy);
seq_printf(m, " tb_ticks_per_usec = %lu\n", tb_ticks_per_usec);
if (!startTitan) {
startTitan = titan_tod;
startTb = tb0;
} else {
unsigned long titan_usec = (titan_tod - startTitan) >> 12;
unsigned long tb_ticks = (tb0 - startTb);
unsigned long titan_jiffies = titan_usec / (1000000/HZ);
unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ);
unsigned long titan_jiff_rem_usec = titan_usec - titan_jiff_usec;
unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy;
unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy;
unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks;
unsigned long tb_jiff_rem_usec = tb_jiff_rem_ticks / tb_ticks_per_usec;
unsigned long new_tb_ticks_per_jiffy = (tb_ticks * (1000000/HZ))/titan_usec;
seq_printf(m, " titan elapsed = %lu uSec\n", titan_usec);
seq_printf(m, " tb elapsed = %lu ticks\n", tb_ticks);
seq_printf(m, " titan jiffies = %lu.%04lu \n", titan_jiffies,
titan_jiff_rem_usec);
seq_printf(m, " tb jiffies = %lu.%04lu\n", tb_jiffies,
tb_jiff_rem_usec);
seq_printf(m, " new tb_ticks_per_jiffy = %lu\n",
new_tb_ticks_per_jiffy);
} }
iSeries_proc_initializationDone = 1;
out:
spin_unlock_irqrestore(&iSeries_proc_lock, flags);
return 0; return 0;
} }
arch_initcall(iSeries_proc_create); static int proc_titantod_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_titantod_show, NULL);
}
static struct file_operations proc_titantod_operations = {
.open = proc_titantod_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
void iSeries_proc_callback(iSeriesProcFunction initFunction) static int __init iseries_proc_init(void)
{ {
unsigned long flags; struct proc_dir_entry *e;
spin_lock_irqsave(&iSeries_proc_lock, flags); e = create_proc_entry("iSeries/lpevents", S_IFREG|S_IRUGO, NULL);
if (iSeries_proc_initializationDone) if (e)
(*initFunction)(iSeries_proc_root); e->proc_fops = &proc_lpevents_operations;
else {
struct iSeries_proc_registration *reg = NULL; e = create_proc_entry("iSeries/titanTod", S_IFREG|S_IRUGO, NULL);
if (e)
MYQUEUEDEQ(&iSeries_free, reg); e->proc_fops = &proc_titantod_operations;
if (reg != NULL) {
reg->functionMember = initFunction; return 0;
MYQUEUEENQ(&iSeries_queued, reg);
} else
printk("Couldn't get a queue entry\n");
}
spin_unlock_irqrestore(&iSeries_proc_lock, flags);
} }
EXPORT_SYMBOL(iSeries_proc_callback); __initcall(iseries_proc_init);
...@@ -51,7 +51,6 @@ ...@@ -51,7 +51,6 @@
#include <asm/iSeries/ItLpQueue.h> #include <asm/iSeries/ItLpQueue.h>
#include <asm/iSeries/IoHriMainStore.h> #include <asm/iSeries/IoHriMainStore.h>
#include <asm/iSeries/iSeries_proc.h> #include <asm/iSeries/iSeries_proc.h>
#include <asm/proc_pmc.h>
#include <asm/iSeries/mf.h> #include <asm/iSeries/mf.h>
/* Function Prototypes */ /* Function Prototypes */
...@@ -393,12 +392,9 @@ void __init iSeries_init(unsigned long r3, unsigned long r4, unsigned long r5, ...@@ -393,12 +392,9 @@ void __init iSeries_init(unsigned long r3, unsigned long r4, unsigned long r5,
iSeries_setup_dprofile(); iSeries_setup_dprofile();
iSeries_proc_early_init();
mf_init(); mf_init();
mf_initialized = 1; mf_initialized = 1;
mb(); mb();
iSeries_proc_callback(&pmc_proc_init);
} }
/* /*
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include <asm/nvram.h> #include <asm/nvram.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/iSeries/ItSpCommArea.h> #include <asm/iSeries/ItSpCommArea.h>
#include <asm/iSeries/iSeries_proc.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/bcd.h> #include <linux/bcd.h>
...@@ -683,8 +682,6 @@ void mf_init(void) ...@@ -683,8 +682,6 @@ void mf_init(void)
/* initialization complete */ /* initialization complete */
printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities initialized\n"); printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities initialized\n");
iSeries_proc_callback(&mf_proc_init);
} }
void mf_setSide(char side) void mf_setSide(char side)
......
...@@ -16,11 +16,10 @@ ...@@ -16,11 +16,10 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/init.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/iSeries/mf.h> #include <asm/iSeries/mf.h>
static struct proc_dir_entry *mf_proc_root = NULL;
static int proc_mf_dump_cmdline(char *page, char **start, off_t off, static int proc_mf_dump_cmdline(char *page, char **start, off_t off,
int count, int *eof, void *data) int count, int *eof, void *data)
{ {
...@@ -187,27 +186,28 @@ static int proc_mf_change_vmlinux(struct file *file, const char *buffer, ...@@ -187,27 +186,28 @@ static int proc_mf_change_vmlinux(struct file *file, const char *buffer,
return count; return count;
} }
void mf_proc_init(struct proc_dir_entry *iSeries_proc) static int __init mf_proc_init(void)
{ {
struct proc_dir_entry *mf_proc_root;
struct proc_dir_entry *ent; struct proc_dir_entry *ent;
struct proc_dir_entry *mf; struct proc_dir_entry *mf;
char name[2]; char name[2];
int i; int i;
mf_proc_root = proc_mkdir("mf", iSeries_proc); mf_proc_root = proc_mkdir("iSeries/mf", NULL);
if (!mf_proc_root) if (!mf_proc_root)
return; return 1;
name[1] = '\0'; name[1] = '\0';
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
name[0] = 'A' + i; name[0] = 'A' + i;
mf = proc_mkdir(name, mf_proc_root); mf = proc_mkdir(name, mf_proc_root);
if (!mf) if (!mf)
return; return 1;
ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf); ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf);
if (!ent) if (!ent)
return; return 1;
ent->nlink = 1; ent->nlink = 1;
ent->data = (void *)(long)i; ent->data = (void *)(long)i;
ent->read_proc = proc_mf_dump_cmdline; ent->read_proc = proc_mf_dump_cmdline;
...@@ -218,7 +218,7 @@ void mf_proc_init(struct proc_dir_entry *iSeries_proc) ...@@ -218,7 +218,7 @@ void mf_proc_init(struct proc_dir_entry *iSeries_proc)
ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf); ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf);
if (!ent) if (!ent)
return; return 1;
ent->nlink = 1; ent->nlink = 1;
ent->data = (void *)(long)i; ent->data = (void *)(long)i;
#if 0 #if 0
...@@ -239,7 +239,7 @@ void mf_proc_init(struct proc_dir_entry *iSeries_proc) ...@@ -239,7 +239,7 @@ void mf_proc_init(struct proc_dir_entry *iSeries_proc)
ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
if (!ent) if (!ent)
return; return 1;
ent->nlink = 1; ent->nlink = 1;
ent->data = (void *)0; ent->data = (void *)0;
ent->read_proc = proc_mf_dump_side; ent->read_proc = proc_mf_dump_side;
...@@ -247,9 +247,13 @@ void mf_proc_init(struct proc_dir_entry *iSeries_proc) ...@@ -247,9 +247,13 @@ void mf_proc_init(struct proc_dir_entry *iSeries_proc)
ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
if (!ent) if (!ent)
return; return 1;
ent->nlink = 1; ent->nlink = 1;
ent->data = (void *)0; ent->data = (void *)0;
ent->read_proc = proc_mf_dump_src; ent->read_proc = proc_mf_dump_src;
ent->write_proc = proc_mf_change_src; ent->write_proc = proc_mf_change_src;
return 0;
} }
__initcall(mf_proc_init);
/*
* pmc.c
* Copyright (C) 2001 Dave Engebretsen & Mike Corrigan IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Change Activity:
* 2001/06/05 : engebret : Created.
* End Change Activity
*/
#include <asm/proc_fs.h>
#include <asm/paca.h>
#include <asm/iSeries/ItLpPaca.h>
#include <asm/iSeries/ItLpQueue.h>
#include <asm/processor.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <asm/pmc.h>
#include <asm/uaccess.h>
#include <asm/naca.h>
struct _pmc_sw pmc_sw_system = {
0
};
struct _pmc_sw pmc_sw_cpu[NR_CPUS] = {
{0 },
};
/*
* Provide enough storage for either system level counters or
* one cpu's counters.
*/
struct _pmc_sw_text pmc_sw_text;
struct _pmc_hw_text pmc_hw_text;
char *
ppc64_pmc_stab(int file)
{
int n;
unsigned long stab_faults, stab_capacity_castouts, stab_invalidations;
unsigned long i;
stab_faults = stab_capacity_castouts = stab_invalidations = n = 0;
if (file == -1) {
for (i = 0; i < NR_CPUS; i++) {
if (!cpu_online(i))
continue;
stab_faults += pmc_sw_cpu[i].stab_faults;
stab_capacity_castouts += pmc_sw_cpu[i].stab_capacity_castouts;
stab_invalidations += pmc_sw_cpu[i].stab_invalidations;
}
n += sprintf(pmc_sw_text.buffer + n,
"Faults 0x%lx\n", stab_faults);
n += sprintf(pmc_sw_text.buffer + n,
"Castouts 0x%lx\n", stab_capacity_castouts);
n += sprintf(pmc_sw_text.buffer + n,
"Invalidations 0x%lx\n", stab_invalidations);
} else {
n += sprintf(pmc_sw_text.buffer + n,
"Faults 0x%lx\n",
pmc_sw_cpu[file].stab_faults);
n += sprintf(pmc_sw_text.buffer + n,
"Castouts 0x%lx\n",
pmc_sw_cpu[file].stab_capacity_castouts);
n += sprintf(pmc_sw_text.buffer + n,
"Invalidations 0x%lx\n",
pmc_sw_cpu[file].stab_invalidations);
for (i = 0; i < STAB_ENTRY_MAX; i++) {
if (pmc_sw_cpu[file].stab_entry_use[i]) {
n += sprintf(pmc_sw_text.buffer + n,
"Entry %02ld 0x%lx\n", i,
pmc_sw_cpu[file].stab_entry_use[i]);
}
}
}
return(pmc_sw_text.buffer);
}
char *
ppc64_pmc_htab(int file)
{
int n;
unsigned long htab_primary_overflows, htab_capacity_castouts;
unsigned long htab_read_to_write_faults;
htab_primary_overflows = htab_capacity_castouts = 0;
htab_read_to_write_faults = n = 0;
if (file == -1) {
n += sprintf(pmc_sw_text.buffer + n,
"Primary Overflows 0x%lx\n",
pmc_sw_system.htab_primary_overflows);
n += sprintf(pmc_sw_text.buffer + n,
"Castouts 0x%lx\n",
pmc_sw_system.htab_capacity_castouts);
} else {
n += sprintf(pmc_sw_text.buffer + n,
"Primary Overflows N/A\n");
n += sprintf(pmc_sw_text.buffer + n,
"Castouts N/A\n\n");
}
return(pmc_sw_text.buffer);
}
char *
ppc64_pmc_hw(int file)
{
int n;
n = 0;
if (file == -1) {
n += sprintf(pmc_hw_text.buffer + n, "Not Implemented\n");
} else {
n += sprintf(pmc_hw_text.buffer + n,
"MMCR0 0x%lx\n", mfspr(MMCR0));
n += sprintf(pmc_hw_text.buffer + n,
"MMCR1 0x%lx\n", mfspr(MMCR1));
#if 0
n += sprintf(pmc_hw_text.buffer + n,
"MMCRA 0x%lx\n", mfspr(MMCRA));
#endif
n += sprintf(pmc_hw_text.buffer + n,
"PMC1 0x%lx\n", mfspr(PMC1));
n += sprintf(pmc_hw_text.buffer + n,
"PMC2 0x%lx\n", mfspr(PMC2));
n += sprintf(pmc_hw_text.buffer + n,
"PMC3 0x%lx\n", mfspr(PMC3));
n += sprintf(pmc_hw_text.buffer + n,
"PMC4 0x%lx\n", mfspr(PMC4));
n += sprintf(pmc_hw_text.buffer + n,
"PMC5 0x%lx\n", mfspr(PMC5));
n += sprintf(pmc_hw_text.buffer + n,
"PMC6 0x%lx\n", mfspr(PMC6));
n += sprintf(pmc_hw_text.buffer + n,
"PMC7 0x%lx\n", mfspr(PMC7));
n += sprintf(pmc_hw_text.buffer + n,
"PMC8 0x%lx\n", mfspr(PMC8));
}
return(pmc_hw_text.buffer);
}
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#include <asm/hw_irq.h> #include <asm/hw_irq.h>
#include <asm/abs_addr.h> #include <asm/abs_addr.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/proc_fs.h>
#ifdef CONFIG_PPC_ISERIES #ifdef CONFIG_PPC_ISERIES
#include <asm/iSeries/HvCallSc.h> #include <asm/iSeries/HvCallSc.h>
#endif #endif
...@@ -164,6 +163,5 @@ EXPORT_SYMBOL(console_drivers); ...@@ -164,6 +163,5 @@ EXPORT_SYMBOL(console_drivers);
EXPORT_SYMBOL(tb_ticks_per_usec); EXPORT_SYMBOL(tb_ticks_per_usec);
EXPORT_SYMBOL(paca); EXPORT_SYMBOL(paca);
EXPORT_SYMBOL(proc_ppc64);
EXPORT_SYMBOL(cur_cpu_spec); EXPORT_SYMBOL(cur_cpu_spec);
EXPORT_SYMBOL(systemcfg); EXPORT_SYMBOL(systemcfg);
/*
* proc_pmc.c
* Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Change Activity:
* 2001 : mikec : Created
* 2001/06/05 : engebret : Software event count support.
* End Change Activity
*/
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <asm/proc_fs.h>
#include <asm/paca.h>
#include <asm/iSeries/ItLpPaca.h>
#include <asm/iSeries/ItLpQueue.h>
#include <asm/iSeries/HvCallXm.h>
#include <asm/iSeries/IoHriMainStore.h>
#include <asm/processor.h>
#include <asm/time.h>
#include <asm/iSeries/LparData.h>
#include <asm/pmc.h>
#include <asm/uaccess.h>
#include <asm/naca.h>
#include <asm/rtas.h>
static int proc_pmc_control_mode = 0;
static struct proc_dir_entry *proc_ppc64_pmc_system_root = NULL;
static struct proc_dir_entry *proc_ppc64_pmc_cpu_root[NR_CPUS] = {NULL, };
static spinlock_t proc_ppc64_lock;
int proc_ppc64_pmc_find_file(void *data);
int proc_ppc64_pmc_read(char *page, char **start, off_t off,
int count, int *eof, char *buffer);
int proc_ppc64_pmc_stab_read(char *page, char **start, off_t off,
int count, int *eof, void *data);
int proc_ppc64_pmc_htab_read(char *page, char **start, off_t off,
int count, int *eof, void *data);
int proc_ppc64_pmc_hw_read(char *page, char **start, off_t off,
int count, int *eof, void *data);
static struct proc_dir_entry *pmc_proc_root = NULL;
int proc_get_lpevents( char *page, char **start, off_t off, int count, int *eof, void *data);
int proc_reset_lpevents( struct file *file, const char *buffer, unsigned long count, void *data);
int proc_get_titanTod( char *page, char **start, off_t off, int count, int *eof, void *data);
int proc_pmc_get_control( char *page, char **start, off_t off, int count, int *eof, void *data);
int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data);
int proc_pmc_set_mmcr0( struct file *file, const char *buffer, unsigned long count, void *data);
int proc_pmc_set_mmcr1( struct file *file, const char *buffer, unsigned long count, void *data);
int proc_pmc_set_mmcra( struct file *file, const char *buffer, unsigned long count, void *data);
int proc_pmc_set_pmc1( struct file *file, const char *buffer, unsigned long count, void *data);
int proc_pmc_set_pmc2( struct file *file, const char *buffer, unsigned long count, void *data);
int proc_pmc_set_pmc3( struct file *file, const char *buffer, unsigned long count, void *data);
int proc_pmc_set_pmc4( struct file *file, const char *buffer, unsigned long count, void *data);
int proc_pmc_set_pmc5( struct file *file, const char *buffer, unsigned long count, void *data);
int proc_pmc_set_pmc6( struct file *file, const char *buffer, unsigned long count, void *data);
int proc_pmc_set_pmc7( struct file *file, const char *buffer, unsigned long count, void *data);
int proc_pmc_set_pmc8( struct file *file, const char *buffer, unsigned long count, void *data);
#if 0
int proc_ppc64_init(void)
{
unsigned long i;
struct proc_dir_entry *ent = NULL;
char buf[256];
printk("proc_ppc64: Creating /proc/ppc64/pmc\n");
/*
* Create the root, system, and cpu directories as follows:
* /proc/ppc64/pmc/system
* /proc/ppc64/pmc/cpu0
*/
spin_lock(&proc_ppc64_lock);
if (proc_ppc64.root == NULL) {
proc_ppc64_init();
if (!proc_ppc64.root) {
spin_unlock(&proc_ppc64_lock);
return;
}
}
spin_unlock(&proc_ppc64_lock);
/* Placeholder for rtas interfaces. */
if (proc_ppc64.rtas == NULL) {
return;
}
proc_ppc64_pmc_root = proc_mkdir("pmc", proc_ppc64.root);
proc_ppc64_pmc_system_root = proc_mkdir("system", proc_ppc64_pmc_root);
for (i = 0; i < NR_CPUS; i++) {
if (cpu_online(i)) {
sprintf(buf, "cpu%ld", i);
proc_ppc64_pmc_cpu_root[i] =
proc_mkdir(buf, proc_ppc64_pmc_root);
}
}
/* Create directories for the software counters. */
for (i = 0; i < NR_CPUS; i++) {
if (!cpu_online(i))
continue;
ent = create_proc_entry("stab", S_IRUGO | S_IWUSR,
proc_ppc64_pmc_cpu_root[i]);
if (ent) {
ent->nlink = 1;
ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
ent->read_proc = (void *)proc_ppc64_pmc_stab_read;
ent->write_proc = NULL;
}
ent = create_proc_entry("htab", S_IRUGO | S_IWUSR,
proc_ppc64_pmc_cpu_root[i]);
if (ent) {
ent->nlink = 1;
ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
ent->read_proc = (void *)proc_ppc64_pmc_htab_read;
ent->write_proc = NULL;
}
}
ent = create_proc_entry("stab", S_IRUGO | S_IWUSR,
proc_ppc64_pmc_system_root);
if (ent) {
ent->nlink = 1;
ent->data = (void *)proc_ppc64_pmc_system_root;
ent->read_proc = (void *)proc_ppc64_pmc_stab_read;
ent->write_proc = NULL;
}
ent = create_proc_entry("htab", S_IRUGO | S_IWUSR,
proc_ppc64_pmc_system_root);
if (ent) {
ent->nlink = 1;
ent->data = (void *)proc_ppc64_pmc_system_root;
ent->read_proc = (void *)proc_ppc64_pmc_htab_read;
ent->write_proc = NULL;
}
/* Create directories for the hardware counters. */
for (i = 0; i < NR_CPUS; i++) {
if (!cpu_online(i))
continue;
ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR,
proc_ppc64_pmc_cpu_root[i]);
if (ent) {
ent->nlink = 1;
ent->data = (void *)proc_ppc64_pmc_cpu_root[i];
ent->read_proc = (void *)proc_ppc64_pmc_hw_read;
ent->write_proc = NULL;
}
}
ent = create_proc_entry("hardware", S_IRUGO | S_IWUSR,
proc_ppc64_pmc_system_root);
if (ent) {
ent->nlink = 1;
ent->data = (void *)proc_ppc64_pmc_system_root;
ent->read_proc = (void *)proc_ppc64_pmc_hw_read;
ent->write_proc = NULL;
}
}
#endif
/*
* Find the requested 'file' given a proc token.
*
* Inputs: void * data: proc token
* Output: int : (0, ..., +N) = CPU number.
* -1 = System.
*/
int proc_ppc64_pmc_find_file(void *data)
{
int i;
if ((unsigned long)data ==
(unsigned long) proc_ppc64_pmc_system_root) {
return(-1);
} else {
for (i = 0; i < NR_CPUS; i++) {
if (!cpu_online(i))
continue;
if ((unsigned long)data ==
(unsigned long)proc_ppc64_pmc_cpu_root[i]) {
return(i);
}
}
}
/* On error, just default to a type of system. */
printk("proc_ppc64_pmc_find_file: failed to find file token.\n");
return(-1);
}
int
proc_ppc64_pmc_read(char *page, char **start, off_t off,
int count, int *eof, char *buffer)
{
int buffer_size, n;
if (count < 0) return 0;
if (buffer == NULL) {
*eof = 1;
return 0;
}
/* Check for read beyond EOF */
buffer_size = n = strlen(buffer);
if (off >= buffer_size) {
*eof = 1;
return 0;
}
if (n > (buffer_size - off)) n = buffer_size - off;
/* Never return more than was requested */
if (n > count) {
n = count;
} else {
*eof = 1;
}
memcpy(page, buffer + off, n);
*start = page;
return n;
}
int
proc_ppc64_pmc_stab_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int n, file;
char *buffer = NULL;
if (count < 0) return 0;
spin_lock(&proc_ppc64_lock);
/* Figure out which file is being request. */
file = proc_ppc64_pmc_find_file(data);
/* Update the counters and the text buffer representation. */
buffer = ppc64_pmc_stab(file);
/* Put the data into the requestor's buffer. */
n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer);
spin_unlock(&proc_ppc64_lock);
return n;
}
int
proc_ppc64_pmc_htab_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int n, file;
char *buffer = NULL;
if (count < 0) return 0;
spin_lock(&proc_ppc64_lock);
/* Figure out which file is being request. */
file = proc_ppc64_pmc_find_file(data);
/* Update the counters and the text buffer representation. */
buffer = ppc64_pmc_htab(file);
/* Put the data into the requestor's buffer. */
n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer);
spin_unlock(&proc_ppc64_lock);
return n;
}
int
proc_ppc64_pmc_hw_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
int n, file;
char *buffer = NULL;
if (count < 0) return 0;
spin_lock(&proc_ppc64_lock);
/* Figure out which file is being request. */
file = proc_ppc64_pmc_find_file(data);
/* Update the counters and the text buffer representation. */
buffer = ppc64_pmc_hw(file);
/* Put the data into the requestor's buffer. */
n = proc_ppc64_pmc_read(page, start, off, count, eof, buffer);
spin_unlock(&proc_ppc64_lock);
return n;
}
/*
* DRENG the remainder of these functions still need work ...
*/
void pmc_proc_init(struct proc_dir_entry *iSeries_proc)
{
struct proc_dir_entry *ent = NULL;
ent = create_proc_entry("lpevents", S_IFREG|S_IRUGO, iSeries_proc);
if (!ent) return;
ent->nlink = 1;
ent->data = (void *)0;
ent->read_proc = proc_get_lpevents;
ent->write_proc = proc_reset_lpevents;
ent = create_proc_entry("titanTod", S_IFREG|S_IRUGO, iSeries_proc);
if (!ent) return;
ent->nlink = 1;
ent->data = (void *)0;
ent->size = 0;
ent->read_proc = proc_get_titanTod;
ent->write_proc = NULL;
pmc_proc_root = proc_mkdir("pmc", iSeries_proc);
if (!pmc_proc_root) return;
ent = create_proc_entry("control", S_IFREG|S_IRUSR|S_IWUSR, pmc_proc_root);
if (!ent) return;
ent->nlink = 1;
ent->data = (void *)0;
ent->read_proc = proc_pmc_get_control;
ent->write_proc = proc_pmc_set_control;
}
static int pmc_calc_metrics( char *page, char **start, off_t off, int count, int *eof, int len)
{
if ( len <= off+count)
*eof = 1;
*start = page+off;
len -= off;
if ( len > count )
len = count;
if ( len < 0 )
len = 0;
return len;
}
static char * lpEventTypes[9] = {
"Hypervisor\t\t",
"Machine Facilities\t",
"Session Manager\t",
"SPD I/O\t\t",
"Virtual Bus\t\t",
"PCI I/O\t\t",
"RIO I/O\t\t",
"Virtual Lan\t\t",
"Virtual I/O\t\t"
};
int proc_get_lpevents
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
unsigned i;
int len = 0;
len += sprintf( page+len, "LpEventQueue 0\n" );
len += sprintf( page+len, " events processed:\t%lu\n",
(unsigned long)xItLpQueue.xLpIntCount );
for (i=0; i<9; ++i) {
len += sprintf( page+len, " %s %10lu\n",
lpEventTypes[i],
(unsigned long)xItLpQueue.xLpIntCountByType[i] );
}
len += sprintf( page+len, "\n events processed by processor:\n" );
for (i = 0; i < NR_CPUS; ++i) {
if (cpu_online(i))
len += sprintf( page+len, " CPU%02d %10u\n",
i, paca[i].lpEvent_count );
}
return pmc_calc_metrics( page, start, off, count, eof, len );
}
int proc_reset_lpevents( struct file *file, const char *buffer, unsigned long count, void *data )
{
return count;
}
static unsigned long startTitan = 0;
static unsigned long startTb = 0;
int proc_get_titanTod
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len = 0;
unsigned long tb0, titan_tod;
tb0 = get_tb();
titan_tod = HvCallXm_loadTod();
len += sprintf( page+len, "Titan\n" );
len += sprintf( page+len, " time base = %016lx\n", tb0 );
len += sprintf( page+len, " titan tod = %016lx\n", titan_tod );
len += sprintf( page+len, " xProcFreq = %016x\n", xIoHriProcessorVpd[0].xProcFreq );
len += sprintf( page+len, " xTimeBaseFreq = %016x\n", xIoHriProcessorVpd[0].xTimeBaseFreq );
len += sprintf( page+len, " tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy );
len += sprintf( page+len, " tb_ticks_per_usec = %lu\n", tb_ticks_per_usec );
if ( !startTitan ) {
startTitan = titan_tod;
startTb = tb0;
}
else {
unsigned long titan_usec = (titan_tod - startTitan) >> 12;
unsigned long tb_ticks = (tb0 - startTb);
unsigned long titan_jiffies = titan_usec / (1000000/HZ);
unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ);
unsigned long titan_jiff_rem_usec = titan_usec - titan_jiff_usec;
unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy;
unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy;
unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks;
unsigned long tb_jiff_rem_usec = tb_jiff_rem_ticks / tb_ticks_per_usec;
unsigned long new_tb_ticks_per_jiffy = (tb_ticks * (1000000/HZ))/titan_usec;
len += sprintf( page+len, " titan elapsed = %lu uSec\n", titan_usec);
len += sprintf( page+len, " tb elapsed = %lu ticks\n", tb_ticks);
len += sprintf( page+len, " titan jiffies = %lu.%04lu \n", titan_jiffies, titan_jiff_rem_usec );
len += sprintf( page+len, " tb jiffies = %lu.%04lu\n", tb_jiffies, tb_jiff_rem_usec );
len += sprintf( page+len, " new tb_ticks_per_jiffy = %lu\n", new_tb_ticks_per_jiffy );
}
return pmc_calc_metrics( page, start, off, count, eof, len );
}
int proc_pmc_get_control
(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len = 0;
if ( proc_pmc_control_mode == PMC_CONTROL_CPI ) {
unsigned long mach_cycles = mfspr( PMC5 );
unsigned long inst_complete = mfspr( PMC4 );
unsigned long inst_dispatch = mfspr( PMC3 );
unsigned long thread_active_run = mfspr( PMC1 );
unsigned long thread_active = mfspr( PMC2 );
unsigned long cpi = 0;
unsigned long cpithou = 0;
unsigned long remain;
if ( inst_complete ) {
cpi = thread_active_run / inst_complete;
remain = thread_active_run % inst_complete;
if ( inst_complete > 1000000 )
cpithou = remain / ( inst_complete / 1000 );
else
cpithou = ( remain * 1000 ) / inst_complete;
}
len += sprintf( page+len, "PMC CPI Mode\nRaw Counts\n" );
len += sprintf( page+len, "machine cycles : %12lu\n", mach_cycles );
len += sprintf( page+len, "thread active cycles : %12lu\n\n", thread_active );
len += sprintf( page+len, "instructions completed : %12lu\n", inst_complete );
len += sprintf( page+len, "instructions dispatched : %12lu\n", inst_dispatch );
len += sprintf( page+len, "thread active run cycles : %12lu\n", thread_active_run );
len += sprintf( page+len, "thread active run cycles/instructions completed\n" );
len += sprintf( page+len, "CPI = %lu.%03lu\n", cpi, cpithou );
}
else if ( proc_pmc_control_mode == PMC_CONTROL_TLB ) {
len += sprintf( page+len, "PMC TLB Mode\n" );
len += sprintf( page+len, "I-miss count : %12lu\n", mfspr( PMC1 ) );
len += sprintf( page+len, "I-miss latency : %12lu\n", mfspr( PMC2 ) );
len += sprintf( page+len, "D-miss count : %12lu\n", mfspr( PMC3 ) );
len += sprintf( page+len, "D-miss latency : %12lu\n", mfspr( PMC4 ) );
len += sprintf( page+len, "IERAT miss count : %12lu\n", mfspr( PMC5 ) );
len += sprintf( page+len, "D-reference count : %12lu\n", mfspr( PMC6 ) );
len += sprintf( page+len, "miss PTEs searched : %12lu\n", mfspr( PMC7 ) );
len += sprintf( page+len, "miss >8 PTEs searched : %12lu\n", mfspr( PMC8 ) );
}
/* IMPLEMENT ME */
return pmc_calc_metrics( page, start, off, count, eof, len );
}
unsigned long proc_pmc_conv_int( const char *buf, unsigned count )
{
const char * p;
char b0, b1;
unsigned v, multiplier, mult, i;
unsigned long val;
multiplier = 10;
p = buf;
if ( count >= 3 ) {
b0 = buf[0];
b1 = buf[1];
if ( ( b0 == '0' ) &&
( ( b1 == 'x' ) || ( b1 == 'X' ) ) ) {
p = buf + 2;
count -= 2;
multiplier = 16;
}
}
val = 0;
for ( i=0; i<count; ++i ) {
b0 = *p++;
v = 0;
mult = multiplier;
if ( ( b0 >= '0' ) && ( b0 <= '9' ) )
v = b0 - '0';
else if ( multiplier == 16 ) {
if ( ( b0 >= 'a' ) && ( b0 <= 'f' ) )
v = b0 - 'a' + 10;
else if ( ( b0 >= 'A' ) && ( b0 <= 'F' ) )
v = b0 - 'A' + 10;
else
mult = 1;
}
else
mult = 1;
val *= mult;
val += v;
}
return val;
}
static inline void proc_pmc_stop(void)
{
/* Freeze all counters, leave everything else alone */
mtspr( MMCR0, mfspr( MMCR0 ) | 0x80000000 );
}
static inline void proc_pmc_start(void)
{
/* Unfreeze all counters, leave everything else alone */
mtspr( MMCR0, mfspr( MMCR0 ) & ~0x80000000 );
}
static inline void proc_pmc_reset(void)
{
/* Clear all the PMCs to zeros
* Assume a "stop" has already frozen the counters
* Clear all the PMCs
*/
mtspr( PMC1, 0 );
mtspr( PMC2, 0 );
mtspr( PMC3, 0 );
mtspr( PMC4, 0 );
mtspr( PMC5, 0 );
mtspr( PMC6, 0 );
mtspr( PMC7, 0 );
mtspr( PMC8, 0 );
}
static inline void proc_pmc_cpi(void)
{
/* Configure the PMC registers to count cycles and instructions */
/* so we can compute cpi */
/*
* MMCRA[30] = 1 Don't count in wait state (CTRL[31]=0)
* MMCR0[6] = 1 Freeze counters when any overflow
* MMCR0[19:25] = 0x01 PMC1 counts Thread Active Run Cycles
* MMCR0[26:31] = 0x05 PMC2 counts Thread Active Cycles
* MMCR1[0:4] = 0x07 PMC3 counts Instructions Dispatched
* MMCR1[5:9] = 0x03 PMC4 counts Instructions Completed
* MMCR1[10:14] = 0x06 PMC5 counts Machine Cycles
*
*/
proc_pmc_control_mode = PMC_CONTROL_CPI;
/* Indicate to hypervisor that we are using the PMCs */
get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
/* Freeze all counters */
mtspr( MMCR0, 0x80000000 );
mtspr( MMCR1, 0x00000000 );
/* Clear all the PMCs */
mtspr( PMC1, 0 );
mtspr( PMC2, 0 );
mtspr( PMC3, 0 );
mtspr( PMC4, 0 );
mtspr( PMC5, 0 );
mtspr( PMC6, 0 );
mtspr( PMC7, 0 );
mtspr( PMC8, 0 );
/* Freeze counters in Wait State (CTRL[31]=0) */
mtspr( MMCRA, 0x00000002 );
/* PMC3<-0x07, PMC4<-0x03, PMC5<-0x06 */
mtspr( MMCR1, 0x38cc0000 );
mb();
/* PMC1<-0x01, PMC2<-0x05
* Start all counters
*/
mtspr( MMCR0, 0x02000045 );
}
static inline void proc_pmc_tlb(void)
{
/* Configure the PMC registers to count tlb misses */
/*
* MMCR0[6] = 1 Freeze counters when any overflow
* MMCR0[19:25] = 0x55 Group count
* PMC1 counts I misses
* PMC2 counts I miss duration (latency)
* PMC3 counts D misses
* PMC4 counts D miss duration (latency)
* PMC5 counts IERAT misses
* PMC6 counts D references (including PMC7)
* PMC7 counts miss PTEs searched
* PMC8 counts miss >8 PTEs searched
*
*/
proc_pmc_control_mode = PMC_CONTROL_TLB;
/* Indicate to hypervisor that we are using the PMCs */
get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
/* Freeze all counters */
mtspr( MMCR0, 0x80000000 );
mtspr( MMCR1, 0x00000000 );
/* Clear all the PMCs */
mtspr( PMC1, 0 );
mtspr( PMC2, 0 );
mtspr( PMC3, 0 );
mtspr( PMC4, 0 );
mtspr( PMC5, 0 );
mtspr( PMC6, 0 );
mtspr( PMC7, 0 );
mtspr( PMC8, 0 );
mtspr( MMCRA, 0x00000000 );
mb();
/* PMC1<-0x55
* Start all counters
*/
mtspr( MMCR0, 0x02001540 );
}
int proc_pmc_set_control( struct file *file, const char *buffer, unsigned long count, void *data )
{
char stkbuf[10];
if (count > 9) count = 9;
if (copy_from_user (stkbuf, buffer, count)) {
return -EFAULT;
}
stkbuf[count] = 0;
if ( ! strncmp( stkbuf, "stop", 4 ) )
proc_pmc_stop();
else if ( ! strncmp( stkbuf, "start", 5 ) )
proc_pmc_start();
else if ( ! strncmp( stkbuf, "reset", 5 ) )
proc_pmc_reset();
else if ( ! strncmp( stkbuf, "cpi", 3 ) )
proc_pmc_cpi();
else if ( ! strncmp( stkbuf, "tlb", 3 ) )
proc_pmc_tlb();
/* IMPLEMENT ME */
return count;
}
int proc_pmc_set_mmcr0( struct file *file, const char *buffer, unsigned long count, void *data )
{
unsigned long v;
v = proc_pmc_conv_int( buffer, count );
v = v & ~0x04000000; /* Don't allow interrupts for now */
if ( v & ~0x80000000 ) /* Inform hypervisor we are using PMCs */
get_paca()->xLpPacaPtr->xPMCRegsInUse = 1;
else
get_paca()->xLpPacaPtr->xPMCRegsInUse = 0;
mtspr( MMCR0, v );
return count;
}
int proc_pmc_set_mmcr1( struct file *file, const char *buffer, unsigned long count, void *data )
{
unsigned long v;
v = proc_pmc_conv_int( buffer, count );
mtspr( MMCR1, v );
return count;
}
int proc_pmc_set_mmcra( struct file *file, const char *buffer, unsigned long count, void *data )
{
unsigned long v;
v = proc_pmc_conv_int( buffer, count );
v = v & ~0x00008000; /* Don't allow interrupts for now */
mtspr( MMCRA, v );
return count;
}
int proc_pmc_set_pmc1( struct file *file, const char *buffer, unsigned long count, void *data )
{
unsigned long v;
v = proc_pmc_conv_int( buffer, count );
mtspr( PMC1, v );
return count;
}
int proc_pmc_set_pmc2( struct file *file, const char *buffer, unsigned long count, void *data )
{
unsigned long v;
v = proc_pmc_conv_int( buffer, count );
mtspr( PMC2, v );
return count;
}
int proc_pmc_set_pmc3( struct file *file, const char *buffer, unsigned long count, void *data )
{
unsigned long v;
v = proc_pmc_conv_int( buffer, count );
mtspr( PMC3, v );
return count;
}
int proc_pmc_set_pmc4( struct file *file, const char *buffer, unsigned long count, void *data )
{
unsigned long v;
v = proc_pmc_conv_int( buffer, count );
mtspr( PMC4, v );
return count;
}
int proc_pmc_set_pmc5( struct file *file, const char *buffer, unsigned long count, void *data )
{
unsigned long v;
v = proc_pmc_conv_int( buffer, count );
mtspr( PMC5, v );
return count;
}
int proc_pmc_set_pmc6( struct file *file, const char *buffer, unsigned long count, void *data )
{
unsigned long v;
v = proc_pmc_conv_int( buffer, count );
mtspr( PMC6, v );
return count;
}
int proc_pmc_set_pmc7( struct file *file, const char *buffer, unsigned long count, void *data )
{
unsigned long v;
v = proc_pmc_conv_int( buffer, count );
mtspr( PMC7, v );
return count;
}
int proc_pmc_set_pmc8( struct file *file, const char *buffer, unsigned long count, void *data )
{
unsigned long v;
v = proc_pmc_conv_int( buffer, count );
mtspr( PMC8, v );
return count;
}
...@@ -18,15 +18,6 @@ ...@@ -18,15 +18,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
/*
* Change Activity:
* 2001 : mikec : Created
* 2001/06/05 : engebret : Software event count support.
* 2003/02/13 : bergner : Move PMC code to pmc.c
* End Change Activity
*/
#include <linux/config.h> #include <linux/config.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/mm.h> #include <linux/mm.h>
...@@ -34,7 +25,6 @@ ...@@ -34,7 +25,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <asm/proc_fs.h>
#include <asm/naca.h> #include <asm/naca.h>
#include <asm/paca.h> #include <asm/paca.h>
#include <asm/systemcfg.h> #include <asm/systemcfg.h>
...@@ -42,10 +32,6 @@ ...@@ -42,10 +32,6 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/prom.h> #include <asm/prom.h>
struct proc_ppc64_t proc_ppc64;
void proc_ppc64_create_paca(int num);
static loff_t page_map_seek( struct file *file, loff_t off, int whence); static loff_t page_map_seek( struct file *file, loff_t off, int whence);
static ssize_t page_map_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos); static ssize_t page_map_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos);
static int page_map_mmap( struct file *file, struct vm_area_struct *vma ); static int page_map_mmap( struct file *file, struct vm_area_struct *vma );
...@@ -59,7 +45,7 @@ static struct file_operations page_map_fops = { ...@@ -59,7 +45,7 @@ static struct file_operations page_map_fops = {
#ifdef CONFIG_PPC_PSERIES #ifdef CONFIG_PPC_PSERIES
/* routines for /proc/ppc64/ofdt */ /* routines for /proc/ppc64/ofdt */
static ssize_t ofdt_write(struct file *, const char __user *, size_t, loff_t *); static ssize_t ofdt_write(struct file *, const char __user *, size_t, loff_t *);
static void proc_ppc64_create_ofdt(struct proc_dir_entry *); static void proc_ppc64_create_ofdt(void);
static int do_remove_node(char *); static int do_remove_node(char *);
static int do_add_node(char *, size_t); static int do_add_node(char *, size_t);
static void release_prop_list(const struct property *); static void release_prop_list(const struct property *);
...@@ -70,77 +56,19 @@ static struct file_operations ofdt_fops = { ...@@ -70,77 +56,19 @@ static struct file_operations ofdt_fops = {
}; };
#endif #endif
int __init proc_ppc64_init(void)
{
if (proc_ppc64.root == NULL) {
printk(KERN_INFO "proc_ppc64: Creating /proc/ppc64/\n");
proc_ppc64.root = proc_mkdir("ppc64", 0);
if (!proc_ppc64.root)
return 0;
} else {
return 0;
}
proc_ppc64.naca = create_proc_entry("naca", S_IRUSR, proc_ppc64.root);
if ( proc_ppc64.naca ) {
proc_ppc64.naca->nlink = 1;
proc_ppc64.naca->data = naca;
proc_ppc64.naca->size = 4096;
proc_ppc64.naca->proc_fops = &page_map_fops;
}
proc_ppc64.systemcfg = create_proc_entry("systemcfg", S_IFREG|S_IRUGO, proc_ppc64.root);
if ( proc_ppc64.systemcfg ) {
proc_ppc64.systemcfg->nlink = 1;
proc_ppc64.systemcfg->data = systemcfg;
proc_ppc64.systemcfg->size = 4096;
proc_ppc64.systemcfg->proc_fops = &page_map_fops;
}
/* /proc/ppc64/paca/XX -- raw paca contents. Only readable to root */
proc_ppc64.paca = proc_mkdir("paca", proc_ppc64.root);
if (proc_ppc64.paca) {
unsigned long i;
for (i = 0; i < NR_CPUS; i++) {
if (!cpu_online(i))
continue;
proc_ppc64_create_paca(i);
}
}
#ifdef CONFIG_PPC_PSERIES
/* Placeholder for rtas interfaces. */
if (proc_ppc64.rtas == NULL)
proc_ppc64.rtas = proc_mkdir("rtas", proc_ppc64.root);
if (proc_ppc64.rtas)
proc_symlink("rtas", 0, "ppc64/rtas");
proc_ppc64_create_ofdt(proc_ppc64.root);
#endif
return 0;
}
/* /*
* NOTE: since paca data is always in flux the values will never be a consistant set. * NOTE: since paca data is always in flux the values will never be a
* In theory it could be made consistent if we made the corresponding cpu * consistant set.
* copy the page for us (via an IPI). Probably not worth it.
*
*/ */
void proc_ppc64_create_paca(int num) static void __init proc_create_paca(struct proc_dir_entry *dir, int num)
{ {
struct proc_dir_entry *ent; struct proc_dir_entry *ent;
struct paca_struct *lpaca = paca + num; struct paca_struct *lpaca = paca + num;
char buf[16]; char buf[16];
sprintf(buf, "%02x", num); sprintf(buf, "%02x", num);
ent = create_proc_entry(buf, S_IRUSR, proc_ppc64.paca); ent = create_proc_entry(buf, S_IRUSR, dir);
if ( ent ) { if (ent) {
ent->nlink = 1; ent->nlink = 1;
ent->data = lpaca; ent->data = lpaca;
ent->size = 4096; ent->size = 4096;
...@@ -148,6 +76,67 @@ void proc_ppc64_create_paca(int num) ...@@ -148,6 +76,67 @@ void proc_ppc64_create_paca(int num)
} }
} }
/*
* Create the ppc64 and ppc64/rtas directories early. This allows us to
* assume that they have been previously created in drivers.
*/
static int __init proc_ppc64_create(void)
{
struct proc_dir_entry *root;
root = proc_mkdir("ppc64", 0);
if (!root)
return 1;
if (!(systemcfg->platform & PLATFORM_PSERIES))
return 0;
if (!proc_mkdir("rtas", root))
return 1;
if (!proc_symlink("rtas", 0, "ppc64/rtas"))
return 1;
return 0;
}
core_initcall(proc_ppc64_create);
static int __init proc_ppc64_init(void)
{
unsigned long i;
struct proc_dir_entry *pde;
pde = create_proc_entry("ppc64/naca", S_IRUSR, NULL);
if (!pde)
return 1;
pde->nlink = 1;
pde->data = naca;
pde->size = 4096;
pde->proc_fops = &page_map_fops;
pde = create_proc_entry("ppc64/systemcfg", S_IFREG|S_IRUGO, NULL);
if (!pde)
return 1;
pde->nlink = 1;
pde->data = systemcfg;
pde->size = 4096;
pde->proc_fops = &page_map_fops;
/* /proc/ppc64/paca/XX -- raw paca contents. Only readable to root */
pde = proc_mkdir("ppc64/paca", NULL);
if (!pde)
return 1;
for_each_cpu(i)
proc_create_paca(pde, i);
#ifdef CONFIG_PPC_PSERIES
if ((systemcfg->platform & PLATFORM_PSERIES))
proc_ppc64_create_ofdt();
#endif
return 0;
}
__initcall(proc_ppc64_init);
static loff_t page_map_seek( struct file *file, loff_t off, int whence) static loff_t page_map_seek( struct file *file, loff_t off, int whence)
{ {
...@@ -204,11 +193,11 @@ static int page_map_mmap( struct file *file, struct vm_area_struct *vma ) ...@@ -204,11 +193,11 @@ static int page_map_mmap( struct file *file, struct vm_area_struct *vma )
#ifdef CONFIG_PPC_PSERIES #ifdef CONFIG_PPC_PSERIES
/* create /proc/ppc64/ofdt write-only by root */ /* create /proc/ppc64/ofdt write-only by root */
static void proc_ppc64_create_ofdt(struct proc_dir_entry *parent) static void proc_ppc64_create_ofdt(void)
{ {
struct proc_dir_entry *ent; struct proc_dir_entry *ent;
ent = create_proc_entry("ofdt", S_IWUSR, parent); ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL);
if (ent) { if (ent) {
ent->nlink = 1; ent->nlink = 1;
ent->data = NULL; ent->data = NULL;
...@@ -423,5 +412,3 @@ static void release_prop_list(const struct property *prop) ...@@ -423,5 +412,3 @@ static void release_prop_list(const struct property *prop)
} }
#endif /* defined(CONFIG_PPC_PSERIES) */ #endif /* defined(CONFIG_PPC_PSERIES) */
fs_initcall(proc_ppc64_init);
...@@ -36,7 +36,6 @@ ...@@ -36,7 +36,6 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/proc_fs.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/sysrq.h> #include <linux/sysrq.h>
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/rtas.h> #include <asm/rtas.h>
#include <asm/proc_fs.h>
#include <asm/machdep.h> /* for ppc_md */ #include <asm/machdep.h> /* for ppc_md */
#include <asm/time.h> #include <asm/time.h>
...@@ -117,8 +116,6 @@ ...@@ -117,8 +116,6 @@
/* Globals */ /* Globals */
extern struct proc_dir_entry *proc_rtas;
static struct rtas_sensors sensors; static struct rtas_sensors sensors;
static struct device_node *rtas_node = NULL; static struct device_node *rtas_node = NULL;
static unsigned long power_on_time = 0; /* Save the time the user set */ static unsigned long power_on_time = 0; /* Save the time the user set */
...@@ -201,51 +198,50 @@ int get_location_code(struct individual_sensor s, char * buf); ...@@ -201,51 +198,50 @@ int get_location_code(struct individual_sensor s, char * buf);
int check_location_string (char *c, char * buf); int check_location_string (char *c, char * buf);
int check_location (char *c, int idx, char * buf); int check_location (char *c, int idx, char * buf);
/* ****************************************************************** */ static int __init proc_rtas_init(void)
/* MAIN */
/* ****************************************************************** */
void proc_rtas_init(void)
{ {
struct proc_dir_entry *entry; struct proc_dir_entry *entry;
if (!(systemcfg->platform & PLATFORM_PSERIES))
return 1;
rtas_node = of_find_node_by_name(NULL, "rtas"); rtas_node = of_find_node_by_name(NULL, "rtas");
if ((rtas_node == NULL) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) { if (rtas_node == NULL)
return; return 1;
}
if (proc_ppc64.rtas == NULL) {
proc_ppc64_init();
}
if (proc_ppc64.rtas == NULL) { entry = create_proc_entry("ppc64/rtas/progress", S_IRUGO|S_IWUSR, NULL);
printk(KERN_ERR "Failed to create /proc/rtas in proc_rtas_init\n"); if (entry)
return; entry->proc_fops = &ppc_rtas_progress_operations;
}
/* /proc/rtas entries */ entry = create_proc_entry("ppc64/rtas/clock", S_IRUGO|S_IWUSR, NULL);
if (entry)
entry->proc_fops = &ppc_rtas_clock_operations;
entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, proc_ppc64.rtas); entry = create_proc_entry("ppc64/rtas/poweron", S_IWUSR|S_IRUGO, NULL);
if (entry) entry->proc_fops = &ppc_rtas_progress_operations; if (entry)
entry->proc_fops = &ppc_rtas_poweron_operations;
entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, proc_ppc64.rtas); create_proc_read_entry("ppc64/rtas/sensors", S_IRUGO, NULL,
if (entry) entry->proc_fops = &ppc_rtas_clock_operations; ppc_rtas_sensor_read, NULL);
entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, proc_ppc64.rtas); entry = create_proc_entry("ppc64/rtas/frequency", S_IWUSR|S_IRUGO,
if (entry) entry->proc_fops = &ppc_rtas_poweron_operations; NULL);
if (entry)
entry->proc_fops = &ppc_rtas_tone_freq_operations;
create_proc_read_entry("sensors", S_IRUGO, proc_ppc64.rtas, entry = create_proc_entry("ppc64/rtas/volume", S_IWUSR|S_IRUGO, NULL);
ppc_rtas_sensor_read, NULL); if (entry)
entry->proc_fops = &ppc_rtas_tone_volume_operations;
entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, proc_ppc64.rtas);
if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations;
entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, proc_ppc64.rtas); entry = create_proc_entry("ppc64/rtas/rmo_buffer", S_IRUSR, NULL);
if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations; if (entry)
entry->proc_fops = &ppc_rtas_rmo_buf_ops;
entry = create_proc_entry("rmo_buffer", S_IRUSR, proc_ppc64.rtas); return 0;
if (entry) entry->proc_fops = &ppc_rtas_rmo_buf_ops;
} }
__initcall(proc_rtas_init);
/* ****************************************************************** */ /* ****************************************************************** */
/* POWER-ON-TIME */ /* POWER-ON-TIME */
/* ****************************************************************** */ /* ****************************************************************** */
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/proc_fs.h>
#include <asm/rtas.h> #include <asm/rtas.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <asm/machdep.h> #include <asm/machdep.h>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/proc_fs.h> #include <linux/proc_fs.h>
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/rtas.h> #include <asm/rtas.h>
...@@ -106,10 +106,10 @@ struct rtas_validate_flash_t ...@@ -106,10 +106,10 @@ struct rtas_validate_flash_t
}; };
static spinlock_t flash_file_open_lock = SPIN_LOCK_UNLOCKED; static spinlock_t flash_file_open_lock = SPIN_LOCK_UNLOCKED;
static struct proc_dir_entry *firmware_flash_pde = NULL; static struct proc_dir_entry *firmware_flash_pde;
static struct proc_dir_entry *firmware_update_pde = NULL; static struct proc_dir_entry *firmware_update_pde;
static struct proc_dir_entry *validate_pde = NULL; static struct proc_dir_entry *validate_pde;
static struct proc_dir_entry *manage_pde = NULL; static struct proc_dir_entry *manage_pde;
/* Do simple sanity checks on the flash image. */ /* Do simple sanity checks on the flash image. */
static int flash_list_valid(struct flash_block_list *flist) static int flash_list_valid(struct flash_block_list *flist)
...@@ -501,7 +501,7 @@ static ssize_t validate_flash_read(struct file *file, char *buf, ...@@ -501,7 +501,7 @@ static ssize_t validate_flash_read(struct file *file, char *buf,
} }
static ssize_t validate_flash_write(struct file *file, const char *buf, static ssize_t validate_flash_write(struct file *file, const char *buf,
size_t count, loff_t *off) size_t count, loff_t *off)
{ {
struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode); struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
struct rtas_validate_flash_t *args_buf; struct rtas_validate_flash_t *args_buf;
...@@ -567,18 +567,18 @@ static int validate_flash_release(struct inode *inode, struct file *file) ...@@ -567,18 +567,18 @@ static int validate_flash_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static inline void remove_flash_pde(struct proc_dir_entry *dp) static void remove_flash_pde(struct proc_dir_entry *dp)
{ {
if (dp) { if (dp) {
if (dp->data != NULL) if (dp->data != NULL)
kfree(dp->data); kfree(dp->data);
remove_proc_entry(dp->name, proc_ppc64.rtas); remove_proc_entry(dp->name, NULL);
} }
} }
static inline int initialize_flash_pde_data(const char *rtas_call_name, static int initialize_flash_pde_data(const char *rtas_call_name,
size_t buf_size, size_t buf_size,
struct proc_dir_entry *dp) struct proc_dir_entry *dp)
{ {
int *status; int *status;
int token; int token;
...@@ -591,7 +591,8 @@ static inline int initialize_flash_pde_data(const char *rtas_call_name, ...@@ -591,7 +591,8 @@ static inline int initialize_flash_pde_data(const char *rtas_call_name,
memset(dp->data, 0, buf_size); memset(dp->data, 0, buf_size);
/* This code assumes that the status int is the first member of the /*
* This code assumes that the status int is the first member of the
* struct * struct
*/ */
status = (int *) dp->data; status = (int *) dp->data;
...@@ -604,12 +605,12 @@ static inline int initialize_flash_pde_data(const char *rtas_call_name, ...@@ -604,12 +605,12 @@ static inline int initialize_flash_pde_data(const char *rtas_call_name,
return 0; return 0;
} }
static inline struct proc_dir_entry * create_flash_pde(const char *filename, static struct proc_dir_entry *create_flash_pde(const char *filename,
struct file_operations *fops) struct file_operations *fops)
{ {
struct proc_dir_entry *ent = NULL; struct proc_dir_entry *ent = NULL;
ent = create_proc_entry(filename, S_IRUSR | S_IWUSR, proc_ppc64.rtas); ent = create_proc_entry(filename, S_IRUSR | S_IWUSR, NULL);
if (ent != NULL) { if (ent != NULL) {
ent->nlink = 1; ent->nlink = 1;
ent->proc_fops = fops; ent->proc_fops = fops;
...@@ -644,50 +645,79 @@ int __init rtas_flash_init(void) ...@@ -644,50 +645,79 @@ int __init rtas_flash_init(void)
{ {
int rc; int rc;
if (!proc_ppc64.rtas) { if (rtas_token("ibm,update-flash-64-and-reboot") ==
printk(KERN_WARNING "rtas proc dir does not already exist"); RTAS_UNKNOWN_SERVICE) {
return -ENOENT; printk(KERN_ERR "rtas_flash: no firmware flash support\n");
return 1;
} }
firmware_flash_pde = create_flash_pde(FIRMWARE_FLASH_NAME, firmware_flash_pde = create_flash_pde("ppc64/rtas/"
FIRMWARE_FLASH_NAME,
&rtas_flash_operations); &rtas_flash_operations);
if (firmware_flash_pde == NULL) {
rc = -ENOMEM;
goto cleanup;
}
rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot", rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot",
sizeof(struct rtas_update_flash_t), sizeof(struct rtas_update_flash_t),
firmware_flash_pde); firmware_flash_pde);
if (rc != 0) if (rc != 0)
return rc; goto cleanup;
firmware_update_pde = create_flash_pde(FIRMWARE_UPDATE_NAME, firmware_update_pde = create_flash_pde("ppc64/rtas/"
FIRMWARE_UPDATE_NAME,
&rtas_flash_operations); &rtas_flash_operations);
if (firmware_update_pde == NULL) {
rc = -ENOMEM;
goto cleanup;
}
rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot", rc = initialize_flash_pde_data("ibm,update-flash-64-and-reboot",
sizeof(struct rtas_update_flash_t), sizeof(struct rtas_update_flash_t),
firmware_update_pde); firmware_update_pde);
if (rc != 0) if (rc != 0)
return rc; goto cleanup;
validate_pde = create_flash_pde(VALIDATE_FLASH_NAME, validate_pde = create_flash_pde("ppc64/rtas/" VALIDATE_FLASH_NAME,
&validate_flash_operations); &validate_flash_operations);
if (validate_pde == NULL) {
rc = -ENOMEM;
goto cleanup;
}
rc = initialize_flash_pde_data("ibm,validate-flash-image", rc = initialize_flash_pde_data("ibm,validate-flash-image",
sizeof(struct rtas_validate_flash_t), sizeof(struct rtas_validate_flash_t),
validate_pde); validate_pde);
if (rc != 0) if (rc != 0)
return rc; goto cleanup;
manage_pde = create_flash_pde(MANAGE_FLASH_NAME, manage_pde = create_flash_pde("ppc64/rtas" MANAGE_FLASH_NAME,
&manage_flash_operations); &manage_flash_operations);
if (manage_pde == NULL) {
rc = -ENOMEM;
goto cleanup;
}
rc = initialize_flash_pde_data("ibm,manage-flash-image", rc = initialize_flash_pde_data("ibm,manage-flash-image",
sizeof(struct rtas_manage_flash_t), sizeof(struct rtas_manage_flash_t),
manage_pde); manage_pde);
if (rc != 0) if (rc != 0)
return rc; goto cleanup;
return 0; return 0;
cleanup:
remove_flash_pde(firmware_flash_pde);
remove_flash_pde(firmware_update_pde);
remove_flash_pde(validate_pde);
remove_flash_pde(manage_pde);
return rc;
} }
void __exit rtas_flash_cleanup(void) void __exit rtas_flash_cleanup(void)
{ {
if (!proc_ppc64.rtas)
return;
remove_flash_pde(firmware_flash_pde); remove_flash_pde(firmware_flash_pde);
remove_flash_pde(firmware_update_pde); remove_flash_pde(firmware_update_pde);
remove_flash_pde(validate_pde); remove_flash_pde(validate_pde);
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/nvram.h> #include <asm/nvram.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/proc_fs.h>
#if 0 #if 0
#define DEBUG(A...) printk(KERN_ERR A) #define DEBUG(A...) printk(KERN_ERR A)
...@@ -47,7 +46,6 @@ static unsigned int rtas_event_scan_rate; ...@@ -47,7 +46,6 @@ static unsigned int rtas_event_scan_rate;
static unsigned int rtas_error_log_max; static unsigned int rtas_error_log_max;
static unsigned int rtas_error_log_buffer_max; static unsigned int rtas_error_log_buffer_max;
extern spinlock_t proc_ppc64_lock;
extern volatile int no_more_logging; extern volatile int no_more_logging;
volatile int error_log_cnt = 0; volatile int error_log_cnt = 0;
...@@ -445,20 +443,18 @@ static int __init rtas_init(void) ...@@ -445,20 +443,18 @@ static int __init rtas_init(void)
{ {
struct proc_dir_entry *entry; struct proc_dir_entry *entry;
if (proc_ppc64.rtas == NULL) { /* No RTAS, only warn if we are on a pSeries box */
proc_ppc64_init(); if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) {
if (systemcfg->platform & PLATFORM_PSERIES);
printk(KERN_ERR "rtasd: no RTAS on system\n");
return 1;
} }
if (proc_ppc64.rtas == NULL) { entry = create_proc_entry("ppc64/error_log", S_IRUSR, NULL);
printk(KERN_ERR "rtas_init: /proc/ppc64/rtas does not exist.");
return -EIO;
}
entry = create_proc_entry("error_log", S_IRUSR, proc_ppc64.rtas);
if (entry) if (entry)
entry->proc_fops = &proc_rtas_log_operations; entry->proc_fops = &proc_rtas_log_operations;
else else
printk(KERN_ERR "Failed to create rtas/error_log proc entry\n"); printk(KERN_ERR "Failed to create error_log proc entry\n");
if (kernel_thread(rtasd, 0, CLONE_FS) < 0) if (kernel_thread(rtasd, 0, CLONE_FS) < 0)
printk(KERN_ERR "Failed to start RTAS daemon\n"); printk(KERN_ERR "Failed to start RTAS daemon\n");
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/rtas.h> #include <asm/rtas.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/proc_fs.h>
#define MODULE_VERS "1.0" #define MODULE_VERS "1.0"
#define MODULE_NAME "scanlog" #define MODULE_NAME "scanlog"
...@@ -212,16 +211,7 @@ int __init scanlog_init(void) ...@@ -212,16 +211,7 @@ int __init scanlog_init(void)
return -EIO; return -EIO;
} }
if (proc_ppc64.rtas == NULL) { ent = create_proc_entry("ppc64/rtas/scan-log-dump", S_IRUSR, NULL);
proc_ppc64_init();
}
if (proc_ppc64.rtas == NULL) {
printk(KERN_ERR "Failed to create /proc/rtas in scanlog_init\n");
return -EIO;
}
ent = create_proc_entry("scan-log-dump", S_IRUSR, proc_ppc64.rtas);
if (ent) { if (ent) {
ent->proc_fops = &scanlog_fops; ent->proc_fops = &scanlog_fops;
/* Ideally we could allocate a buffer < 4G */ /* Ideally we could allocate a buffer < 4G */
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
*/ */
#include <asm/uaccess.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -37,9 +36,10 @@ ...@@ -37,9 +36,10 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/seq_file.h>
#include <asm/hardirq.h> /* for is_atomic */ #include <asm/hardirq.h>
#include <asm/uaccess.h>
#include <asm/iSeries/LparData.h> #include <asm/iSeries/LparData.h>
#include <asm/iSeries/HvLpEvent.h> #include <asm/iSeries/HvLpEvent.h>
#include <asm/iSeries/HvLpConfig.h> #include <asm/iSeries/HvLpConfig.h>
...@@ -184,21 +184,21 @@ static unsigned char e2a(unsigned char x) ...@@ -184,21 +184,21 @@ static unsigned char e2a(unsigned char x)
return ' '; return ' ';
} }
/* Handle reads from the proc file system static int proc_viopath_show(struct seq_file *m, void *v)
*/
static int proc_read(char *buf, char **start, off_t offset,
int blen, int *eof, void *data)
{ {
char *buf;
dma_addr_t handle;
HvLpEvent_Rc hvrc; HvLpEvent_Rc hvrc;
DECLARE_MUTEX_LOCKED(Semaphore); DECLARE_MUTEX_LOCKED(Semaphore);
dma_addr_t dmaa =
dma_map_single(iSeries_vio_dev, buf, PAGE_SIZE, DMA_FROM_DEVICE);
int len = PAGE_SIZE;
if (len > blen) buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
len = blen; if (!buf)
return 0;
memset(buf, 0, PAGE_SIZE);
handle = dma_map_single(iSeries_vio_dev, buf, PAGE_SIZE,
DMA_FROM_DEVICE);
memset(buf, 0x00, len);
hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
HvLpEvent_Type_VirtualIo, HvLpEvent_Type_VirtualIo,
viomajorsubtype_config | vioconfigget, viomajorsubtype_config | vioconfigget,
...@@ -206,50 +206,54 @@ static int proc_read(char *buf, char **start, off_t offset, ...@@ -206,50 +206,54 @@ static int proc_read(char *buf, char **start, off_t offset,
viopath_sourceinst(viopath_hostLp), viopath_sourceinst(viopath_hostLp),
viopath_targetinst(viopath_hostLp), viopath_targetinst(viopath_hostLp),
(u64)(unsigned long)&Semaphore, VIOVERSION << 16, (u64)(unsigned long)&Semaphore, VIOVERSION << 16,
((u64)dmaa) << 32, len, 0, 0); ((u64)handle) << 32, PAGE_SIZE, 0, 0);
if (hvrc != HvLpEvent_Rc_Good) if (hvrc != HvLpEvent_Rc_Good)
printk("viopath hv error on op %d\n", (int) hvrc); printk("viopath hv error on op %d\n", (int)hvrc);
down(&Semaphore); down(&Semaphore);
dma_unmap_single(iSeries_vio_dev, dmaa, PAGE_SIZE, DMA_FROM_DEVICE); dma_unmap_single(iSeries_vio_dev, handle, PAGE_SIZE, DMA_FROM_DEVICE);
kfree(buf);
sprintf(buf + strlen(buf), "SRLNBR=");
buf[strlen(buf)] = e2a(xItExtVpdPanel.mfgID[2]); buf[PAGE_SIZE] = '\0';
buf[strlen(buf)] = e2a(xItExtVpdPanel.mfgID[3]); seq_printf(m, "%s", buf);
buf[strlen(buf)] = e2a(xItExtVpdPanel.systemSerial[1]);
buf[strlen(buf)] = e2a(xItExtVpdPanel.systemSerial[2]); seq_printf(m, "SRLNBR=%c%c%c%c%c%c%c\n",
buf[strlen(buf)] = e2a(xItExtVpdPanel.systemSerial[3]); e2a(xItExtVpdPanel.mfgID[2]),
buf[strlen(buf)] = e2a(xItExtVpdPanel.systemSerial[4]); e2a(xItExtVpdPanel.mfgID[3]),
buf[strlen(buf)] = e2a(xItExtVpdPanel.systemSerial[5]); e2a(xItExtVpdPanel.systemSerial[1]),
buf[strlen(buf)] = '\n'; e2a(xItExtVpdPanel.systemSerial[2]),
*eof = 1; e2a(xItExtVpdPanel.systemSerial[3]),
return strlen(buf); e2a(xItExtVpdPanel.systemSerial[4]),
e2a(xItExtVpdPanel.systemSerial[5]));
return 0;
} }
/* Handle writes to our proc file system static int proc_viopath_open(struct inode *inode, struct file *file)
*/
static int proc_write(struct file *file, const char *buffer,
unsigned long count, void *data)
{ {
/* Doesn't do anything today!!! return single_open(file, proc_viopath_show, NULL);
*/
return count;
} }
/* setup our proc file system entries static struct file_operations proc_viopath_operations = {
*/ .open = proc_viopath_open,
static void vio_proc_init(struct proc_dir_entry *iSeries_proc) .read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init vio_proc_init(void)
{ {
struct proc_dir_entry *ent; struct proc_dir_entry *e;
ent = create_proc_entry("config", S_IFREG | S_IRUSR, iSeries_proc);
if (!ent) e = create_proc_entry("iSeries/config", 0, NULL);
return; if (e)
ent->nlink = 1; e->proc_fops = &proc_viopath_operations;
ent->data = NULL;
ent->read_proc = proc_read; return 0;
ent->write_proc = proc_write;
} }
__initcall(vio_proc_init);
/* See if a given LP is active. Allow for invalid lps to be passed in /* See if a given LP is active. Allow for invalid lps to be passed in
* and just return invalid * and just return invalid
...@@ -433,13 +437,8 @@ void vio_set_hostlp(void) ...@@ -433,13 +437,8 @@ void vio_set_hostlp(void)
viopath_ourLp = HvLpConfig_getLpIndex(); viopath_ourLp = HvLpConfig_getLpIndex();
viopath_hostLp = HvCallCfg_getHostingLpIndex(viopath_ourLp); viopath_hostLp = HvCallCfg_getHostingLpIndex(viopath_ourLp);
/* If we have a valid hosting LP, create a proc file system entry if (viopath_hostLp != HvLpIndexInvalid)
* for config information
*/
if (viopath_hostLp != HvLpIndexInvalid) {
iSeries_proc_callback(&vio_proc_init);
vio_setHandler(viomajorsubtype_config, handleConfig); vio_setHandler(viomajorsubtype_config, handleConfig);
}
} }
EXPORT_SYMBOL(vio_set_hostlp); EXPORT_SYMBOL(vio_set_hostlp);
......
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/naca.h> #include <asm/naca.h>
#include <asm/pmc.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/lmb.h> #include <asm/lmb.h>
#include <asm/abs_addr.h> #include <asm/abs_addr.h>
......
...@@ -36,7 +36,6 @@ ...@@ -36,7 +36,6 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/proc_fs.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/page.h> #include <asm/page.h>
......
...@@ -73,9 +73,6 @@ void __init proc_root_init(void) ...@@ -73,9 +73,6 @@ void __init proc_root_init(void)
proc_tty_init(); proc_tty_init();
#ifdef CONFIG_PROC_DEVICETREE #ifdef CONFIG_PROC_DEVICETREE
proc_device_tree_init(); proc_device_tree_init();
#endif
#ifdef CONFIG_PPC_RTAS
proc_rtas_init();
#endif #endif
proc_bus = proc_mkdir("bus", 0); proc_bus = proc_mkdir("bus", 0);
} }
......
...@@ -19,12 +19,6 @@ ...@@ -19,12 +19,6 @@
#ifndef _ISERIES_PROC_H #ifndef _ISERIES_PROC_H
#define _ISERIES_PROC_H #define _ISERIES_PROC_H
#include <linux/proc_fs.h>
extern void iSeries_proc_early_init(void); extern void iSeries_proc_early_init(void);
typedef void (*iSeriesProcFunction)(struct proc_dir_entry *iSeries_proc);
extern void iSeries_proc_callback(iSeriesProcFunction initFunction);
#endif /* _iSeries_PROC_H */ #endif /* _iSeries_PROC_H */
...@@ -67,6 +67,4 @@ extern int mf_getRtcTime(unsigned long *time); ...@@ -67,6 +67,4 @@ extern int mf_getRtcTime(unsigned long *time);
extern int mf_getRtc( struct rtc_time * tm ); extern int mf_getRtc( struct rtc_time * tm );
extern int mf_setRtc( struct rtc_time * tm ); extern int mf_setRtc( struct rtc_time * tm );
extern void mf_proc_init(struct proc_dir_entry *iSeries_proc);
#endif /* MF_H_INCLUDED */ #endif /* MF_H_INCLUDED */
/*
* pmc.h
* Copyright (C) 2001 Dave Engebretsen & Mike Corrigan IBM Corporation.
*
* The PPC64 PMC subsystem encompases both the hardware PMC registers and
* a set of software event counters. An interface is provided via the
* proc filesystem which can be used to access this subsystem.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Start Change Log
* 2001/06/05 : engebret : Created.
* End Change Log
*/
#ifndef _PPC64_TYPES_H
#include <asm/types.h>
#endif
#ifndef _PMC_H
#define _PMC_H
#define STAB_ENTRY_MAX 64
struct _pmc_hw
{
u64 mmcr0;
u64 mmcr1;
u64 mmcra;
u64 pmc1;
u64 pmc2;
u64 pmc3;
u64 pmc4;
u64 pmc5;
u64 pmc6;
u64 pmc7;
u64 pmc8;
};
struct _pmc_sw
{
u64 stab_faults; /* Count of faults on the stab */
u64 stab_capacity_castouts;/* Count of castouts from the stab */
u64 stab_invalidations; /* Count of invalidations from the */
/* stab, not including castouts */
u64 stab_entry_use[STAB_ENTRY_MAX];
u64 htab_primary_overflows;
u64 htab_capacity_castouts;
u64 htab_read_to_write_fault;
};
#define PMC_HW_TEXT_ENTRY_COUNT (sizeof(struct _pmc_hw) / sizeof(u64))
#define PMC_SW_TEXT_ENTRY_COUNT (sizeof(struct _pmc_sw) / sizeof(u64))
#define PMC_TEXT_ENTRY_SIZE 64
struct _pmc_sw_text {
char buffer[PMC_SW_TEXT_ENTRY_COUNT * PMC_TEXT_ENTRY_SIZE];
};
struct _pmc_hw_text {
char buffer[PMC_HW_TEXT_ENTRY_COUNT * PMC_TEXT_ENTRY_SIZE];
};
extern struct _pmc_sw pmc_sw_system;
extern struct _pmc_sw pmc_sw_cpu[];
extern struct _pmc_sw_text pmc_sw_text;
extern struct _pmc_hw_text pmc_hw_text;
extern char *ppc64_pmc_stab(int file);
extern char *ppc64_pmc_htab(int file);
extern char *ppc64_pmc_hw(int file);
#if 1
#define PMC_SW_PROCESSOR(F) pmc_sw_cpu[smp_processor_id()].F++
#define PMC_SW_PROCESSOR_A(F, E) (pmc_sw_cpu[smp_processor_id()].F[(E)])++
#define PMC_SW_SYSTEM(F) pmc_sw_system.F++
#else
#define PMC_SW_PROCESSOR(F) do {;} while (0)
#define PMC_SW_PROCESSOR_A(F) do {;} while (0)
#define PMC_SW_SYSTEM(F) do {;} while (0)
#endif
#define MMCR0 795
#define MMCR1 798
#define MMCRA 786
#define PMC1 787
#define PMC2 788
#define PMC3 789
#define PMC4 790
#define PMC5 791
#define PMC6 792
#define PMC7 793
#define PMC8 794
#define PMC_CONTROL_CPI 1
#define PMC_CONTROL_TLB 2
#endif /* _PMC_H */
#ifndef _PPC64_PROC_FS_H
#define _PPC64_PROC_FS_H
/*
* proc_fs.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Change Activity: */
/* tgall -- merge of iSeries/iSeries_proc.h and proc_pmc.h */
/* End Change Activity */
#include <linux/proc_fs.h>
struct proc_ppc64_t {
struct proc_dir_entry *root;
struct proc_dir_entry *naca;
struct proc_dir_entry *paca;
struct proc_dir_entry *systemcfg;
struct proc_dir_entry *rtas;
};
extern struct proc_ppc64_t proc_ppc64;
extern int proc_ppc64_init(void);
#endif /* _PPC64_PROC_FS_H */
/*
* pmc_proc.h
* Copyright (C) 2001 Mike Corrigan IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Change Activity: */
/* End Change Activity */
#ifndef _PMC_PROC_H
#define _PMC_PROC_H
#include <linux/proc_fs.h>
void pmc_proc_init(struct proc_dir_entry *iSeries_proc);
void proc_ppc64_init(void);
#endif /* _PMC_PROC_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment