760 lines
17 KiB
C
760 lines
17 KiB
C
|
/* Copyright (c) 2010, The Linux Foundation. All rights reserved.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License version 2 and
|
||
|
* only 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.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
per-axi
|
||
|
DESCRIPTION
|
||
|
Functions related to AXI bus performance counter manipulations.
|
||
|
*/
|
||
|
|
||
|
#include <linux/io.h>
|
||
|
#include <linux/err.h>
|
||
|
#include <linux/init.h>
|
||
|
#include <linux/platform_device.h>
|
||
|
#include <linux/proc_fs.h>
|
||
|
#include "asm/uaccess.h"
|
||
|
#include "per-axi.h"
|
||
|
#include "perf.h"
|
||
|
|
||
|
/*
|
||
|
Definitions for AXI register addresses, macros to set and get register values
|
||
|
*/
|
||
|
#define AXI_BASE_SIZE 0x00004000
|
||
|
#define AXI_REG_BASE (AXI_BASE + 0x00000000)
|
||
|
#define AXI_REG_BASE_PHYS 0xa8200000
|
||
|
|
||
|
#define __inpdw(port) ioread32(port)
|
||
|
#define in_dword_masked(addr, mask) (__inpdw(addr) & (mask))
|
||
|
#define __outpdw(port, val) (iowrite32((uint32_t) (val), port))
|
||
|
#define out_dword(addr, val) __outpdw(addr, val)
|
||
|
|
||
|
#define HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_ADDR \
|
||
|
(AXI_REG_BASE + 0x00003434)
|
||
|
#define HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_RMSK 0xffff
|
||
|
#define HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_IN \
|
||
|
in_dword_masked(HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_ADDR, \
|
||
|
HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_RMSK)
|
||
|
|
||
|
#define HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_ADDR (AXI_REG_BASE + 0x00003438)
|
||
|
#define HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_RMSK 0xffff
|
||
|
#define HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_IN \
|
||
|
in_dword_masked(HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_ADDR, \
|
||
|
HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_RMSK)
|
||
|
|
||
|
#define HWIO_AXI_MONITOR_SELECTION_REG0_ADDR (AXI_REG_BASE + 0x00003428)
|
||
|
#define HWIO_AXI_MONITOR_SELECTION_REG1_ADDR (AXI_REG_BASE + 0x0000342c)
|
||
|
#define HWIO_AXI_MONITOR_TENURE_SELECTION_REG_ADDR (AXI_REG_BASE + 0x00003430)
|
||
|
#define HWIO_AXI_MONITOR_SELECTION_REG0_ETC_BMSK 0x4000
|
||
|
#define HWIO_AXI_MONITOR_SELECTION_REG0_ECC_BMSK 0x2000
|
||
|
#define HWIO_AXI_MONITOR_SELECTION_REG0_EEC1_BMSK 0x800
|
||
|
#define HWIO_AXI_MONITOR_SELECTION_REG0_EEC0_BMSK 0x200
|
||
|
#define HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_OUT(v) \
|
||
|
out_dword(HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_ADDR, v)
|
||
|
#define HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_OUT(v) \
|
||
|
out_dword(HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_ADDR, v)
|
||
|
#define HWIO_AXI_MONITOR_SELECTION_REG0_OUT(v) \
|
||
|
out_dword(HWIO_AXI_MONITOR_SELECTION_REG0_ADDR, v)
|
||
|
#define HWIO_AXI_MONITOR_SELECTION_REG1_OUT(v) \
|
||
|
out_dword(HWIO_AXI_MONITOR_SELECTION_REG1_ADDR, v)
|
||
|
#define HWIO_AXI_MONITOR_TENURE_SELECTION_REG_OUT(v) \
|
||
|
out_dword(HWIO_AXI_MONITOR_TENURE_SELECTION_REG_ADDR, v)
|
||
|
#define HWIO_AXI_MONITOR_SELECTION_REG0_RMSK 0xffff
|
||
|
#define HWIO_AXI_MONITOR_SELECTION_REG0_IN \
|
||
|
in_dword_masked(HWIO_AXI_MONITOR_SELECTION_REG0_ADDR, \
|
||
|
HWIO_AXI_MONITOR_SELECTION_REG0_RMSK)
|
||
|
|
||
|
#define HWIO_AXI_CONFIGURATION_REG_ADDR (AXI_REG_BASE + 0x00000008)
|
||
|
#define HWIO_AXI_CONFIGURATION_REG_OUT(v) \
|
||
|
out_dword(HWIO_AXI_CONFIGURATION_REG_ADDR, v)
|
||
|
#define HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK 0x0
|
||
|
#define HWIO_AXI_CONFIGURATION_REG_DISABLE 0x2
|
||
|
#define AXI_EVTSEL_ENABLE_MASK 0x6a00
|
||
|
#define AXI_EVTSEL_DISABLE_MASK 0x95ff
|
||
|
#define AXI_EVTSEL_RESET_MASK 0xfe40
|
||
|
|
||
|
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG0_ADDR (AXI_REG_BASE + 0x00003450)
|
||
|
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG0_RMSK 0xffff
|
||
|
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG0_SHFT 0
|
||
|
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG0_IN \
|
||
|
in_dword_masked(HWIO_AXI_MONITOR_EVENT_LOWER_REG0_ADDR, \
|
||
|
HWIO_AXI_MONITOR_EVENT_LOWER_REG0_RMSK)
|
||
|
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG0_ADDR (AXI_REG_BASE + 0x00003454)
|
||
|
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG0_RMSK 0xffff
|
||
|
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG0_SHFT 0
|
||
|
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG0_IN \
|
||
|
in_dword_masked(HWIO_AXI_MONITOR_EVENT_UPPER_REG0_ADDR, \
|
||
|
HWIO_AXI_MONITOR_EVENT_UPPER_REG0_RMSK)
|
||
|
|
||
|
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG1_ADDR (AXI_REG_BASE + 0x00003458)
|
||
|
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG1_RMSK 0xffff
|
||
|
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG1_SHFT 0
|
||
|
#define HWIO_AXI_MONITOR_EVENT_LOWER_REG1_IN \
|
||
|
in_dword_masked(HWIO_AXI_MONITOR_EVENT_LOWER_REG1_ADDR, \
|
||
|
HWIO_AXI_MONITOR_EVENT_LOWER_REG1_RMSK)
|
||
|
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG1_ADDR (AXI_REG_BASE + 0x0000345c)
|
||
|
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG1_RMSK 0xffff
|
||
|
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG1_SHFT 0
|
||
|
#define HWIO_AXI_MONITOR_EVENT_UPPER_REG1_IN \
|
||
|
in_dword_masked(HWIO_AXI_MONITOR_EVENT_UPPER_REG1_ADDR, \
|
||
|
HWIO_AXI_MONITOR_EVENT_UPPER_REG1_RMSK)
|
||
|
|
||
|
#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_ADDR (AXI_REG_BASE + 0x00003448)
|
||
|
#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_RMSK 0xffff
|
||
|
#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_SHFT 0
|
||
|
#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_IN \
|
||
|
in_dword_masked(HWIO_AXI_MONITOR_TENURE_LOWER_REG_ADDR, \
|
||
|
HWIO_AXI_MONITOR_TENURE_LOWER_REG_RMSK)
|
||
|
#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_ADDR (AXI_REG_BASE + 0x00003444)
|
||
|
#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_RMSK 0xffff
|
||
|
#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_SHFT 0
|
||
|
#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_IN \
|
||
|
in_dword_masked(HWIO_AXI_MONITOR_TENURE_UPPER_REG_ADDR, \
|
||
|
HWIO_AXI_MONITOR_TENURE_UPPER_REG_RMSK)
|
||
|
|
||
|
#define HWIO_AXI_MONITOR_MIN_REG_ADDR (AXI_REG_BASE + 0x0000343c)
|
||
|
#define HWIO_AXI_MONITOR_MIN_REG_RMSK 0xffff
|
||
|
#define HWIO_AXI_MONITOR_MIN_REG_SHFT 0
|
||
|
#define HWIO_AXI_MONITOR_MIN_REG_IN \
|
||
|
in_dword_masked(HWIO_AXI_MONITOR_MIN_REG_ADDR, \
|
||
|
HWIO_AXI_MONITOR_MIN_REG_RMSK)
|
||
|
#define HWIO_AXI_MONITOR_MAX_REG_ADDR (AXI_REG_BASE + 0x00003440)
|
||
|
#define HWIO_AXI_MONITOR_MAX_REG_RMSK 0xffff
|
||
|
#define HWIO_AXI_MONITOR_MAX_REG_SHFT 0
|
||
|
#define HWIO_AXI_MONITOR_MAX_REG_IN \
|
||
|
in_dword_masked(HWIO_AXI_MONITOR_MAX_REG_ADDR, \
|
||
|
HWIO_AXI_MONITOR_MAX_REG_RMSK)
|
||
|
#define HWIO_AXI_MONITOR_LAST_TENURE_REG_ADDR (AXI_REG_BASE + 0x0000344c)
|
||
|
#define HWIO_AXI_MONITOR_LAST_TENURE_REG_RMSK 0xffff
|
||
|
#define HWIO_AXI_MONITOR_LAST_TENURE_REG_SHFT 0
|
||
|
#define HWIO_AXI_MONITOR_LAST_TENURE_REG_IN \
|
||
|
in_dword_masked(HWIO_AXI_MONITOR_LAST_TENURE_REG_ADDR, \
|
||
|
HWIO_AXI_MONITOR_LAST_TENURE_REG_RMSK)
|
||
|
#define HWIO_AXI_MONITOR_TENURE_UPPER_REG_OUT(v) \
|
||
|
out_dword(HWIO_AXI_MONITOR_TENURE_UPPER_REG_ADDR, v)
|
||
|
#define HWIO_AXI_MONITOR_TENURE_LOWER_REG_OUT(v) \
|
||
|
out_dword(HWIO_AXI_MONITOR_TENURE_LOWER_REG_ADDR, v)
|
||
|
|
||
|
#define HWIO_AXI_RESET_ALL 0x9400
|
||
|
#define HWIO_AXI_ENABLE_ALL_NOCYCLES 0x4a00
|
||
|
#define HWIO_AXI_DISABLE_ALL 0xb500
|
||
|
uint32_t AXI_BASE;
|
||
|
|
||
|
unsigned int is_first = 1;
|
||
|
struct perf_mon_axi_data pm_axi_info;
|
||
|
struct perf_mon_axi_cnts axi_cnts;
|
||
|
|
||
|
/*
|
||
|
FUNCTION get_axi_sel_reg0
|
||
|
|
||
|
DESCRIPTION
|
||
|
Retrieve the value of AXI_SEL_REG0
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
AXI_SEL_REG0
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
unsigned long get_axi_sel_reg0(void)
|
||
|
{
|
||
|
return pm_axi_info.sel_reg0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION get_axi_sel_reg1
|
||
|
|
||
|
DESCRIPTION
|
||
|
Retrieve the value of AXI_SEL_REG1
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
AXI_SEL_REG1
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
unsigned long get_axi_sel_reg1(void)
|
||
|
{
|
||
|
return pm_axi_info.sel_reg1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION get_axi_ten_sel_reg
|
||
|
|
||
|
DESCRIPTION
|
||
|
Retrieve the value of AXI_TEN_REG
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
AXI_TEN_REG
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
unsigned long get_axi_ten_sel_reg(void)
|
||
|
{
|
||
|
return pm_axi_info.ten_sel_reg;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION get_axi_valid
|
||
|
|
||
|
DESCRIPTION
|
||
|
Retrieve the value of AXI valid bit
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
AXI Valid bit
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
unsigned long get_axi_valid(void)
|
||
|
{
|
||
|
return pm_axi_info.valid;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION get_axi_enable
|
||
|
|
||
|
DESCRIPTION
|
||
|
Retrieve the value of AXI enable bit
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
AXI enable bit
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
unsigned long get_axi_enable(void)
|
||
|
{
|
||
|
return pm_axi_info.enable;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION get_axi_clear
|
||
|
|
||
|
DESCRIPTION
|
||
|
Retrieve the value of AXI clear bit
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
AXI clear bit
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
unsigned long get_axi_clear(void)
|
||
|
{
|
||
|
return pm_axi_info.clear;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_cnts_write
|
||
|
|
||
|
DESCRIPTION
|
||
|
Write handler for the /proc axi results directory.
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
Number of characters to output.
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
int pm_axi_cnts_write(struct file *file, const char *buff,
|
||
|
unsigned long cnt, void *data)
|
||
|
{
|
||
|
char *newbuf;
|
||
|
struct PerfMonAxiCnts *p =
|
||
|
(struct PerfMonAxiCnts *)data;
|
||
|
|
||
|
if (p == 0)
|
||
|
return cnt;
|
||
|
/*
|
||
|
* Alloc the user data in kernel space. and then copy user to kernel
|
||
|
*/
|
||
|
newbuf = kmalloc(cnt + 1, GFP_KERNEL);
|
||
|
if (0 == newbuf)
|
||
|
return cnt;
|
||
|
if (copy_from_user(newbuf, buff, cnt) != 0) {
|
||
|
printk(KERN_INFO "%s copy_from_user failed\n", __func__);
|
||
|
return cnt;
|
||
|
}
|
||
|
return cnt;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_update_cnts
|
||
|
|
||
|
DESCRIPTION
|
||
|
Read the current AXI counter values. Check for overflows and
|
||
|
adjust the values stored accordingly.
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
void pm_axi_update_cnts(void)
|
||
|
{
|
||
|
if (is_first) {
|
||
|
pm_axi_start();
|
||
|
} else {
|
||
|
if (pm_axi_info.valid == 1) {
|
||
|
pm_axi_info.valid = 0;
|
||
|
pm_axi_update();
|
||
|
} else {
|
||
|
pm_axi_enable();
|
||
|
}
|
||
|
}
|
||
|
is_first = 0;
|
||
|
axi_cnts.cycles += pm_get_axi_cycle_count();
|
||
|
axi_cnts.cnt0 += pm_get_axi_evt0_count();
|
||
|
axi_cnts.cnt1 += pm_get_axi_evt1_count();
|
||
|
axi_cnts.tenure_total += pm_get_axi_ten_total_count();
|
||
|
|
||
|
axi_cnts.tenure_min = pm_get_axi_ten_min_count();
|
||
|
axi_cnts.tenure_max = pm_get_axi_ten_max_count();
|
||
|
axi_cnts.tenure_last = pm_get_axi_ten_last_count();
|
||
|
|
||
|
pm_axi_start();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_clear_cnts
|
||
|
|
||
|
DESCRIPTION
|
||
|
Clear the locally stored AXI counter values.
|
||
|
Also clear the AXI counter registers.
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
void pm_axi_clear_cnts(void)
|
||
|
{
|
||
|
axi_cnts.cycles = 0;
|
||
|
axi_cnts.cnt0 = 0;
|
||
|
axi_cnts.cnt1 = 0;
|
||
|
axi_cnts.tenure_total = 0;
|
||
|
axi_cnts.tenure_min = 0;
|
||
|
axi_cnts.tenure_max = 0;
|
||
|
axi_cnts.tenure_last = 0;
|
||
|
pm_axi_start();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_read_decimal
|
||
|
|
||
|
DESCRIPTION
|
||
|
Read handler for the /proc axi results directory in decimal format.
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
Number of characters to output.
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
int pm_axi_read_decimal(char *page, char **start, off_t off, int count,
|
||
|
int *eof, void *data)
|
||
|
{
|
||
|
struct perf_mon_axi_cnts *p = (struct perf_mon_axi_cnts *)data;
|
||
|
|
||
|
return sprintf(page, "cnt0:%llu cnt1:%llu tenure:%llu ten_max:%llu \
|
||
|
ten_min:%llu ten_last:%llu cycles:%llu\n",
|
||
|
p->cnt0,
|
||
|
p->cnt1,
|
||
|
p->tenure_total,
|
||
|
p->tenure_max,
|
||
|
p->tenure_min,
|
||
|
p->tenure_last,
|
||
|
p->cycles);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_read_hex
|
||
|
|
||
|
DESCRIPTION
|
||
|
Read handler for the /proc axi results directory in hex format.
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
Number of characters to output.
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
int pm_axi_read_hex(char *page, char **start, off_t off, int count,
|
||
|
int *eof, void *data)
|
||
|
{
|
||
|
struct perf_mon_axi_cnts *p = (struct perf_mon_axi_cnts *)data;
|
||
|
|
||
|
return sprintf(page, "cnt0:%llx cnt1:%llx tenure:%llx ten_max:%llx \
|
||
|
ten_min:%llx ten_last:%llx cycles:%llx\n",
|
||
|
p->cnt0,
|
||
|
p->cnt1,
|
||
|
p->tenure_total,
|
||
|
p->tenure_max,
|
||
|
p->tenure_min,
|
||
|
p->tenure_last,
|
||
|
p->cycles);
|
||
|
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_set_proc_entry
|
||
|
|
||
|
DESCRIPTION
|
||
|
Create a generic entry for the /proc axi settings directory.
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
void pm_axi_set_proc_entry(char *name, unsigned long *var,
|
||
|
struct proc_dir_entry *d, int hex)
|
||
|
{
|
||
|
struct proc_dir_entry *pe;
|
||
|
pe = create_proc_entry(name, 0777, d);
|
||
|
if (0 == pe)
|
||
|
return;
|
||
|
if (hex) {
|
||
|
pe->read_proc = per_process_read;
|
||
|
pe->write_proc = per_process_write_hex;
|
||
|
} else {
|
||
|
pe->read_proc = per_process_read_decimal;
|
||
|
pe->write_proc = per_process_write_dec;
|
||
|
}
|
||
|
pe->data = (void *)var;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_get_cnt_proc_entry
|
||
|
|
||
|
DESCRIPTION
|
||
|
Create a generic entry for the /proc axi results directory.
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
void pm_axi_get_cnt_proc_entry(char *name, struct perf_mon_axi_cnts *var,
|
||
|
struct proc_dir_entry *d, int hex)
|
||
|
{
|
||
|
struct proc_dir_entry *pe;
|
||
|
pe = create_proc_entry(name, 0777, d);
|
||
|
if (0 == pe)
|
||
|
return;
|
||
|
if (hex) {
|
||
|
pe->read_proc = pm_axi_read_hex;
|
||
|
pe->write_proc = pm_axi_cnts_write;
|
||
|
} else {
|
||
|
pe->read_proc = pm_axi_read_decimal;
|
||
|
pe->write_proc = pm_axi_cnts_write;
|
||
|
}
|
||
|
pe->data = (void *)var;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_clear_tenure
|
||
|
|
||
|
DESCRIPTION
|
||
|
Clear AXI tenure cntr manually. Temporary solution till hardware bug
|
||
|
is fixed
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
void pm_axi_clear_tenure(void)
|
||
|
{
|
||
|
HWIO_AXI_MONITOR_TENURE_UPPER_REG_OUT(0x0);
|
||
|
HWIO_AXI_MONITOR_TENURE_LOWER_REG_OUT(0x0);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_init
|
||
|
|
||
|
DESCRIPTION
|
||
|
Map AXI region to virtual memory.
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
void pm_axi_init()
|
||
|
{
|
||
|
/*Map the AXI regs*/
|
||
|
#ifdef CONFIG_ARCH_QSD8X50
|
||
|
{
|
||
|
/*Map the AXI regs*/
|
||
|
AXI_BASE = (uint32_t)ioremap(AXI_REG_BASE_PHYS, AXI_BASE_SIZE);
|
||
|
if (!AXI_BASE)
|
||
|
printk(KERN_ERR "Mem map failed\n");
|
||
|
}
|
||
|
#else
|
||
|
{
|
||
|
AXI_BASE = (uint32_t)kmalloc(AXI_BASE_SIZE, GFP_KERNEL);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_start
|
||
|
|
||
|
DESCRIPTION
|
||
|
Set event0, event1 and tenure registers based on the /proc entries.
|
||
|
Set cycle cntr to fffffffe to start counters.
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
void
|
||
|
pm_axi_start()
|
||
|
{
|
||
|
unsigned long sel_reg0, sel_reg1, ten_sel_reg;
|
||
|
sel_reg0 = get_axi_sel_reg0();
|
||
|
sel_reg1 = get_axi_sel_reg1();
|
||
|
ten_sel_reg = get_axi_ten_sel_reg();
|
||
|
HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK);
|
||
|
/*Set AXI Cycle Counter to enable AXI Monitors*/
|
||
|
HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_OUT(0xffff);
|
||
|
HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_OUT(0xfffe);
|
||
|
/*Set master/slave*/
|
||
|
HWIO_AXI_MONITOR_SELECTION_REG1_OUT(sel_reg1);
|
||
|
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_RESET_ALL);
|
||
|
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_ENABLE_ALL_NOCYCLES);
|
||
|
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_MONITOR_SELECTION_REG0_IN
|
||
|
| sel_reg0);
|
||
|
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_MONITOR_SELECTION_REG0_IN
|
||
|
| HWIO_AXI_MONITOR_SELECTION_REG0_ECC_BMSK);
|
||
|
HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_update
|
||
|
|
||
|
DESCRIPTION
|
||
|
Set event0, event1 and tenure registers based on the /proc entries.
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
void
|
||
|
pm_axi_update()
|
||
|
{
|
||
|
HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK);
|
||
|
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_MONITOR_SELECTION_REG0_IN
|
||
|
| HWIO_AXI_RESET_ALL);
|
||
|
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(HWIO_AXI_MONITOR_SELECTION_REG0_IN
|
||
|
& HWIO_AXI_DISABLE_ALL);
|
||
|
pm_axi_start();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_disable
|
||
|
|
||
|
DESCRIPTION
|
||
|
Disable all cntrs.
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
void
|
||
|
pm_axi_disable(void)
|
||
|
{
|
||
|
unsigned long sel_reg0;
|
||
|
/*Disable cntrs*/
|
||
|
sel_reg0 = get_axi_sel_reg0();
|
||
|
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(sel_reg0 & AXI_EVTSEL_DISABLE_MASK);
|
||
|
/*Disable clk*/
|
||
|
HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_DISABLE);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_enable
|
||
|
|
||
|
DESCRIPTION
|
||
|
Enable all cntrs.
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
void
|
||
|
pm_axi_enable(void)
|
||
|
{
|
||
|
unsigned long sel_reg0;
|
||
|
/*Enable cntrs*/
|
||
|
sel_reg0 = get_axi_sel_reg0();
|
||
|
HWIO_AXI_MONITOR_SELECTION_REG0_OUT(sel_reg0 | 0x6a00);
|
||
|
/*Enable clk*/
|
||
|
HWIO_AXI_CONFIGURATION_REG_OUT(HWIO_AXI_CONFIGURATION_REG_PPDM_BMSK);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_axi_disable_cnts
|
||
|
|
||
|
DESCRIPTION
|
||
|
Read cycle cntr value
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
unsigned long
|
||
|
pm_get_axi_cycle_count(void)
|
||
|
{
|
||
|
if (HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_IN == 0x0 &&
|
||
|
HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_IN == 0x0) {
|
||
|
/*Set AXI Cycle Counter to enable AXI Monitors*/
|
||
|
HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_OUT(0xffff);
|
||
|
HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_OUT(0xfffe);
|
||
|
}
|
||
|
return 0xfffffffe - ((HWIO_AXI_MONITOR_CYCLE_COUNT_UPPER_REG_IN << 16)
|
||
|
+ HWIO_AXI_MONITOR_CYCLE_COUNT_LOWER_REG_IN);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_get_axi_evt0_count
|
||
|
|
||
|
DESCRIPTION
|
||
|
Read Event0 cntr value
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
unsigned long
|
||
|
pm_get_axi_evt0_count(void)
|
||
|
{
|
||
|
return (HWIO_AXI_MONITOR_EVENT_UPPER_REG0_IN << 16)
|
||
|
+ HWIO_AXI_MONITOR_EVENT_LOWER_REG0_IN;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_get_axi_evt1_count
|
||
|
|
||
|
DESCRIPTION
|
||
|
Read Event1 cntr value
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
unsigned long
|
||
|
pm_get_axi_evt1_count(void)
|
||
|
{
|
||
|
return (HWIO_AXI_MONITOR_EVENT_UPPER_REG1_IN << 16)
|
||
|
+ HWIO_AXI_MONITOR_EVENT_LOWER_REG1_IN;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_get_axi_ten_min_count
|
||
|
|
||
|
DESCRIPTION
|
||
|
Read min tenure cntr value
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
unsigned long
|
||
|
pm_get_axi_ten_min_count(void)
|
||
|
{
|
||
|
return HWIO_AXI_MONITOR_MIN_REG_IN;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_get_axi_ten_max_count
|
||
|
|
||
|
DESCRIPTION
|
||
|
Read max tenure cntr value
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
unsigned long
|
||
|
pm_get_axi_ten_max_count(void)
|
||
|
{
|
||
|
return HWIO_AXI_MONITOR_MAX_REG_IN;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_get_axi_ten_total_count
|
||
|
|
||
|
DESCRIPTION
|
||
|
Read total tenure cntr value
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
unsigned long
|
||
|
pm_get_axi_ten_total_count(void)
|
||
|
{
|
||
|
return (HWIO_AXI_MONITOR_TENURE_UPPER_REG_IN << 16)
|
||
|
+ HWIO_AXI_MONITOR_TENURE_LOWER_REG_IN;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
FUNCTION pm_get_axi_ten_last_count
|
||
|
|
||
|
DESCRIPTION
|
||
|
Read last tenure cntr value
|
||
|
|
||
|
DEPENDENCIES
|
||
|
|
||
|
RETURN VALUE
|
||
|
|
||
|
SIDE EFFECTS
|
||
|
*/
|
||
|
unsigned long
|
||
|
pm_get_axi_ten_last_count(void)
|
||
|
{
|
||
|
return HWIO_AXI_MONITOR_LAST_TENURE_REG_IN;
|
||
|
}
|