blob: dc4671cf369577b640c8bb7f013c64ab0dec3089 [file] [log] [blame]
/* Copyright (c) 2012-2013, 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.
*/
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/irqreturn.h>
#ifndef MSM_IOMMU_PERFMON_H
#define MSM_IOMMU_PERFMON_H
/**
* struct iommu_pmon_counter - container for a performance counter.
* @counter_no: counter number within the group
* @absolute_counter_no: counter number within IOMMU PMU
* @value: cached counter value
* @overflow_count: no of times counter has overflowed
* @enabled: indicates whether counter is enabled or not
* @current_event_class: current selected event class, -1 if none
* @counter_dir: debugfs directory for this counter
* @cnt_group: group this counter belongs to
*/
struct iommu_pmon_counter {
unsigned int counter_no;
unsigned int absolute_counter_no;
unsigned long value;
unsigned long overflow_count;
unsigned int enabled;
int current_event_class;
struct dentry *counter_dir;
struct iommu_pmon_cnt_group *cnt_group;
};
/**
* struct iommu_pmon_cnt_group - container for a perf mon counter group.
* @grp_no: group number
* @num_counters: number of counters in this group
* @counters: list of counter in this group
* @group_dir: debugfs directory for this group
* @pmon: pointer to the iommu_pmon object this group belongs to
*/
struct iommu_pmon_cnt_group {
unsigned int grp_no;
unsigned int num_counters;
struct iommu_pmon_counter *counters;
struct dentry *group_dir;
struct iommu_pmon *pmon;
};
/**
* struct iommu_info - container for a perf mon iommu info.
* @iommu_name: name of the iommu from device tree
* @base: virtual base address for this iommu
* @evt_irq: irq number for event overflow interrupt
* @iommu_dev: pointer to iommu device
* @ops: iommu access operations pointer.
* @hw_ops: iommu pm hw access operations pointer.
* @always_on: 1 if iommu is always on, 0 otherwise.
*/
struct iommu_info {
const char *iommu_name;
void *base;
int evt_irq;
struct device *iommu_dev;
struct iommu_access_ops *ops;
struct iommu_pm_hw_ops *hw_ops;
unsigned int always_on;
};
/**
* struct iommu_pmon - main container for a perf mon data.
* @iommu_dir: debugfs directory for this iommu
* @iommu: iommu_info instance
* @iommu_list: iommu_list head
* @cnt_grp: list of counter groups
* @num_groups: number of counter groups
* @num_counters: number of counters per group
* @event_cls_supported: an array of event classes supported for this PMU
* @nevent_cls_supported: number of event classes supported.
* @enabled: Indicates whether perf. mon is enabled or not
* @iommu_attached Indicates whether iommu is attached or not.
* @lock: mutex used to synchronize access to shared data
*/
struct iommu_pmon {
struct dentry *iommu_dir;
struct iommu_info iommu;
struct list_head iommu_list;
struct iommu_pmon_cnt_group *cnt_grp;
u32 num_groups;
u32 num_counters;
u32 *event_cls_supported;
u32 nevent_cls_supported;
unsigned int enabled;
unsigned int iommu_attach_count;
struct mutex lock;
};
/**
* struct iommu_hw_ops - Callbacks for accessing IOMMU HW
* @initialize_hw: Call to do any initialization before enabling ovf interrupts
* @is_hw_access_ok: Returns 1 if we can access HW, 0 otherwise
* @grp_enable: Call to enable a counter group
* @grp_disable: Call to disable a counter group
* @enable_pm: Call to enable PM
* @disable_pm: Call to disable PM
* @reset_counters: Call to reset counters
* @check_for_overflow: Call to check for overflow
* @evt_ovfl_int_handler: Overflow interrupt handler callback
* @counter_enable: Call to enable counters
* @counter_disable: Call to disable counters
* @ovfl_int_enable: Call to enable overflow interrupts
* @ovfl_int_disable: Call to disable overflow interrupts
* @set_event_class: Call to set event class
* @read_counter: Call to read a counter value
*/
struct iommu_pm_hw_ops {
void (*initialize_hw)(const struct iommu_pmon *);
unsigned int (*is_hw_access_OK)(const struct iommu_pmon *);
void (*grp_enable)(struct iommu_info *, unsigned int);
void (*grp_disable)(struct iommu_info *, unsigned int);
void (*enable_pm)(struct iommu_info *);
void (*disable_pm)(struct iommu_info *);
void (*reset_counters)(const struct iommu_info *);
void (*check_for_overflow)(struct iommu_pmon *);
irqreturn_t (*evt_ovfl_int_handler)(int, void *);
void (*counter_enable)(struct iommu_info *,
struct iommu_pmon_counter *);
void (*counter_disable)(struct iommu_info *,
struct iommu_pmon_counter *);
void (*ovfl_int_enable)(struct iommu_info *,
const struct iommu_pmon_counter *);
void (*ovfl_int_disable)(struct iommu_info *,
const struct iommu_pmon_counter *);
void (*set_event_class)(struct iommu_pmon *pmon, unsigned int,
unsigned int);
unsigned int (*read_counter)(struct iommu_pmon_counter *);
};
extern struct iommu_access_ops iommu_access_ops_v0;
extern struct iommu_access_ops iommu_access_ops_v1;
#define MSM_IOMMU_PMU_NO_EVENT_CLASS -1
#ifdef CONFIG_MSM_IOMMU_PMON
/**
* Get pointer to PMU hardware access functions for IOMMUv0 PMU
*/
struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v0(void);
/**
* Get pointer to PMU hardware access functions for IOMMUv1 PMU
*/
struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v1(void);
/**
* Allocate memory for performance monitor structure. Must
* be called before iommu_pm_iommu_register
*/
struct iommu_pmon *msm_iommu_pm_alloc(struct device *iommu_dev);
/**
* Free memory previously allocated with iommu_pm_alloc
*/
void msm_iommu_pm_free(struct device *iommu_dev);
/**
* Register iommu with the performance monitor module.
*/
int msm_iommu_pm_iommu_register(struct iommu_pmon *info);
/**
* Unregister iommu with the performance monitor module.
*/
void msm_iommu_pm_iommu_unregister(struct device *dev);
/**
* Called by iommu driver when attaching is complete
* Must NOT be called with IOMMU mutexes held.
* @param iommu_dev IOMMU device that is attached
*/
void msm_iommu_attached(struct device *dev);
/**
* Called by iommu driver before detaching.
* Must NOT be called with IOMMU mutexes held.
* @param iommu_dev IOMMU device that is going to be detached
*/
void msm_iommu_detached(struct device *dev);
#else
static inline struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v0(void)
{
return NULL;
}
static inline struct iommu_pm_hw_ops *iommu_pm_get_hw_ops_v1(void)
{
return NULL;
}
static inline struct iommu_pmon *msm_iommu_pm_alloc(struct device *iommu_dev)
{
return NULL;
}
static inline void msm_iommu_pm_free(struct device *iommu_dev)
{
return;
}
static inline int msm_iommu_pm_iommu_register(struct iommu_pmon *info)
{
return -EIO;
}
static inline void msm_iommu_pm_iommu_unregister(struct device *dev)
{
}
static inline void msm_iommu_attached(struct device *dev)
{
}
static inline void msm_iommu_detached(struct device *dev)
{
}
#endif
#endif