| /* Copyright (c) 2002,2007-2015, 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. |
| * |
| */ |
| #ifndef __KGSL_DEVICE_H |
| #define __KGSL_DEVICE_H |
| |
| #include <linux/slab.h> |
| #include <linux/idr.h> |
| #include <linux/pm_qos.h> |
| #include <linux/sched.h> |
| #include <linux/workqueue.h> |
| |
| #include "kgsl.h" |
| #include "kgsl_mmu.h" |
| #include "kgsl_pwrctrl.h" |
| #include "kgsl_log.h" |
| #include "kgsl_pwrscale.h" |
| #include "kgsl_snapshot.h" |
| |
| #include <linux/sync.h> |
| |
| #define KGSL_TIMEOUT_NONE 0 |
| #define KGSL_TIMEOUT_DEFAULT 0xFFFFFFFF |
| #define KGSL_TIMEOUT_PART 50 /* 50 msec */ |
| |
| #define KGSL_IOCTL_FUNC(_cmd, _func) \ |
| [_IOC_NR((_cmd))] = \ |
| { .cmd = (_cmd), .func = (_func) } |
| |
| /* KGSL device state is initialized to INIT when platform_probe * |
| * sucessfully initialized the device. Once a device has been opened * |
| * (started) it becomes active. NAP implies that only low latency * |
| * resources (for now clocks on some platforms) are off. SLEEP implies * |
| * that the KGSL module believes a device is idle (has been inactive * |
| * past its timer) and all system resources are released. SUSPEND is * |
| * requested by the kernel and will be enforced upon all open devices. */ |
| |
| #define KGSL_STATE_NONE 0x00000000 |
| #define KGSL_STATE_INIT 0x00000001 |
| #define KGSL_STATE_ACTIVE 0x00000002 |
| #define KGSL_STATE_NAP 0x00000004 |
| #define KGSL_STATE_SLEEP 0x00000008 |
| #define KGSL_STATE_SUSPEND 0x00000010 |
| #define KGSL_STATE_AWARE 0x00000020 |
| #define KGSL_STATE_SLUMBER 0x00000080 |
| |
| #define KGSL_GRAPHICS_MEMORY_LOW_WATERMARK 0x1000000 |
| |
| #define KGSL_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK))) |
| |
| /** |
| * enum kgsl_event_results - result codes passed to an event callback when the |
| * event is retired or cancelled |
| * @KGSL_EVENT_RETIRED: The timestamp associated with the event retired |
| * successflly |
| * @KGSL_EVENT_CANCELLED: The event was cancelled before the event was fired |
| */ |
| enum kgsl_event_results { |
| KGSL_EVENT_RETIRED = 1, |
| KGSL_EVENT_CANCELLED = 2, |
| }; |
| |
| #define KGSL_FLAG_WAKE_ON_TOUCH BIT(0) |
| |
| /* |
| * "list" of event types for ftrace symbolic magic |
| */ |
| |
| #define KGSL_EVENT_TYPES \ |
| { KGSL_EVENT_RETIRED, "retired" }, \ |
| { KGSL_EVENT_CANCELLED, "cancelled" } |
| |
| #define KGSL_CONTEXT_FLAGS \ |
| { KGSL_CONTEXT_NO_GMEM_ALLOC , "NO_GMEM_ALLOC" }, \ |
| { KGSL_CONTEXT_PREAMBLE, "PREAMBLE" }, \ |
| { KGSL_CONTEXT_TRASH_STATE, "TRASH_STATE" }, \ |
| { KGSL_CONTEXT_CTX_SWITCH, "CTX_SWITCH" }, \ |
| { KGSL_CONTEXT_PER_CONTEXT_TS, "PER_CONTEXT_TS" }, \ |
| { KGSL_CONTEXT_USER_GENERATED_TS, "USER_TS" }, \ |
| { KGSL_CONTEXT_NO_FAULT_TOLERANCE, "NO_FT" }, \ |
| { KGSL_CONTEXT_PWR_CONSTRAINT, "PWR" }, \ |
| { KGSL_CONTEXT_SAVE_GMEM, "SAVE_GMEM" } |
| |
| #define KGSL_CMDBATCH_FLAGS \ |
| { KGSL_CMDBATCH_MARKER, "MARKER" }, \ |
| { KGSL_CMDBATCH_CTX_SWITCH, "CTX_SWITCH" }, \ |
| { KGSL_CMDBATCH_SYNC, "SYNC" }, \ |
| { KGSL_CMDBATCH_END_OF_FRAME, "EOF" }, \ |
| { KGSL_CMDBATCH_PWR_CONSTRAINT, "PWR_CONSTRAINT" }, \ |
| { KGSL_CMDBATCH_SUBMIT_IB_LIST, "IB_LIST" } |
| |
| #define KGSL_CONTEXT_TYPES \ |
| { KGSL_CONTEXT_TYPE_ANY, "ANY" }, \ |
| { KGSL_CONTEXT_TYPE_GL, "GL" }, \ |
| { KGSL_CONTEXT_TYPE_CL, "CL" }, \ |
| { KGSL_CONTEXT_TYPE_C2D, "C2D" }, \ |
| { KGSL_CONTEXT_TYPE_RS, "RS" } |
| |
| #define KGSL_CONTEXT_ID(_context) \ |
| ((_context != NULL) ? (_context)->id : KGSL_MEMSTORE_GLOBAL) |
| |
| /* Allocate 512K for the snapshot static region*/ |
| #define KGSL_SNAPSHOT_MEMSIZE (512 * 1024) |
| |
| struct kgsl_device; |
| struct platform_device; |
| struct kgsl_device_private; |
| struct kgsl_context; |
| struct kgsl_power_stats; |
| struct kgsl_event; |
| struct kgsl_cmdbatch; |
| struct kgsl_snapshot; |
| |
| struct kgsl_functable { |
| /* Mandatory functions - these functions must be implemented |
| by the client device. The driver will not check for a NULL |
| pointer before calling the hook. |
| */ |
| void (*regread) (struct kgsl_device *device, |
| unsigned int offsetwords, unsigned int *value); |
| void (*regwrite) (struct kgsl_device *device, |
| unsigned int offsetwords, unsigned int value); |
| int (*idle) (struct kgsl_device *device); |
| bool (*isidle) (struct kgsl_device *device); |
| int (*suspend_context) (struct kgsl_device *device); |
| int (*init) (struct kgsl_device *device); |
| int (*start) (struct kgsl_device *device, int priority); |
| int (*stop) (struct kgsl_device *device); |
| int (*getproperty) (struct kgsl_device *device, |
| enum kgsl_property_type type, void __user *value, |
| size_t sizebytes); |
| int (*getproperty_compat) (struct kgsl_device *device, |
| enum kgsl_property_type type, void __user *value, |
| size_t sizebytes); |
| int (*waittimestamp) (struct kgsl_device *device, |
| struct kgsl_context *context, unsigned int timestamp, |
| unsigned int msecs); |
| int (*readtimestamp) (struct kgsl_device *device, void *priv, |
| enum kgsl_timestamp_type type, unsigned int *timestamp); |
| int (*issueibcmds) (struct kgsl_device_private *dev_priv, |
| struct kgsl_context *context, struct kgsl_cmdbatch *cmdbatch, |
| uint32_t *timestamps); |
| void (*power_stats)(struct kgsl_device *device, |
| struct kgsl_power_stats *stats); |
| unsigned int (*gpuid)(struct kgsl_device *device, unsigned int *chipid); |
| void (*snapshot)(struct kgsl_device *device, |
| struct kgsl_snapshot *snapshot, struct kgsl_context *context); |
| irqreturn_t (*irq_handler)(struct kgsl_device *device); |
| int (*drain)(struct kgsl_device *device); |
| /* Optional functions - these functions are not mandatory. The |
| driver will check that the function pointer is not NULL before |
| calling the hook */ |
| struct kgsl_context *(*drawctxt_create) (struct kgsl_device_private *, |
| uint32_t *flags); |
| void (*drawctxt_detach)(struct kgsl_context *context); |
| void (*drawctxt_destroy) (struct kgsl_context *context); |
| void (*drawctxt_dump) (struct kgsl_device *device, |
| struct kgsl_context *context); |
| long (*ioctl) (struct kgsl_device_private *dev_priv, |
| unsigned int cmd, void *data); |
| long (*compat_ioctl) (struct kgsl_device_private *dev_priv, |
| unsigned int cmd, void *data); |
| int (*setproperty) (struct kgsl_device_private *dev_priv, |
| enum kgsl_property_type type, void __user *value, |
| unsigned int sizebytes); |
| int (*setproperty_compat) (struct kgsl_device_private *dev_priv, |
| enum kgsl_property_type type, void __user *value, |
| unsigned int sizebytes); |
| void (*drawctxt_sched)(struct kgsl_device *device, |
| struct kgsl_context *context); |
| void (*resume)(struct kgsl_device *device); |
| void (*regulator_enable)(struct kgsl_device *); |
| bool (*is_hw_collapsible)(struct kgsl_device *); |
| void (*regulator_disable)(struct kgsl_device *); |
| void (*pwrlevel_change_settings)(struct kgsl_device *device, |
| bool mask_throttle); |
| }; |
| |
| typedef long (*kgsl_ioctl_func_t)(struct kgsl_device_private *, |
| unsigned int, void *); |
| |
| struct kgsl_ioctl { |
| unsigned int cmd; |
| kgsl_ioctl_func_t func; |
| }; |
| |
| long kgsl_ioctl_helper(struct file *filep, unsigned int cmd, |
| const struct kgsl_ioctl *ioctl_funcs, |
| unsigned int array_size, unsigned long arg); |
| |
| /* Flag to mark the memobj_node as a preamble */ |
| #define MEMOBJ_PREAMBLE BIT(0) |
| /* Flag to mark that the memobj_node should not go to the hadrware */ |
| #define MEMOBJ_SKIP BIT(1) |
| |
| /** |
| * struct kgsl_memobj_node - Memory object descriptor |
| * @node: Local list node for the cmdbatch |
| * @cmdbatch: Cmdbatch the node belongs to |
| * @addr: memory start address |
| * @sizedwords: size of memory @addr |
| * @flags: any special case flags |
| */ |
| struct kgsl_memobj_node { |
| struct list_head node; |
| unsigned long gpuaddr; |
| size_t sizedwords; |
| unsigned long priv; |
| }; |
| |
| /** |
| * struct kgsl_cmdbatch - KGSl command descriptor |
| * @device: KGSL GPU device that the command was created for |
| * @context: KGSL context that created the command |
| * @timestamp: Timestamp assigned to the command |
| * @flags: flags |
| * @priv: Internal flags |
| * @fault_policy: Internal policy describing how to handle this command in case |
| * of a fault |
| * @fault_recovery: recovery actions actually tried for this batch |
| * @expires: Point in time when the cmdbatch is considered to be hung |
| * @refcount: kref structure to maintain the reference count |
| * @cmdlist: List of IBs to issue |
| * @memlist: List of all memory used in this command batch |
| * @synclist: List of context/timestamp tuples to wait for before issuing |
| * @timer: a timer used to track possible sync timeouts for this cmdbatch |
| * @marker_timestamp: For markers, the timestamp of the last "real" command that |
| * was queued |
| * @profiling_buf_entry: Mem entry containing the profiling buffer |
| * @profiling_buffer_gpuaddr: GPU virt address of the profile buffer added here |
| * for easy access |
| * @profile_index: Index to store the start/stop ticks in the kernel profiling |
| * buffer |
| * @submit_ticks: Variable to hold ticks at the time of cmdbatch submit. |
| * This structure defines an atomic batch of command buffers issued from |
| * userspace. |
| * @timeout_jiffies: For a syncpoint cmdbatch the jiffies at which the |
| * timer will expire |
| */ |
| struct kgsl_cmdbatch { |
| struct kgsl_device *device; |
| struct kgsl_context *context; |
| spinlock_t lock; |
| uint32_t timestamp; |
| uint32_t flags; |
| unsigned long priv; |
| unsigned long fault_policy; |
| unsigned long fault_recovery; |
| unsigned long expires; |
| struct kref refcount; |
| struct list_head cmdlist; |
| struct list_head memlist; |
| struct list_head synclist; |
| struct timer_list timer; |
| unsigned int marker_timestamp; |
| struct kgsl_mem_entry *profiling_buf_entry; |
| unsigned long profiling_buffer_gpuaddr; |
| unsigned int profile_index; |
| uint64_t submit_ticks; |
| unsigned int global_ts; |
| unsigned long timeout_jiffies; |
| }; |
| |
| /** |
| * struct kgsl_cmdbatch_sync_event |
| * @type: Syncpoint type |
| * @node: Local list node for the cmdbatch sync point list |
| * @cmdbatch: Pointer to the cmdbatch that owns the sync event |
| * @context: Pointer to the KGSL context that owns the cmdbatch |
| * @timestamp: Pending timestamp for the event |
| * @handle: Pointer to a sync fence handle |
| * @device: Pointer to the KGSL device |
| * @refcount: Allow event to be destroyed asynchronously |
| */ |
| struct kgsl_cmdbatch_sync_event { |
| int type; |
| struct list_head node; |
| struct kgsl_cmdbatch *cmdbatch; |
| struct kgsl_context *context; |
| unsigned int timestamp; |
| struct kgsl_sync_fence_waiter *handle; |
| struct kgsl_device *device; |
| struct kref refcount; |
| }; |
| |
| /** |
| * enum kgsl_cmdbatch_priv - Internal cmdbatch flags |
| * @CMDBATCH_FLAG_SKIP - skip the entire command batch |
| * @CMDBATCH_FLAG_FORCE_PREAMBLE - Force the preamble on for the cmdbatch |
| * @CMDBATCH_FLAG_WFI - Force wait-for-idle for the submission |
| * @CMDBATCH_FLAG_PROFILE - store the start / retire ticks for the command batch |
| * in the profiling buffer |
| * @CMDBATCH_FLAG_FENCE_LOG - Set if the cmdbatch is dumping fence logs via the |
| * cmdbatch timer - this is used to avoid recursion |
| */ |
| |
| enum kgsl_cmdbatch_priv { |
| CMDBATCH_FLAG_SKIP = 0, |
| CMDBATCH_FLAG_FORCE_PREAMBLE, |
| CMDBATCH_FLAG_WFI, |
| CMDBATCH_FLAG_PROFILE, |
| CMDBATCH_FLAG_FENCE_LOG, |
| }; |
| |
| struct kgsl_device { |
| struct device *dev; |
| const char *name; |
| unsigned int ver_major; |
| unsigned int ver_minor; |
| uint32_t flags; |
| enum kgsl_deviceid id; |
| |
| /* Starting physical address for GPU registers */ |
| unsigned long reg_phys; |
| |
| /* Starting Kernel virtual address for GPU registers */ |
| void *reg_virt; |
| |
| /* Total memory size for all GPU registers */ |
| unsigned int reg_len; |
| |
| /* Kernel virtual address for GPU shader memory */ |
| void *shader_mem_virt; |
| |
| /* Starting physical address for GPU shader memory */ |
| unsigned long shader_mem_phys; |
| |
| /* GPU shader memory size */ |
| unsigned int shader_mem_len; |
| struct kgsl_memdesc memstore; |
| const char *iomemname; |
| const char *shadermemname; |
| |
| struct kgsl_mmu mmu; |
| struct completion hwaccess_gate; |
| struct completion cmdbatch_gate; |
| const struct kgsl_functable *ftbl; |
| struct work_struct idle_check_ws; |
| struct timer_list idle_timer; |
| struct kgsl_pwrctrl pwrctrl; |
| int open_count; |
| |
| struct mutex mutex; |
| uint32_t state; |
| uint32_t requested_state; |
| |
| atomic_t active_cnt; |
| |
| wait_queue_head_t wait_queue; |
| wait_queue_head_t active_cnt_wq; |
| struct workqueue_struct *work_queue; |
| struct platform_device *pdev; |
| struct dentry *d_debugfs; |
| struct idr context_idr; |
| rwlock_t context_lock; |
| |
| struct { |
| void *ptr; |
| size_t size; |
| } snapshot_memory; |
| |
| struct kgsl_snapshot *snapshot; |
| |
| u32 snapshot_faultcount; /* Total number of faults since boot */ |
| struct kobject snapshot_kobj; |
| |
| struct kobject ppd_kobj; |
| |
| /* Logging levels */ |
| int cmd_log; |
| int ctxt_log; |
| int drv_log; |
| int mem_log; |
| int pwr_log; |
| struct kgsl_pwrscale pwrscale; |
| struct work_struct event_work; |
| |
| int reset_counter; /* Track how many GPU core resets have occured */ |
| int cff_dump_enable; |
| struct workqueue_struct *events_wq; |
| |
| struct device *busmondev; /* pseudo dev for GPU BW voting governor */ |
| }; |
| |
| |
| #define KGSL_DEVICE_COMMON_INIT(_dev) \ |
| .hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\ |
| .cmdbatch_gate = COMPLETION_INITIALIZER((_dev).cmdbatch_gate),\ |
| .idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\ |
| kgsl_idle_check),\ |
| .event_work = __WORK_INITIALIZER((_dev).event_work,\ |
| kgsl_process_events),\ |
| .context_idr = IDR_INIT((_dev).context_idr),\ |
| .wait_queue = __WAIT_QUEUE_HEAD_INITIALIZER((_dev).wait_queue),\ |
| .active_cnt_wq = __WAIT_QUEUE_HEAD_INITIALIZER((_dev).active_cnt_wq),\ |
| .mutex = __MUTEX_INITIALIZER((_dev).mutex),\ |
| .state = KGSL_STATE_NONE,\ |
| .ver_major = DRIVER_VERSION_MAJOR,\ |
| .ver_minor = DRIVER_VERSION_MINOR |
| |
| |
| /** |
| * enum bits for struct kgsl_context.priv |
| * @KGSL_CONTEXT_PRIV_DETACHED - The context has been destroyed by userspace |
| * and is no longer using the gpu. |
| * @KGSL_CONTEXT_PRIV_INVALID - The context has been destroyed by the kernel |
| * because it caused a GPU fault. |
| * @KGSL_CONTEXT_PRIV_PAGEFAULT - The context has caused a page fault. |
| * @KGSL_CONTEXT_PRIV_DEVICE_SPECIFIC - this value and higher values are |
| * reserved for devices specific use. |
| */ |
| enum kgsl_context_priv { |
| KGSL_CONTEXT_PRIV_DETACHED = 0, |
| KGSL_CONTEXT_PRIV_INVALID, |
| KGSL_CONTEXT_PRIV_PAGEFAULT, |
| KGSL_CONTEXT_PRIV_DEVICE_SPECIFIC = 16, |
| }; |
| |
| struct kgsl_process_private; |
| |
| /** |
| * struct kgsl_context - The context fields that are valid for a user defined |
| * context |
| * @refcount: kref object for reference counting the context |
| * @id: integer identifier for the context |
| * @priority; The context's priority to submit commands to GPU |
| * @tid: task that created this context. |
| * @dev_priv: pointer to the owning device instance |
| * @proc_priv: pointer to process private, the process that allocated the |
| * context |
| * @priv: in-kernel context flags, use KGSL_CONTEXT_* values |
| * @reset_status: status indication whether a gpu reset occured and whether |
| * this context was responsible for causing it |
| * @wait_on_invalid_ts: flag indicating if this context has tried to wait on a |
| * bad timestamp |
| * @timeline: sync timeline used to create fences that can be signaled when a |
| * sync_pt timestamp expires |
| * @events: A kgsl_event_group for this context - contains the list of GPU |
| * events |
| * @pagefault_ts: global timestamp of the pagefault, if KGSL_CONTEXT_PAGEFAULT |
| * is set. |
| * @flags: flags from userspace controlling the behavior of this context |
| * @pwr_constraint: power constraint from userspace for this context |
| * @fault_count: number of times gpu hanged in last _context_throttle_time ms |
| * @fault_time: time of the first gpu hang in last _context_throttle_time ms |
| */ |
| struct kgsl_context { |
| struct kref refcount; |
| uint32_t id; |
| uint32_t priority; |
| pid_t tid; |
| struct kgsl_device_private *dev_priv; |
| struct kgsl_process_private *proc_priv; |
| unsigned long priv; |
| struct kgsl_device *device; |
| unsigned int reset_status; |
| bool wait_on_invalid_ts; |
| struct sync_timeline *timeline; |
| struct kgsl_event_group events; |
| unsigned int pagefault_ts; |
| unsigned int flags; |
| struct kgsl_pwr_constraint pwr_constraint; |
| unsigned int fault_count; |
| unsigned long fault_time; |
| }; |
| |
| /** |
| * struct kgsl_process_private - Private structure for a KGSL process (across |
| * all devices) |
| * @priv: Internal flags, use KGSL_PROCESS_* values |
| * @pid: ID for the task owner of the process |
| * @comm: task name of the process |
| * @mem_lock: Spinlock to protect the process memory lists |
| * @refcount: kref object for reference counting the process |
| * @mem_rb: RB tree node for the memory owned by this process |
| * @idr: Iterator for assigning IDs to memory allocations |
| * @pagetable: Pointer to the pagetable owned by this process |
| * @kobj: Pointer to a kobj for the sysfs directory for this process |
| * @debug_root: Pointer to the debugfs root for this process |
| * @stats: Memory allocation statistics for this process |
| * @syncsource_idr: sync sources created by this process |
| * @syncsource_lock: Spinlock to protect the syncsource idr |
| * @fd_count: Counter for the number of FDs for this process |
| */ |
| struct kgsl_process_private { |
| unsigned long priv; |
| pid_t pid; |
| char comm[TASK_COMM_LEN]; |
| spinlock_t mem_lock; |
| struct kref refcount; |
| struct rb_root mem_rb; |
| struct idr mem_idr; |
| struct kgsl_pagetable *pagetable; |
| struct list_head list; |
| struct kobject kobj; |
| struct dentry *debug_root; |
| struct { |
| unsigned int cur; |
| unsigned int max; |
| } stats[KGSL_MEM_ENTRY_MAX]; |
| struct idr syncsource_idr; |
| spinlock_t syncsource_lock; |
| int fd_count; |
| }; |
| |
| /** |
| * enum kgsl_process_priv_flags - Private flags for kgsl_process_private |
| * @KGSL_PROCESS_INIT: Set if the process structure has been set up |
| */ |
| enum kgsl_process_priv_flags { |
| KGSL_PROCESS_INIT = 0, |
| }; |
| |
| struct kgsl_device_private { |
| struct kgsl_device *device; |
| struct kgsl_process_private *process_priv; |
| }; |
| |
| /** |
| * struct kgsl_snapshot - details for a specific snapshot instance |
| * @start: Pointer to the start of the static snapshot region |
| * @size: Size of the current snapshot instance |
| * @ptr: Pointer to the next block of memory to write to during snapshotting |
| * @remain: Bytes left in the snapshot region |
| * @timestamp: Timestamp of the snapshot instance (in seconds since boot) |
| * @mempool: Pointer to the memory pool for storing memory objects |
| * @mempool_size: Size of the memory pool |
| * @obj_list: List of frozen GPU buffers that are waiting to be dumped. |
| * @cp_list: List of IB's to be dumped. |
| * @work: worker to dump the frozen memory |
| * @dump_gate: completion gate signaled by worker when it is finished. |
| * @process: the process that caused the hang, if known. |
| */ |
| struct kgsl_snapshot { |
| u8 *start; |
| size_t size; |
| u8 *ptr; |
| size_t remain; |
| unsigned long timestamp; |
| u8 *mempool; |
| size_t mempool_size; |
| struct list_head obj_list; |
| struct list_head cp_list; |
| struct work_struct work; |
| struct completion dump_gate; |
| struct kgsl_process_private *process; |
| }; |
| |
| /** |
| * struct kgsl_snapshot_object - GPU memory in the snapshot |
| * @gpuaddr: The GPU address identified during snapshot |
| * @size: The buffer size identified during snapshot |
| * @offset: offset from start of the allocated kgsl_mem_entry |
| * @type: SNAPSHOT_OBJ_TYPE_* identifier. |
| * @entry: the reference counted memory entry for this buffer |
| * @node: node for kgsl_snapshot.obj_list |
| */ |
| struct kgsl_snapshot_object { |
| unsigned int gpuaddr; |
| unsigned int size; |
| unsigned int offset; |
| int type; |
| struct kgsl_mem_entry *entry; |
| struct list_head node; |
| }; |
| |
| /** |
| * struct kgsl_protected_registers - Protected register range |
| * @base: Offset of the range to be protected |
| * @range: Range (# of registers = 2 ** range) |
| */ |
| struct kgsl_protected_registers { |
| unsigned int base; |
| int range; |
| }; |
| |
| struct kgsl_device *kgsl_get_device(int dev_idx); |
| |
| static inline void kgsl_process_add_stats(struct kgsl_process_private *priv, |
| unsigned int type, size_t size) |
| { |
| priv->stats[type].cur += size; |
| if (priv->stats[type].max < priv->stats[type].cur) |
| priv->stats[type].max = priv->stats[type].cur; |
| } |
| |
| static inline void kgsl_regread(struct kgsl_device *device, |
| unsigned int offsetwords, |
| unsigned int *value) |
| { |
| device->ftbl->regread(device, offsetwords, value); |
| } |
| |
| static inline void kgsl_regwrite(struct kgsl_device *device, |
| unsigned int offsetwords, |
| unsigned int value) |
| { |
| device->ftbl->regwrite(device, offsetwords, value); |
| } |
| |
| static inline int kgsl_idle(struct kgsl_device *device) |
| { |
| return device->ftbl->idle(device); |
| } |
| |
| static inline unsigned int kgsl_gpuid(struct kgsl_device *device, |
| unsigned int *chipid) |
| { |
| return device->ftbl->gpuid(device, chipid); |
| } |
| |
| static inline int kgsl_create_device_sysfs_files(struct device *root, |
| const struct device_attribute **list) |
| { |
| int ret = 0, i; |
| for (i = 0; list[i] != NULL; i++) |
| ret |= device_create_file(root, list[i]); |
| return ret; |
| } |
| |
| static inline void kgsl_remove_device_sysfs_files(struct device *root, |
| const struct device_attribute **list) |
| { |
| int i; |
| for (i = 0; list[i] != NULL; i++) |
| device_remove_file(root, list[i]); |
| } |
| |
| static inline struct kgsl_mmu * |
| kgsl_get_mmu(struct kgsl_device *device) |
| { |
| return (struct kgsl_mmu *) (device ? &device->mmu : NULL); |
| } |
| |
| static inline struct kgsl_device *kgsl_device_from_dev(struct device *dev) |
| { |
| int i; |
| |
| for (i = 0; i < KGSL_DEVICE_MAX; i++) { |
| if (kgsl_driver.devp[i] && kgsl_driver.devp[i]->dev == dev) |
| return kgsl_driver.devp[i]; |
| } |
| |
| return NULL; |
| } |
| |
| static inline int kgsl_create_device_workqueue(struct kgsl_device *device) |
| { |
| device->work_queue = create_singlethread_workqueue(device->name); |
| if (!device->work_queue) { |
| KGSL_DRV_ERR(device, |
| "create_singlethread_workqueue(%s) failed\n", |
| device->name); |
| return -EINVAL; |
| } |
| return 0; |
| } |
| |
| static inline int kgsl_state_is_awake(struct kgsl_device *device) |
| { |
| if (device->state == KGSL_STATE_ACTIVE || |
| device->state == KGSL_STATE_AWARE) |
| return true; |
| else |
| return false; |
| } |
| |
| int kgsl_readtimestamp(struct kgsl_device *device, void *priv, |
| enum kgsl_timestamp_type type, unsigned int *timestamp); |
| |
| int kgsl_check_timestamp(struct kgsl_device *device, |
| struct kgsl_context *context, unsigned int timestamp); |
| |
| int kgsl_device_platform_probe(struct kgsl_device *device); |
| |
| void kgsl_device_platform_remove(struct kgsl_device *device); |
| |
| const char *kgsl_pwrstate_to_str(unsigned int state); |
| |
| int kgsl_device_snapshot_init(struct kgsl_device *device); |
| int kgsl_device_snapshot(struct kgsl_device *device, |
| struct kgsl_context *context); |
| void kgsl_device_snapshot_close(struct kgsl_device *device); |
| void kgsl_snapshot_save_frozen_objs(struct work_struct *work); |
| |
| void kgsl_events_init(void); |
| void kgsl_events_exit(void); |
| |
| void kgsl_del_event_group(struct kgsl_event_group *group); |
| |
| void kgsl_add_event_group(struct kgsl_event_group *group, |
| struct kgsl_context *context, const char *name, |
| readtimestamp_func readtimestamp, void *priv); |
| |
| void kgsl_cancel_events_timestamp(struct kgsl_device *device, |
| struct kgsl_event_group *group, unsigned int timestamp); |
| void kgsl_cancel_events(struct kgsl_device *device, |
| struct kgsl_event_group *group); |
| void kgsl_cancel_event(struct kgsl_device *device, |
| struct kgsl_event_group *group, unsigned int timestamp, |
| kgsl_event_func func, void *priv); |
| bool kgsl_event_pending(struct kgsl_device *device, |
| struct kgsl_event_group *group, unsigned int timestamp, |
| kgsl_event_func func, void *priv); |
| int kgsl_add_event(struct kgsl_device *device, struct kgsl_event_group *group, |
| unsigned int timestamp, kgsl_event_func func, void *priv); |
| void kgsl_process_event_group(struct kgsl_device *device, |
| struct kgsl_event_group *group); |
| void kgsl_flush_event_group(struct kgsl_device *device, |
| struct kgsl_event_group *group); |
| void kgsl_process_events(struct work_struct *work); |
| |
| void kgsl_context_destroy(struct kref *kref); |
| |
| int kgsl_context_init(struct kgsl_device_private *, struct kgsl_context |
| *context); |
| |
| void kgsl_context_dump(struct kgsl_context *context); |
| |
| int kgsl_memfree_find_entry(pid_t pid, unsigned long *gpuaddr, |
| unsigned long *size, unsigned int *flags); |
| |
| /** |
| * kgsl_context_put() - Release context reference count |
| * @context: Pointer to the KGSL context to be released |
| * |
| * Reduce the reference count on a KGSL context and destroy it if it is no |
| * longer needed |
| */ |
| static inline void |
| kgsl_context_put(struct kgsl_context *context) |
| { |
| if (context) |
| kref_put(&context->refcount, kgsl_context_destroy); |
| } |
| |
| /** |
| * kgsl_context_detached() - check if a context is detached |
| * @context: the context |
| * |
| * Check if a context has been destroyed by userspace and is only waiting |
| * for reference counts to go away. This check is used to weed out |
| * contexts that shouldn't use the gpu so NULL is considered detached. |
| */ |
| static inline bool kgsl_context_detached(struct kgsl_context *context) |
| { |
| return (context == NULL || test_bit(KGSL_CONTEXT_PRIV_DETACHED, |
| &context->priv)); |
| } |
| |
| /** |
| * kgsl_context_invalid() - check if a context is invalid |
| * @context: the context |
| * |
| * Check if a context has been invalidated by the kernel and may no |
| * longer use the GPU. |
| */ |
| static inline bool kgsl_context_invalid(struct kgsl_context *context) |
| { |
| return (context == NULL || test_bit(KGSL_CONTEXT_PRIV_INVALID, |
| &context->priv)); |
| } |
| |
| |
| /** |
| * kgsl_context_get() - get a pointer to a KGSL context |
| * @device: Pointer to the KGSL device that owns the context |
| * @id: Context ID |
| * |
| * Find the context associated with the given ID number, increase the reference |
| * count on it and return it. The caller must make sure that this call is |
| * paired with a kgsl_context_put. This function is for internal use because it |
| * doesn't validate the ownership of the context with the calling process - use |
| * kgsl_context_get_owner for that |
| */ |
| static inline struct kgsl_context *kgsl_context_get(struct kgsl_device *device, |
| uint32_t id) |
| { |
| int result = 0; |
| struct kgsl_context *context = NULL; |
| |
| read_lock(&device->context_lock); |
| |
| context = idr_find(&device->context_idr, id); |
| |
| /* Don't return a context that has been detached */ |
| if (kgsl_context_detached(context)) |
| context = NULL; |
| else |
| result = kref_get_unless_zero(&context->refcount); |
| |
| read_unlock(&device->context_lock); |
| |
| if (!result) |
| return NULL; |
| return context; |
| } |
| |
| /** |
| * _kgsl_context_get() - lightweight function to just increment the ref count |
| * @context: Pointer to the KGSL context |
| * |
| * Get a reference to the specified KGSL context structure. This is a |
| * lightweight way to just increase the refcount on a known context rather than |
| * walking through kgsl_context_get and searching the iterator |
| */ |
| static inline int _kgsl_context_get(struct kgsl_context *context) |
| { |
| int ret = 0; |
| |
| if (context) { |
| ret = kref_get_unless_zero(&context->refcount); |
| /* |
| * We shouldn't realistically fail kref_get_unless_zero unless |
| * we did something really dumb so make the failure both public |
| * and painful |
| */ |
| |
| WARN_ON(!ret); |
| } |
| |
| return ret; |
| } |
| |
| /** |
| * kgsl_context_get_owner() - get a pointer to a KGSL context in a specific |
| * process |
| * @dev_priv: Pointer to the process struct |
| * @id: Context ID to return |
| * |
| * Find the context associated with the given ID number, increase the reference |
| * count on it and return it. The caller must make sure that this call is |
| * paired with a kgsl_context_put. This function validates that the context id |
| * given is owned by the dev_priv instancet that is passed in. See |
| * kgsl_context_get for the internal version that doesn't do the check |
| */ |
| static inline struct kgsl_context *kgsl_context_get_owner( |
| struct kgsl_device_private *dev_priv, uint32_t id) |
| { |
| struct kgsl_context *context; |
| |
| context = kgsl_context_get(dev_priv->device, id); |
| |
| /* Verify that the context belongs to current calling fd. */ |
| if (context != NULL && context->dev_priv != dev_priv) { |
| kgsl_context_put(context); |
| return NULL; |
| } |
| |
| return context; |
| } |
| |
| void kgsl_dump_syncpoints(struct kgsl_device *device, |
| struct kgsl_cmdbatch *cmdbatch); |
| |
| void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch); |
| |
| void kgsl_cmdbatch_destroy_object(struct kref *kref); |
| |
| /** |
| * kgsl_process_private_get() - increment the refcount on a kgsl_process_private |
| * struct |
| * @process: Pointer to the KGSL process_private |
| * |
| * Returns 0 if the structure is invalid and a reference count could not be |
| * obtained, nonzero otherwise. |
| */ |
| static inline int kgsl_process_private_get(struct kgsl_process_private *process) |
| { |
| int ret = 0; |
| if (process != NULL) |
| ret = kref_get_unless_zero(&process->refcount); |
| return ret; |
| } |
| |
| void kgsl_process_private_put(struct kgsl_process_private *private); |
| |
| |
| struct kgsl_process_private *kgsl_process_private_find(pid_t pid); |
| |
| /** |
| * kgsl_cmdbatch_put() - Decrement the refcount for a command batch object |
| * @cmdbatch: Pointer to the command batch object |
| */ |
| static inline void kgsl_cmdbatch_put(struct kgsl_cmdbatch *cmdbatch) |
| { |
| if (cmdbatch) |
| kref_put(&cmdbatch->refcount, kgsl_cmdbatch_destroy_object); |
| } |
| |
| /** |
| * kgsl_property_read_u32() - Read a u32 property from the device tree |
| * @device: Pointer to the KGSL device |
| * @prop: String name of the property to query |
| * @ptr: Pointer to the variable to store the property |
| */ |
| static inline int kgsl_property_read_u32(struct kgsl_device *device, |
| const char *prop, unsigned int *ptr) |
| { |
| return of_property_read_u32(device->pdev->dev.of_node, prop, ptr); |
| } |
| |
| /** |
| * kgsl_sysfs_store() - parse a string from a sysfs store function |
| * @buf: Incoming string to parse |
| * @ptr: Pointer to an unsigned int to store the value |
| */ |
| static inline int kgsl_sysfs_store(const char *buf, unsigned int *ptr) |
| { |
| unsigned int val; |
| int rc; |
| |
| rc = kstrtou32(buf, 0, &val); |
| if (rc) |
| return rc; |
| |
| if (ptr) |
| *ptr = val; |
| |
| return 0; |
| } |
| |
| /* |
| * A helper macro to print out "not enough memory functions" - this |
| * makes it easy to standardize the messages as well as cut down on |
| * the number of strings in the binary |
| */ |
| #define SNAPSHOT_ERR_NOMEM(_d, _s) \ |
| KGSL_DRV_ERR((_d), \ |
| "snapshot: not enough snapshot memory for section %s\n", (_s)) |
| |
| /** |
| * struct kgsl_snapshot_registers - list of registers to snapshot |
| * @regs: Pointer to an array of register ranges |
| * @count: Number of entries in the array |
| */ |
| struct kgsl_snapshot_registers { |
| unsigned int *regs; |
| int count; |
| int dump; |
| unsigned int *snap_addr; |
| }; |
| |
| /** |
| * struct kgsl_snapshot_registers_list - list of register lists |
| * @registers: Pointer to an array of register lists |
| * @count: Number of entries in the array |
| */ |
| struct kgsl_snapshot_registers_list { |
| struct kgsl_snapshot_registers *registers; |
| int count; |
| }; |
| |
| size_t kgsl_snapshot_dump_regs(struct kgsl_device *device, u8 *snapshot, |
| size_t remain, void *priv); |
| |
| void kgsl_snapshot_indexed_registers(struct kgsl_device *device, |
| struct kgsl_snapshot *snapshot, unsigned int index, |
| unsigned int data, unsigned int start, unsigned int count); |
| |
| int kgsl_snapshot_get_object(struct kgsl_snapshot *snapshot, |
| struct kgsl_process_private *process, unsigned int gpuaddr, |
| unsigned int size, unsigned int type); |
| |
| int kgsl_snapshot_have_object(struct kgsl_snapshot *snapshot, |
| struct kgsl_process_private *process, |
| unsigned int gpuaddr, unsigned int size); |
| |
| struct adreno_ib_object_list; |
| |
| int kgsl_snapshot_add_ib_obj_list(struct kgsl_snapshot *snapshot, |
| struct adreno_ib_object_list *ib_obj_list); |
| |
| void kgsl_snapshot_dump_skipped_regs(struct kgsl_device *device, |
| struct kgsl_snapshot_registers_list *list); |
| |
| void kgsl_snapshot_add_section(struct kgsl_device *device, u16 id, |
| struct kgsl_snapshot *snapshot, |
| size_t (*func)(struct kgsl_device *, u8 *, size_t, void *), |
| void *priv); |
| |
| /** |
| * struct kgsl_pwr_limit - limit structure for each client |
| * @node: Local list node for the limits list |
| * @level: requested power level |
| * @device: pointer to the device structure |
| */ |
| struct kgsl_pwr_limit { |
| struct list_head node; |
| unsigned int level; |
| struct kgsl_device *device; |
| }; |
| |
| |
| #endif /* __KGSL_DEVICE_H */ |