[BACK]Return to op_model_fsl_booke.c CVS log [TXT][DIR] Up to [Development] / linux-2.6-xfs / arch / powerpc / oprofile

File: [Development] / linux-2.6-xfs / arch / powerpc / oprofile / Attic / op_model_fsl_booke.c (download)

Revision 1.6, Wed Sep 12 17:09:56 2007 UTC (10 years, 1 month ago) by tes.longdrop.melbourne.sgi.com
Branch: MAIN
Changes since 1.5: +8 -3 lines

Update 2.6.x-xfs to 2.6.23-rc4.

Also update fs/xfs with external mainline changes.
There were 12 such missing commits that I detected:

--------
commit ad690ef9e690f6c31f7d310b09ef1314bcec9033
Author: Al Viro <viro@ftp.linux.org.uk>
    xfs ioctl __user annotations

commit 20c2df83d25c6a95affe6157a4c9cac4cf5ffaac
Author: Paul Mundt <lethal@linux-sh.org>
    mm: Remove slab destructors from kmem_cache_create().

commit d0217ac04ca6591841e5665f518e38064f4e65bd
Author: Nick Piggin <npiggin@suse.de>
    mm: fault feedback #1

commit 54cb8821de07f2ffcd28c380ce9b93d5784b40d7
Author: Nick Piggin <npiggin@suse.de>
    mm: merge populate and nopage into fault (fixes nonlinear)

commit d00806b183152af6d24f46f0c33f14162ca1262a
Author: Nick Piggin <npiggin@suse.de>
    mm: fix fault vs invalidate race for linear mappings

commit a569425512253992cc64ebf8b6d00a62f986db3e
Author: Christoph Hellwig <hch@infradead.org>
    knfsd: exportfs: add exportfs.h header

commit 831441862956fffa17b9801db37e6ea1650b0f69
Author: Rafael J. Wysocki <rjw@sisk.pl>
    Freezer: make kernel threads nonfreezable by default

commit 8e1f936b73150f5095448a0fee6d4f30a1f9001d
Author: Rusty Russell <rusty@rustcorp.com.au>
    mm: clean up and kernelify shrinker registration

commit 5ffc4ef45b3b0a57872f631b4e4ceb8ace0d7496
Author: Jens Axboe <jens.axboe@oracle.com>
    sendfile: remove .sendfile from filesystems that use generic_file_sendfile()

commit 8bb7844286fb8c9fce6f65d8288aeb09d03a5e0d
Author: Rafael J. Wysocki <rjw@sisk.pl>
    Add suspend-related notifications for CPU hotplug

commit 59c51591a0ac7568824f541f57de967e88adaa07
Author: Michael Opdenacker <michael@free-electrons.com>
    Fix occurrences of "the the "

commit 0ceb331433e8aad9c5f441a965d7c681f8b9046f
Author: Dmitriy Monakhov <dmonakhov@openvz.org>
    mm: move common segment checks to separate helper function
--------
Merge of 2.6.x-xfs-melb:linux:29656b by kenmcd.

/*
 * arch/powerpc/oprofile/op_model_fsl_booke.c
 *
 * Freescale Book-E oprofile support, based on ppc64 oprofile support
 * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
 *
 * Copyright (c) 2004 Freescale Semiconductor, Inc
 *
 * Author: Andy Fleming
 * Maintainer: Kumar Gala <galak@kernel.crashing.org>
 *
 * 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.
 */

#include <linux/oprofile.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/processor.h>
#include <asm/cputable.h>
#include <asm/reg_booke.h>
#include <asm/page.h>
#include <asm/pmc.h>
#include <asm/oprofile_impl.h>

static unsigned long reset_value[OP_MAX_COUNTER];

static int num_counters;
static int oprofile_running;

static inline u32 get_pmlca(int ctr)
{
	u32 pmlca;

	switch (ctr) {
		case 0:
			pmlca = mfpmr(PMRN_PMLCA0);
			break;
		case 1:
			pmlca = mfpmr(PMRN_PMLCA1);
			break;
		case 2:
			pmlca = mfpmr(PMRN_PMLCA2);
			break;
		case 3:
			pmlca = mfpmr(PMRN_PMLCA3);
			break;
		default:
			panic("Bad ctr number\n");
	}

	return pmlca;
}

static inline void set_pmlca(int ctr, u32 pmlca)
{
	switch (ctr) {
		case 0:
			mtpmr(PMRN_PMLCA0, pmlca);
			break;
		case 1:
			mtpmr(PMRN_PMLCA1, pmlca);
			break;
		case 2:
			mtpmr(PMRN_PMLCA2, pmlca);
			break;
		case 3:
			mtpmr(PMRN_PMLCA3, pmlca);
			break;
		default:
			panic("Bad ctr number\n");
	}
}

static inline unsigned int ctr_read(unsigned int i)
{
	switch(i) {
		case 0:
			return mfpmr(PMRN_PMC0);
		case 1:
			return mfpmr(PMRN_PMC1);
		case 2:
			return mfpmr(PMRN_PMC2);
		case 3:
			return mfpmr(PMRN_PMC3);
		default:
			return 0;
	}
}

static inline void ctr_write(unsigned int i, unsigned int val)
{
	switch(i) {
		case 0:
			mtpmr(PMRN_PMC0, val);
			break;
		case 1:
			mtpmr(PMRN_PMC1, val);
			break;
		case 2:
			mtpmr(PMRN_PMC2, val);
			break;
		case 3:
			mtpmr(PMRN_PMC3, val);
			break;
		default:
			break;
	}
}


static void init_pmc_stop(int ctr)
{
	u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU |
			PMLCA_FCM1 | PMLCA_FCM0);
	u32 pmlcb = 0;

	switch (ctr) {
		case 0:
			mtpmr(PMRN_PMLCA0, pmlca);
			mtpmr(PMRN_PMLCB0, pmlcb);
			break;
		case 1:
			mtpmr(PMRN_PMLCA1, pmlca);
			mtpmr(PMRN_PMLCB1, pmlcb);
			break;
		case 2:
			mtpmr(PMRN_PMLCA2, pmlca);
			mtpmr(PMRN_PMLCB2, pmlcb);
			break;
		case 3:
			mtpmr(PMRN_PMLCA3, pmlca);
			mtpmr(PMRN_PMLCB3, pmlcb);
			break;
		default:
			panic("Bad ctr number!\n");
	}
}

static void set_pmc_event(int ctr, int event)
{
	u32 pmlca;

	pmlca = get_pmlca(ctr);

	pmlca = (pmlca & ~PMLCA_EVENT_MASK) |
		((event << PMLCA_EVENT_SHIFT) &
		 PMLCA_EVENT_MASK);

	set_pmlca(ctr, pmlca);
}

static void set_pmc_user_kernel(int ctr, int user, int kernel)
{
	u32 pmlca;

	pmlca = get_pmlca(ctr);

	if(user)
		pmlca &= ~PMLCA_FCU;
	else
		pmlca |= PMLCA_FCU;

	if(kernel)
		pmlca &= ~PMLCA_FCS;
	else
		pmlca |= PMLCA_FCS;

	set_pmlca(ctr, pmlca);
}

static void set_pmc_marked(int ctr, int mark0, int mark1)
{
	u32 pmlca = get_pmlca(ctr);

	if(mark0)
		pmlca &= ~PMLCA_FCM0;
	else
		pmlca |= PMLCA_FCM0;

	if(mark1)
		pmlca &= ~PMLCA_FCM1;
	else
		pmlca |= PMLCA_FCM1;

	set_pmlca(ctr, pmlca);
}

static void pmc_start_ctr(int ctr, int enable)
{
	u32 pmlca = get_pmlca(ctr);

	pmlca &= ~PMLCA_FC;

	if (enable)
		pmlca |= PMLCA_CE;
	else
		pmlca &= ~PMLCA_CE;

	set_pmlca(ctr, pmlca);
}

static void pmc_start_ctrs(int enable)
{
	u32 pmgc0 = mfpmr(PMRN_PMGC0);

	pmgc0 &= ~PMGC0_FAC;
	pmgc0 |= PMGC0_FCECE;

	if (enable)
		pmgc0 |= PMGC0_PMIE;
	else
		pmgc0 &= ~PMGC0_PMIE;

	mtpmr(PMRN_PMGC0, pmgc0);
}

static void pmc_stop_ctrs(void)
{
	u32 pmgc0 = mfpmr(PMRN_PMGC0);

	pmgc0 |= PMGC0_FAC;

	pmgc0 &= ~(PMGC0_PMIE | PMGC0_FCECE);

	mtpmr(PMRN_PMGC0, pmgc0);
}

static void dump_pmcs(void)
{
	printk("pmgc0: %x\n", mfpmr(PMRN_PMGC0));
	printk("pmc\t\tpmlca\t\tpmlcb\n");
	printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC0),
			mfpmr(PMRN_PMLCA0), mfpmr(PMRN_PMLCB0));
	printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC1),
			mfpmr(PMRN_PMLCA1), mfpmr(PMRN_PMLCB1));
	printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC2),
			mfpmr(PMRN_PMLCA2), mfpmr(PMRN_PMLCB2));
	printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC3),
			mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
}

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

	/* freeze all counters */
	pmc_stop_ctrs();

	for (i = 0;i < num_counters;i++) {
		init_pmc_stop(i);

		set_pmc_event(i, ctr[i].event);

		set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel);
	}

	return 0;
}

static int fsl_booke_reg_setup(struct op_counter_config *ctr,
			     struct op_system_config *sys,
			     int num_ctrs)
{
	int i;

	num_counters = num_ctrs;

	/* Our counters count up, and "count" refers to
	 * how much before the next interrupt, and we interrupt
	 * on overflow.  So we calculate the starting value
	 * which will give us "count" until overflow.
	 * Then we set the events on the enabled counters */
	for (i = 0; i < num_counters; ++i)
		reset_value[i] = 0x80000000UL - ctr[i].count;

	return 0;
}

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

	mtmsr(mfmsr() | MSR_PMM);

	for (i = 0; i < num_counters; ++i) {
		if (ctr[i].enabled) {
			ctr_write(i, reset_value[i]);
			/* Set each enabled counter to only
			 * count when the Mark bit is *not* set */
			set_pmc_marked(i, 1, 0);
			pmc_start_ctr(i, 1);
		} else {
			ctr_write(i, 0);

			/* Set the ctr to be stopped */
			pmc_start_ctr(i, 0);
		}
	}

	/* Clear the freeze bit, and enable the interrupt.
	 * The counters won't actually start until the rfi clears
	 * the PMM bit */
	pmc_start_ctrs(1);

	oprofile_running = 1;

	pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(),
			mfpmr(PMRN_PMGC0));

	return 0;
}

static void fsl_booke_stop(void)
{
	/* freeze counters */
	pmc_stop_ctrs();

	oprofile_running = 0;

	pr_debug("stop on cpu %d, pmgc0 %x\n", smp_processor_id(),
			mfpmr(PMRN_PMGC0));

	mb();
}


static void fsl_booke_handle_interrupt(struct pt_regs *regs,
				    struct op_counter_config *ctr)
{
	unsigned long pc;
	int is_kernel;
	int val;
	int i;

	/* set the PMM bit (see comment below) */
	mtmsr(mfmsr() | MSR_PMM);

	pc = regs->nip;
	is_kernel = is_kernel_addr(pc);

	for (i = 0; i < num_counters; ++i) {
		val = ctr_read(i);
		if (val < 0) {
			if (oprofile_running && ctr[i].enabled) {
				oprofile_add_ext_sample(pc, regs, i, is_kernel);
				ctr_write(i, reset_value[i]);
			} else {
				ctr_write(i, 0);
			}
		}
	}

	/* The freeze bit was set by the interrupt. */
	/* Clear the freeze bit, and reenable the interrupt.
	 * The counters won't actually start until the rfi clears
	 * the PMM bit */
	pmc_start_ctrs(1);
}

struct op_powerpc_model op_model_fsl_booke = {
	.reg_setup		= fsl_booke_reg_setup,
	.cpu_setup		= fsl_booke_cpu_setup,
	.start			= fsl_booke_start,
	.stop			= fsl_booke_stop,
	.handle_interrupt	= fsl_booke_handle_interrupt,
};