| /* 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 |