203 lines
5.8 KiB
C
Executable File
203 lines
5.8 KiB
C
Executable File
/*
|
|
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
|
|
* http://www.samsung.com
|
|
*
|
|
* Data structure definition for Exynos IOMMU driver
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#ifndef _EXYNOS_IOMMU_LOG_H_
|
|
#define _EXYNOS_IOMMU_LOG_H_
|
|
|
|
#include <linux/mm.h>
|
|
#include <linux/mm_types.h>
|
|
#include <linux/ktime.h>
|
|
#include <linux/hrtimer.h>
|
|
#include <linux/gfp.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/device.h>
|
|
|
|
enum sysmmu_event_log_event {
|
|
EVENT_SYSMMU_NONE, /* initialized value */
|
|
EVENT_SYSMMU_ENABLE,
|
|
EVENT_SYSMMU_DISABLE,
|
|
EVENT_SYSMMU_TLB_INV_RANGE,
|
|
EVENT_SYSMMU_TLB_INV_ALL,
|
|
EVENT_SYSMMU_POWERON,
|
|
EVENT_SYSMMU_POWEROFF,
|
|
EVENT_SYSMMU_IOMMU_ATTACH,
|
|
EVENT_SYSMMU_IOMMU_DETACH,
|
|
EVENT_SYSMMU_IOMMU_MAP,
|
|
EVENT_SYSMMU_IOMMU_UNMAP,
|
|
EVENT_SYSMMU_IOMMU_ALLOCSLPD,
|
|
EVENT_SYSMMU_IOMMU_FREESLPD,
|
|
EVENT_SYSMMU_IOVMM_MAP,
|
|
EVENT_SYSMMU_IOVMM_UNMAP
|
|
};
|
|
|
|
struct sysmmu_event_range {
|
|
u32 start;
|
|
u32 end;
|
|
};
|
|
|
|
struct sysmmu_event_IOMMU_MAP {
|
|
u32 start;
|
|
u32 end;
|
|
unsigned int pfn;
|
|
};
|
|
|
|
struct sysmmu_event_IOVMM_MAP {
|
|
u32 start;
|
|
u32 end;
|
|
unsigned int dummy;
|
|
};
|
|
|
|
/**
|
|
* event must be updated before eventdata because of eventdata.dev
|
|
* sysmmu_event_log is not protected by any locks. That means it permits
|
|
* some data inconsistency by race condition between updating and reading.
|
|
* However the problem arises when event is either IOMMU_ATTACH or
|
|
* IOMMU_DETACH because they stores a pointer to device descriptor to
|
|
* eventdata.dev and reading the sysmmu_event_log of those events refers
|
|
* to values pointed by eventdata.dev.
|
|
* Therefore, eventdata must be updated before event not to access invalid
|
|
* pointer by reading debugfs entries.
|
|
*/
|
|
struct sysmmu_event_log {
|
|
ktime_t timestamp;
|
|
union {
|
|
struct sysmmu_event_range range;
|
|
struct sysmmu_event_IOMMU_MAP iommu;
|
|
struct sysmmu_event_IOVMM_MAP iovmm;
|
|
u32 addr;
|
|
struct device *dev;
|
|
} eventdata;
|
|
enum sysmmu_event_log_event event;
|
|
};
|
|
|
|
struct exynos_iommu_event_log {
|
|
atomic_t index;
|
|
unsigned int log_len;
|
|
struct sysmmu_event_log *log;
|
|
struct dentry *debugfs_root;
|
|
};
|
|
|
|
/* sizeof(struct sysmmu_event_log) = 8 + 4 * 3 + 4 = 24 bytes */
|
|
#define SYSMMU_LOG_LEN 1024
|
|
#define IOMMU_LOG_LEN 4096
|
|
#define IOVMM_LOG_LEN 512
|
|
|
|
#define SYSMMU_DRVDATA_TO_LOG(data) (&(data)->log)
|
|
#define IOMMU_PRIV_TO_LOG(data) (&(data)->log)
|
|
#define IOMMU_TO_LOG(data) (&(to_exynos_domain(data))->log)
|
|
#define IOVMM_TO_LOG(data) (&(data)->log)
|
|
|
|
static inline struct sysmmu_event_log *sysmmu_event_log_get(
|
|
struct exynos_iommu_event_log *plog)
|
|
{
|
|
struct sysmmu_event_log *log;
|
|
unsigned int index =
|
|
(unsigned int)atomic_inc_return(&plog->index) - 1;
|
|
log = &plog->log[index % plog->log_len];
|
|
log->timestamp = ktime_get();
|
|
return log;
|
|
}
|
|
|
|
#define DEFINE_SYSMMU_EVENT_LOG(evt) \
|
|
static inline void SYSMMU_EVENT_LOG_##evt(struct exynos_iommu_event_log *plog) \
|
|
{ \
|
|
struct sysmmu_event_log *log = sysmmu_event_log_get(plog); \
|
|
log->event = EVENT_SYSMMU_##evt; \
|
|
}
|
|
|
|
#define DEFINE_SYSMMU_EVENT_LOG_1ADDR(evt) \
|
|
static inline void SYSMMU_EVENT_LOG_##evt( \
|
|
struct exynos_iommu_event_log *plog, u32 addr) \
|
|
{ \
|
|
struct sysmmu_event_log *log = sysmmu_event_log_get(plog); \
|
|
log->eventdata.addr = addr; \
|
|
log->event = EVENT_SYSMMU_##evt; \
|
|
}
|
|
|
|
#define DEFINE_SYSMMU_EVENT_LOG_2ADDR(evt) \
|
|
static inline void SYSMMU_EVENT_LOG_##evt(struct exynos_iommu_event_log *plog, \
|
|
u32 start, u32 end) \
|
|
{ \
|
|
struct sysmmu_event_log *log = sysmmu_event_log_get(plog); \
|
|
log->eventdata.range.start = start; \
|
|
log->eventdata.range.end = end; \
|
|
log->event = EVENT_SYSMMU_##evt; \
|
|
}
|
|
|
|
static inline void SYSMMU_EVENT_LOG_IOVMM_MAP(
|
|
struct exynos_iommu_event_log *plog,
|
|
u32 start, u32 end, unsigned int dummy)
|
|
{
|
|
struct sysmmu_event_log *log = sysmmu_event_log_get(plog);
|
|
log->eventdata.iovmm.start = start;
|
|
log->eventdata.iovmm.end = end;
|
|
log->eventdata.iovmm.dummy = dummy;
|
|
log->event = EVENT_SYSMMU_IOVMM_MAP;
|
|
}
|
|
|
|
static inline void SYSMMU_EVENT_LOG_IOMMU_ATTACH(
|
|
struct exynos_iommu_event_log *plog, struct device *dev)
|
|
{
|
|
struct sysmmu_event_log *log = sysmmu_event_log_get(plog);
|
|
log->eventdata.dev = dev;
|
|
log->event = EVENT_SYSMMU_IOMMU_ATTACH;
|
|
}
|
|
|
|
static inline void SYSMMU_EVENT_LOG_IOMMU_DETACH(
|
|
struct exynos_iommu_event_log *plog, struct device *dev)
|
|
{
|
|
struct sysmmu_event_log *log = sysmmu_event_log_get(plog);
|
|
log->eventdata.dev = dev;
|
|
log->event = EVENT_SYSMMU_IOMMU_DETACH;
|
|
}
|
|
|
|
static inline void SYSMMU_EVENT_LOG_IOMMU_MAP(
|
|
struct exynos_iommu_event_log *plog,
|
|
u32 start, u32 end, unsigned int pfn)
|
|
{
|
|
struct sysmmu_event_log *log = sysmmu_event_log_get(plog);
|
|
log->event = EVENT_SYSMMU_IOMMU_MAP;
|
|
log->eventdata.iommu.start = start;
|
|
log->eventdata.iommu.end = end;
|
|
log->eventdata.iommu.pfn = pfn;
|
|
}
|
|
|
|
int exynos_iommu_init_event_log(struct exynos_iommu_event_log *log,
|
|
unsigned int log_len);
|
|
|
|
void sysmmu_add_log_to_debugfs(struct dentry *debugfs_root,
|
|
struct exynos_iommu_event_log *log, const char *name);
|
|
|
|
void iommu_add_log_to_debugfs(struct dentry *debugfs_root,
|
|
struct exynos_iommu_event_log *log, const char *name);
|
|
|
|
#if defined(CONFIG_EXYNOS_IOVMM)
|
|
void iovmm_add_log_to_debugfs(struct dentry *debugfs_root,
|
|
struct exynos_iommu_event_log *log, const char *name);
|
|
#else
|
|
#define iovmm_add_log_to_debugfs(debugfs_root, log, name) do { } while (0)
|
|
#endif
|
|
|
|
DEFINE_SYSMMU_EVENT_LOG(ENABLE)
|
|
DEFINE_SYSMMU_EVENT_LOG(DISABLE)
|
|
DEFINE_SYSMMU_EVENT_LOG(TLB_INV_ALL)
|
|
DEFINE_SYSMMU_EVENT_LOG(POWERON)
|
|
DEFINE_SYSMMU_EVENT_LOG(POWEROFF)
|
|
|
|
DEFINE_SYSMMU_EVENT_LOG_2ADDR(IOMMU_ALLOCSLPD)
|
|
DEFINE_SYSMMU_EVENT_LOG_2ADDR(IOMMU_FREESLPD)
|
|
|
|
DEFINE_SYSMMU_EVENT_LOG_2ADDR(TLB_INV_RANGE)
|
|
DEFINE_SYSMMU_EVENT_LOG_2ADDR(IOMMU_UNMAP)
|
|
DEFINE_SYSMMU_EVENT_LOG_2ADDR(IOVMM_UNMAP)
|
|
|
|
#endif /*_EXYNOS_IOMMU_LOG_H_*/
|