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 = (pc >= KERNELBASE);

	for (i = 0; i < num_counters; ++i) {
		val = ctr_read(i);
		if (val < 0) {
			if (oprofile_running && ctr[i].enabled) {
				oprofile_add_pc(pc, is_kernel, i);
				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);
}
static inline void
op_add_pm(unsigned long pc, int kern, unsigned long counter,
	  struct op_counter_config *ctr, unsigned long event)
{
	unsigned long fake_counter = 2 + event;
	if (counter == 1)
		fake_counter += PM_NUM_COUNTERS;
	if (ctr[fake_counter].enabled)
		oprofile_add_pc(pc, kern, fake_counter);
}
Example #3
0
static irqreturn_t 
xenoprof_ovf_interrupt(int irq, void * dev_id, struct pt_regs * regs)
{
	int head, tail, size;
	struct xenoprof_buf * buf;
	int cpu;

	cpu = smp_processor_id();
	buf = xenoprof_buf[cpu];

	head = buf->event_head;
	tail = buf->event_tail;
	size = buf->event_size;

	if (tail > head) {
		while (tail < size) {
			oprofile_add_pc(buf->event_log[tail].eip,
					buf->event_log[tail].mode,
					buf->event_log[tail].event);
			oprofile_samples++;
			tail++;
		}
		tail = 0;
	}
	while (tail < head) {
		oprofile_add_pc(buf->event_log[tail].eip,
				buf->event_log[tail].mode,
				buf->event_log[tail].event);
		oprofile_samples++;
		tail++;
	}

	buf->event_tail = tail;

	return IRQ_HANDLED;
}
void tile_backtrace(struct pt_regs *const regs, unsigned int depth)
{
	struct KBacktraceIterator kbt;
	unsigned int i;

	/*
	 * Get the address just after the "jalr" instruction that
	 * jumps to the handler for a syscall.  When we find this
	 * address in a backtrace, we silently ignore it, which gives
	 * us a one-step backtrace connection from the sys_xxx()
	 * function in the kernel to the xxx() function in libc.
	 * Otherwise, we lose the ability to properly attribute time
	 * from the libc calls to the kernel implementations, since
	 * oprofile only considers PCs from backtraces a pair at a time.
	 */
	unsigned long handle_syscall_pc = handle_syscall_link_address();

	KBacktraceIterator_init(&kbt, NULL, regs);
	kbt.profile = 1;

	/*
	 * The sample for the pc is already recorded.  Now we are adding the
	 * address of the callsites on the stack.  Our iterator starts
	 * with the frame of the (already sampled) call site.  If our
	 * iterator contained a "return address" field, we could have just
	 * used it and wouldn't have needed to skip the first
	 * frame.  That's in effect what the arm and x86 versions do.
	 * Instead we peel off the first iteration to get the equivalent
	 * behavior.
	 */

	if (KBacktraceIterator_end(&kbt))
		return;
	KBacktraceIterator_next(&kbt);

	for (i = 0; i < depth; ++i) {
		int is_kernel;
		unsigned long pc;
		if (KBacktraceIterator_end(&kbt))
			break;
		pc = kbt.it.pc;
		is_kernel = (pc >= PAGE_OFFSET &&
			     !is_arch_mappable_range(pc, 1));
		if (pc != handle_syscall_pc)
			oprofile_add_pc(pc, is_kernel, 0);
		KBacktraceIterator_next(&kbt);
	}
}
static void rs64_handle_interrupt(struct pt_regs *regs,
				  struct op_counter_config *ctr)
{
	unsigned int mmcr0;
	int val;
	int i;
	unsigned long pc = mfspr(SPRN_SIAR);
	int is_kernel = (pc >= KERNELBASE);

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

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

	mmcr0 = mfspr(SPRN_MMCR0);

	/* reset the perfmon trigger */
	mmcr0 |= MMCR0_PMXE;

	/*
	 * now clear the freeze bit, counting will not start until we
	 * rfid from this exception, because only at that point will
	 * the PMM bit be cleared
	 */
	mmcr0 &= ~MMCR0_FC;
	mtspr(SPRN_MMCR0, mmcr0);
}
Example #6
0
static void xenoprof_add_pc(xenoprof_buf_t *buf, int is_passive)
{
	int head, tail, size;
	int tracing = 0;

	head = buf->event_head;
	tail = buf->event_tail;
	size = buf->event_size;

	while (tail != head) {
		if (xenoprof_is_escape(buf, tail) &&
		    xenoprof_get_event(buf, tail) == XENOPROF_TRACE_BEGIN) {
			tracing=1;
			oprofile_add_mode(buf->event_log[tail].mode);
			if (!is_passive)
				oprofile_samples++;
			else
				p_oprofile_samples++;
			
		} else {
			oprofile_add_pc(buf->event_log[tail].eip,
					buf->event_log[tail].mode,
					buf->event_log[tail].event);
			if (!tracing) {
				if (!is_passive)
					oprofile_samples++;
				else
					p_oprofile_samples++;
			}
       
		}
		tail++;
		if(tail==size)
		    tail=0;
	}
	buf->event_tail = tail;
}
static void
ev67_handle_interrupt(unsigned long which, struct pt_regs *regs,
		      struct op_counter_config *ctr)
{
	unsigned long pmpc, pctr_ctl;
	int kern = !user_mode(regs);
	int mispredict = 0;
	union {
		unsigned long v;
		struct {
			unsigned reserved:	30; /*  0-29 */
			unsigned overcount:	 3; /* 30-32 */
			unsigned icache_miss:	 1; /*    33 */
			unsigned trap_type:	 4; /* 34-37 */
			unsigned load_store:	 1; /*    38 */
			unsigned trap:		 1; /*    39 */
			unsigned mispredict:	 1; /*    40 */
		} fields;
	} i_stat;

	enum trap_types {
		TRAP_REPLAY,
		TRAP_INVALID0,
		TRAP_DTB_DOUBLE_MISS_3,
		TRAP_DTB_DOUBLE_MISS_4,
		TRAP_FP_DISABLED,
		TRAP_UNALIGNED,
		TRAP_DTB_SINGLE_MISS,
		TRAP_DSTREAM_FAULT,
		TRAP_OPCDEC,
		TRAP_INVALID1,
		TRAP_MACHINE_CHECK,
		TRAP_INVALID2,
		TRAP_ARITHMETIC,
		TRAP_INVALID3,
		TRAP_MT_FPCR,
		TRAP_RESET
	};

	pmpc = wrperfmon(9, 0);
	/* ??? Don't know how to handle physical-mode PALcode address.  */
	if (pmpc & 1)
		return;
	pmpc &= ~2;		/* clear reserved bit */

	i_stat.v = wrperfmon(8, 0);
	if (i_stat.fields.trap) {
		switch (i_stat.fields.trap_type) {
		case TRAP_INVALID1:
		case TRAP_INVALID2:
		case TRAP_INVALID3:
			/* Pipeline redirection ocurred. PMPC points
			   to PALcode. Recognize ITB miss by PALcode
			   offset address, and get actual PC from
			   EXC_ADDR.  */
			oprofile_add_pc(regs->pc, kern, which);
			if ((pmpc & ((1 << 15) - 1)) ==  581)
				op_add_pm(regs->pc, kern, which,
					  ctr, PM_ITB_MISS);
			/* Most other bit and counter values will be
			   those for the first instruction in the
			   fault handler, so we're done.  */
			return;
		case TRAP_REPLAY:
			op_add_pm(pmpc, kern, which, ctr,
				  (i_stat.fields.load_store
				   ? PM_LOAD_STORE : PM_REPLAY));
			break;
		case TRAP_DTB_DOUBLE_MISS_3:
		case TRAP_DTB_DOUBLE_MISS_4:
		case TRAP_DTB_SINGLE_MISS:
			op_add_pm(pmpc, kern, which, ctr, PM_DTB_MISS);
			break;
		case TRAP_UNALIGNED:
			op_add_pm(pmpc, kern, which, ctr, PM_UNALIGNED);
			break;
		case TRAP_INVALID0:
		case TRAP_FP_DISABLED:
		case TRAP_DSTREAM_FAULT:
		case TRAP_OPCDEC:
		case TRAP_MACHINE_CHECK:
		case TRAP_ARITHMETIC:
		case TRAP_MT_FPCR:
		case TRAP_RESET:
			break;
		}

		/* ??? JSR/JMP/RET/COR or HW_JSR/HW_JMP/HW_RET/HW_COR
		   mispredicts do not set this bit but can be
		   recognized by the presence of one of these
		   instructions at the PMPC location with bit 39
		   set.  */
		if (i_stat.fields.mispredict) {
			mispredict = 1;
			op_add_pm(pmpc, kern, which, ctr, PM_MISPREDICT);
		}
	}

	oprofile_add_pc(pmpc, kern, which);

	pctr_ctl = wrperfmon(5, 0);
	if (pctr_ctl & (1UL << 27))
		op_add_pm(pmpc, kern, which, ctr, PM_STALLED);

	/* Unfortunately, TAK is undefined on mispredicted branches.
	   ??? It is also undefined for non-cbranch insns, should
	   check that.  */
	if (!mispredict && pctr_ctl & (1UL << 0))
		op_add_pm(pmpc, kern, which, ctr, PM_TAKEN);
}
Example #8
0
static void
ev67_handle_interrupt(unsigned long which, struct pt_regs *regs,
		      struct op_counter_config *ctr)
{
	unsigned long pmpc, pctr_ctl;
	int kern = !user_mode(regs);
	int mispredict = 0;
	union {
		unsigned long v;
		struct {
			unsigned reserved:	30; 
			unsigned overcount:	 3; 
			unsigned icache_miss:	 1; 
			unsigned trap_type:	 4; 
			unsigned load_store:	 1; 
			unsigned trap:		 1; 
			unsigned mispredict:	 1; 
		} fields;
	} i_stat;

	enum trap_types {
		TRAP_REPLAY,
		TRAP_INVALID0,
		TRAP_DTB_DOUBLE_MISS_3,
		TRAP_DTB_DOUBLE_MISS_4,
		TRAP_FP_DISABLED,
		TRAP_UNALIGNED,
		TRAP_DTB_SINGLE_MISS,
		TRAP_DSTREAM_FAULT,
		TRAP_OPCDEC,
		TRAP_INVALID1,
		TRAP_MACHINE_CHECK,
		TRAP_INVALID2,
		TRAP_ARITHMETIC,
		TRAP_INVALID3,
		TRAP_MT_FPCR,
		TRAP_RESET
	};

	pmpc = wrperfmon(9, 0);
	
	if (pmpc & 1)
		return;
	pmpc &= ~2;		

	i_stat.v = wrperfmon(8, 0);
	if (i_stat.fields.trap) {
		switch (i_stat.fields.trap_type) {
		case TRAP_INVALID1:
		case TRAP_INVALID2:
		case TRAP_INVALID3:
			oprofile_add_pc(regs->pc, kern, which);
			if ((pmpc & ((1 << 15) - 1)) ==  581)
				op_add_pm(regs->pc, kern, which,
					  ctr, PM_ITB_MISS);
			return;
		case TRAP_REPLAY:
			op_add_pm(pmpc, kern, which, ctr,
				  (i_stat.fields.load_store
				   ? PM_LOAD_STORE : PM_REPLAY));
			break;
		case TRAP_DTB_DOUBLE_MISS_3:
		case TRAP_DTB_DOUBLE_MISS_4:
		case TRAP_DTB_SINGLE_MISS:
			op_add_pm(pmpc, kern, which, ctr, PM_DTB_MISS);
			break;
		case TRAP_UNALIGNED:
			op_add_pm(pmpc, kern, which, ctr, PM_UNALIGNED);
			break;
		case TRAP_INVALID0:
		case TRAP_FP_DISABLED:
		case TRAP_DSTREAM_FAULT:
		case TRAP_OPCDEC:
		case TRAP_MACHINE_CHECK:
		case TRAP_ARITHMETIC:
		case TRAP_MT_FPCR:
		case TRAP_RESET:
			break;
		}

		if (i_stat.fields.mispredict) {
			mispredict = 1;
			op_add_pm(pmpc, kern, which, ctr, PM_MISPREDICT);
		}
	}

	oprofile_add_pc(pmpc, kern, which);

	pctr_ctl = wrperfmon(5, 0);
	if (pctr_ctl & (1UL << 27))
		op_add_pm(pmpc, kern, which, ctr, PM_STALLED);

	if (!mispredict && pctr_ctl & (1UL << 0))
		op_add_pm(pmpc, kern, which, ctr, PM_TAKEN);
}