/*
* Copyright IBM Corp. 2010
* Author: Heinz Graalfs <graalfs@de.ibm.com>
*/
#include <linux/kernel_stat.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/smp.h>
#include <linux/errno.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <linux/cpu.h>
#include <linux/semaphore.h>
#include <linux/oom.h>
#include <linux/oprofile.h>
#include <asm/facility.h>
#include <asm/cpu_mf.h>
#include <asm/irq.h>
#include "hwsampler.h"
#include "op_counter.h"
#define MAX_NUM_SDB 511
#define MIN_NUM_SDB 1
DECLARE_PER_CPU(struct hws_cpu_buffer, sampler_cpu_buffer);
struct hws_execute_parms {
void *buffer;
signed int rc;
};
DEFINE_PER_CPU(struct hws_cpu_buffer, sampler_cpu_buffer);
EXPORT_PER_CPU_SYMBOL(sampler_cpu_buffer);
static DEFINE_MUTEX(hws_sem);
static DEFINE_MUTEX(hws_sem_oom);
static unsigned char hws_flush_all;
static unsigned int hws_oom;
static unsigned int hws_alert;
static struct workqueue_struct *hws_wq;
static unsigned int hws_state;
enum {
HWS_INIT = 1,
HWS_DEALLOCATED,
HWS_STOPPED,
HWS_STARTED,
HWS_STOPPING };
/* set to 1 if called by kernel during memory allocation */
static unsigned char oom_killer_was_active;
/* size of SDBT and SDB as of allocate API */
static unsigned long num_sdbt = 100;
static unsigned long num_sdb = 511;
/* sampling interval (machine cycles) */
static unsigned long interval;
static unsigned long min_sampler_rate;
static unsigned long max_sampler_rate;
static void execute_qsi(void *parms)
{
struct hws_execute_parms *ep = parms;
ep->rc = qsi(ep->buffer);
}
static void execute_ssctl(void *parms)
{
struct hws_execute_parms *ep = parms;
ep->rc = lsctl(ep->buffer);
}
static int smp_ctl_ssctl_stop(int cpu)
{
int rc;
struct hws_execute_parms ep;
struct hws_cpu_buffer *cb;
cb = &per_cpu(sampler_cpu_buffer, cpu);
cb->ssctl.es = 0;
cb->ssctl.cs = 0;
ep.buffer = &cb->ssctl;
smp_call_function_single(cpu, execute_ssctl, &ep, 1);
rc = ep.rc;
if (rc) {
printk(KERN_ERR "hwsampler: CPU %d CPUMF SSCTL failed.\n", cpu);
dump_stack();
}
ep.buffer = &cb->qsi;
smp_call_function_single(cpu, execute_qsi, &ep, 1);
if (cb->qsi.es || cb->qsi.cs) {
printk(KERN_EMERG "CPUMF sampling did not stop properly.\n");
dump_stack();
}
return rc;
}
static int smp_ctl_ssctl_deactivate(int cpu)
{
int rc;
struct hws_execute_parms ep;
struct hws_cpu_buffer *cb;
cb = &per_cpu(sampler_cpu_buffer, cpu);
cb->ssctl.es = 1;
cb->ssctl.cs = 0;
ep.buffer = &cb->ssctl;
smp_call_function_single(cpu, execute_ssctl, &ep, 1);
rc = ep.rc;
if (rc)
printk(KERN_ERR "hwsampler: CPU %d CPUMF SSCTL failed.\n", cpu