/*
 * Copyright (C) 2006-2007 PA Semi, Inc
 *
 * Author: Shashi Rao, PA Semi
 *
 * Maintained by: Olof Johansson <olof@lixom.net>
 *
 * Based on arch/powerpc/oprofile/op_model_power4.c
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * 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
 */

#include <linux/oprofile.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/percpu.h>
#include <asm/processor.h>
#include <asm/cputable.h>
#include <asm/oprofile_impl.h>
#include <asm/reg.h>

static unsigned char oprofile_running;

/* mmcr values are set in pa6t_reg_setup, used in pa6t_cpu_setup */
static u64 mmcr0_val;
static u64 mmcr1_val;

/* inited in pa6t_reg_setup */
static u64 reset_value[OP_MAX_COUNTER];

static inline u64 ctr_read(unsigned int i)
{
	switch (i) {
	case 0:
		return mfspr(SPRN_PA6T_PMC0);
	case 1:
		return mfspr(SPRN_PA6T_PMC1);
	case 2:
		return mfspr(SPRN_PA6T_PMC2);
	case 3:
		return mfspr(SPRN_PA6T_PMC3);
	case 4:
		return mfspr(SPRN_PA6T_PMC4);
	case 5:
		return mfspr(SPRN_PA6T_PMC5);
	default:
		printk(KERN_ERR "ctr_read called with bad arg %u\n", i);
		return 0;
	}
}

static inline void ctr_write(unsigned int i, u64 val)
{
	switch (i) {
	case 0:
		mtspr(SPRN_PA6T_PMC0, val);
		break;
	case 1:
		mtspr(SPRN_PA6T_PMC1, val);
		break;
	case 2:
		mtspr(SPRN_PA6T_PMC2, val);
		break;
	case 3:
		mtspr(SPRN_PA6T_PMC3, val);
		break;
	case 4:
		mtspr(SPRN_PA6T_PMC4, val);
		break;
	case 5:
		mtspr(SPRN_PA6T_PMC5, val);
		break;
	default:
		printk(KERN_ERR "ctr_write called with bad arg %u\n", i);
		break;
	}
}


/* precompute the values to stuff in the hardware registers */
static int pa6t_reg_setup(struct op_counter_config *ctr,
			   struct op_system_config *sys,
			   int num_ctrs)
{
	int pmc;

	/*
	 * adjust the mmcr0.en[0-5] and mmcr0.inten[0-5] values obtained from the
	 * event_mappings file by turning off the counters that the user doesn't
	 * care about
	 *
	 * setup user and kernel profiling
	 */
	for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++)
		if (!ctr[pmc].enabled) {
			sys->mmcr0 &= ~(0x1UL << pmc);
			sys->mmcr0 &= ~(0x1UL << (pmc+12));
			pr_debug("turned off counter %u\n", pmc);
		}

	if (sys->enable_kernel)
		sys->mmcr0 |= PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN;
	else
		sys->mmcr0 &= ~(PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN);

	if (sys->enable_user)
		sys->mmcr0 |= PA6T_MMCR0_PREN;
	else
		sys->mmcr0 &= ~PA6T_MMCR0_PREN;

	/*
	 * The performance counter event settings are given in the mmcr0 and
	 * mmcr1 values passed from the user in the op_system_config
	 * structure (sys variable).
	 */
	mmcr0_val = sys->mmcr0;
	mmcr1_val = sys->mmcr1;
	pr_debug("mmcr0_val inited to %016lx\n", sys->mmcr0);
	pr_debug("mmcr1_val inited to %016lx\n", sys->mmcr1);

	for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++) {
		/* counters are 40 bit. Move to cputable at some point? */
		reset_value[pmc] = (0x1UL << 39) - ctr[pmc].count;
		pr_debug("reset_value for pmc%u inited to 0x%lx\n",
				 pmc, reset_value[pmc]);
	}

	return 0;
}

/* configure registers on this cpu */
static int pa6t_cpu_setup(struct op_counter_config *ctr)
{
	u64 mmcr0 = mmcr0_val;
	u64 mmcr1 = mmcr1_val;

	/* Default is all PMCs off */
	mmcr0 &= ~(0x3FUL);
	mtspr(SPRN_PA6T_MMCR0, mmcr0);

	/* program selected programmable events in */
	mtspr(SPRN_PA6T_MMCR1, mmcr1);

	pr_debug("setup on cpu %d, mmcr0 %016lx\n", smp_processor_id(),
		mfspr(SPRN_PA6T_MMCR0));
	pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(),
		mfspr(SPRN_PA6T_MMCR1));

	return 0;
}

static int pa6t_start(struct op_counter_config *ctr)
{
	int i;

	/* Hold off event counting until rfid */
	u64 mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS;

	for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
		if (ctr[i].enabled)
			ctr_write(i, reset_value[i]);
		else
			ctr_write(i, 0UL);

	mtspr(SPRN_PA6T_MMCR0, mmcr0);

	oprofile_running = 1;

	pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);

	return 0;
}

static void pa6t_stop(void)
{
	u64 mmcr0;

	/* freeze counters */
	mmcr0 = mfspr(SPRN_PA6T_MMCR0);
	mmcr0 |= PA6T_MMCR0_FCM0;
	mtspr(SPRN_PA6T_MMCR0, mmcr0);

	oprofile_running = 0;

	pr_debug("stop on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
}

/* handle the perfmon overflow vector */
static void pa6t_handle_interrupt(struct pt_regs *regs,
				  struct op_counter_config *ctr)
{
	unsigned long pc = mfspr(SPRN_PA6T_SIAR);
	int is_kernel = is_kernel_addr(pc);
	u64 val;
	int i;
	u64 mmcr0;

	/* disable perfmon counting until rfid */
	mmcr0 = mfspr(SPRN_PA6T_MMCR0);
	mtspr(SPRN_PA6T_MMCR0, mmcr0 | PA6T_MMCR0_HANDDIS);

	/* Record samples. We've got one global bit for whether a sample
	 * was taken, so add it for any counter that triggered overflow.
	 */
	for (i = 0; i < cur_cpu_spec->num_pmcs; i++) {
		val = ctr_read(i);
		if (val & (0x1UL << 39)) { /* Overflow bit set */
			if (oprofile_running && ctr[i].enabled) {
				if (mmcr0 & PA6T_MMCR0_SIARLOG)
					oprofile_add_ext_sample(pc, regs, i, is_kernel);
				ctr_write(i, reset_value[i]);
			} else {
				ctr_write(i, 0UL);
			}
		}
	}

	/* Restore mmcr0 to a good known value since the PMI changes it */
	mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS;
	mtspr(SPRN_PA6T_MMCR0, mmcr0);
}

struct op_powerpc_model op_model_pa6t = {
	.reg_setup		= pa6t_reg_setup,
	.cpu_setup		= pa6t_cpu_setup,
	.start			= pa6t_start,
	.stop			= pa6t_stop,
	.handle_interrupt	= pa6t_handle_interrupt,
};
