/**
 * @file daemon/opd_ibs.h
 * AMD Family10h Instruction Based Sampling (IBS) handling.
 *
 * @remark Copyright 2008 OProfile authors
 * @remark Read the file COPYING
 *
 * @author Jason Yeh <jason.yeh@amd.com>
 * @author Paul Drongowski <paul.drongowski@amd.com>
 * @author Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
 * Copyright (c) 2008 Advanced Micro Devices, Inc.
 */

#ifndef OPD_IBS_H
#define OPD_IBS_H

#include <stdint.h>

#include "opd_ibs_macro.h"

struct transient;
struct opd_event;

/**
 * IBS information is processed in two steps. The first step decodes
 * hardware-level IBS information and saves it in decoded form. The
 * second step translates the decoded IBS information into IBS derived
 * events. IBS information is tallied and is reported as derived events.
 */

struct ibs_sample {
	struct ibs_fetch_sample * fetch;
	struct ibs_op_sample * op;
};

/**
 * This struct represents the hardware-level IBS fetch information.
 * Each field corresponds to a model-specific register (MSR.) See the
 * BIOS and Kernel Developer's Guide for AMD Model Family 10h Processors
 * for further details.
 */
struct ibs_fetch_sample {
	unsigned long int rip;
	/* MSRC001_1030 IBS Fetch Control Register */
	unsigned int ibs_fetch_ctl_low;
	unsigned int ibs_fetch_ctl_high;
	/* MSRC001_1031 IBS Fetch Linear Address Register */
	unsigned int ibs_fetch_lin_addr_low;
	unsigned int ibs_fetch_lin_addr_high;
	/* MSRC001_1032 IBS Fetch Physical Address Register */
	unsigned int ibs_fetch_phys_addr_low;
	unsigned int ibs_fetch_phys_addr_high;
	unsigned int dummy_event;
};



/** This struct represents the hardware-level IBS op information. */
struct ibs_op_sample {
	unsigned long int rip;
	/* MSRC001_1034 IBS Op Logical Address Register */
	unsigned int ibs_op_lin_addr_low;
	unsigned int ibs_op_lin_addr_high;
	/* MSRC001_1035 IBS Op Data Register */
	unsigned int ibs_op_data1_low;
	unsigned int ibs_op_data1_high;
	/* MSRC001_1036 IBS Op Data 2 Register */
	unsigned int ibs_op_data2_low;
	unsigned int ibs_op_data2_high;
	/* MSRC001_1037 IBS Op Data 3 Register */
	unsigned int ibs_op_data3_low;
	unsigned int ibs_op_data3_high;
	unsigned int ibs_op_ldst_linaddr_low;
	unsigned int ibs_op_ldst_linaddr_high;
	unsigned int ibs_op_phys_addr_low;
	unsigned int ibs_op_phys_addr_high;
};


enum IBSL1PAGESIZE {
	L1TLB4K = 0,
	L1TLB2M,
	L1TLB1G,
	L1TLB_INVALID
};


/**
 * Handle an IBS fetch sample escape code sequence. An IBS fetch sample
 * is represented as an escape code sequence. (See the comment for the
 * function code_ibs_op_sample() for the sequence of entries in the event
 * buffer.) When this function is called, the ESCAPE_CODE and IBS_FETCH_CODE
 * have already been removed from the event buffer. Thus, 7 more event buffer
 * entries are needed in order to process a complete IBS fetch sample.
 */
extern void code_ibs_fetch_sample(struct transient * trans);

/**
 * Handle an IBS op sample escape code sequence. An IBS op sample
 * is represented as an escape code sequence:
 *
 *    IBS fetch              IBS op
 *    ---------------        ----------------
 *    ESCAPE_CODE            ESCAPE_CODE
 *    IBS_FETCH_CODE         IBS_OP_CODE
 *    Offset                 Offset
 *    IbsFetchLinAd low      IbsOpRip low        <-- Logical (virtual) RIP
 *    IbsFetchLinAd high     IbsOpRip high       <-- Logical (virtual) RIP
 *    IbsFetchCtl low        IbsOpData low
 *    IbsFetchCtl high       IbsOpData high
 *    IbsFetchPhysAd low     IbsOpData2 low
 *    IbsFetchPhysAd high    IbsOpData2 high
 *                           IbsOpData3 low
 *                           IbsOpData3 high
 *                           IbsDcLinAd low
 *                           IbsDcLinAd high
 *                           IbsDcPhysAd low
 *                           IbsDcPhysAd high
 *
 * When this function is called, the ESCAPE_CODE and IBS_OP_CODE have
 * already been removed from the event buffer. Thus, 13 more event buffer
 * entries are needed to process a complete IBS op sample.
 *
 * The IbsFetchLinAd and IbsOpRip are the linear (virtual) addresses
 * that were generated by the IBS hardware. These addresses are mapped
 * into the offset.
 */
extern void code_ibs_op_sample(struct transient * trans);

/** Log the specified IBS derived event. */
extern void opd_log_ibs_event(unsigned int event, struct transient * trans);

/** Log the specified IBS cycle count. */
extern void opd_log_ibs_count(unsigned int event, struct transient * trans, unsigned int count);


#endif /*OPD_IBS_H*/