summaryrefslogtreecommitdiff
path: root/drivers/gpu/msm/adreno_ringbuffer.h
blob: a2bf92acf4af5d050eac285131db268aa29faa9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/* Copyright (c) 2002,2007-2016,2019-2020 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 __ADRENO_RINGBUFFER_H
#define __ADRENO_RINGBUFFER_H

#include "kgsl_iommu.h"
#include "adreno_iommu.h"
#include "adreno_dispatch.h"

/* Given a ringbuffer, return the adreno device that owns it */

#define _RB_OFFSET(_id) (offsetof(struct adreno_device, ringbuffers) + \
		((_id) * sizeof(struct adreno_ringbuffer)))

#define ADRENO_RB_DEVICE(_rb) \
	((struct adreno_device *) (((void *) (_rb)) - _RB_OFFSET((_rb)->id)))

/* Adreno ringbuffer size in bytes */
#define KGSL_RB_SIZE (32 * 1024)

/*
 * A handy macro to convert the RB size to dwords since most ringbuffer
 * operations happen in dword increments
 */
#define KGSL_RB_DWORDS (KGSL_RB_SIZE >> 2)

struct kgsl_device;
struct kgsl_device_private;

/**
 * struct adreno_submit_time - utility structure to store the wall clock / GPU
 * ticks at command submit time
 * @ticks: GPU ticks at submit time (from the 19.2Mhz timer)
 * @ktime: local clock time (in nanoseconds)
 * @utime: Wall clock time
 */
struct adreno_submit_time {
	uint64_t ticks;
	u64 ktime;
	struct timespec utime;
};

/**
 * struct adreno_ringbuffer_pagetable_info - Contains fields used during a
 * pagetable switch.
 * @current_global_ptname: The current pagetable id being used by the GPU.
 * Only the ringbuffers[0] current_global_ptname is used to keep track of
 * the current pagetable id
 * @current_rb_ptname: The current pagetable active on the given RB
 * @incoming_ptname: Contains the incoming pagetable we are switching to. After
 * switching of pagetable this value equals current_rb_ptname.
 * @switch_pt_enable: Flag used during pagetable switch to check if pt
 * switch can be skipped
 * @ttbr0: value to program into TTBR0 during pagetable switch.
 * @contextidr: value to program into CONTEXTIDR during pagetable switch.
 */
struct adreno_ringbuffer_pagetable_info {
	int current_global_ptname;
	int current_rb_ptname;
	int incoming_ptname;
	int switch_pt_enable;
	uint64_t ttbr0;
	unsigned int contextidr;
};

#define PT_INFO_OFFSET(_field) \
	offsetof(struct adreno_ringbuffer_pagetable_info, _field)

/**
 * struct adreno_ringbuffer - Definition for an adreno ringbuffer object
 * @flags: Internal control flags for the ringbuffer
 * @buffer_desc: Pointer to the ringbuffer memory descripto
 * @_wptr: The next value of wptr to be written to the hardware on submit
 * @wptr: Local copy of the wptr offset last written to hardware
 * @last_wptr: offset of the last wptr that was written to CFF
 * @rb_ctx: The context that represents a ringbuffer
 * @id: Priority level of the ringbuffer, also used as an ID
 * @fault_detect_ts: The last retired global timestamp read during fault detect
 * @timestamp: The RB's global timestamp
 * @events: A kgsl_event_group for this context - contains the list of GPU
 * events
 * @drawctxt_active: The last pagetable that this ringbuffer is set to
 * @preemption_desc: The memory descriptor containing
 * preemption info written/read by CP
 * @pagetable_desc: Memory to hold information about the pagetables being used
 * and the commands to switch pagetable on the RB
 * @dispatch_q: The dispatcher side queue for this ringbuffer
 * @ts_expire_waitq: Wait queue to wait for rb timestamp to expire
 * @ts_expire_waitq: Wait q to wait for rb timestamp to expire
 * @wptr_preempt_end: Used during preemption to check that preemption occurred
 * at the right rptr
 * @gpr11: The gpr11 value of this RB
 * @preempted_midway: Indicates that the RB was preempted before rptr = wptr
 * @sched_timer: Timer that tracks how long RB has been waiting to be scheduled
 * or how long it has been scheduled for after preempting in
 * @starve_timer_state: Indicates the state of the wait.
 * @preempt_lock: Lock to protect the wptr pointer while it is being updated
 */
struct adreno_ringbuffer {
	uint32_t flags;
	struct kgsl_memdesc buffer_desc;
	unsigned int _wptr;
	unsigned int wptr;
	unsigned int last_wptr;
	int id;
	unsigned int fault_detect_ts;
	unsigned int timestamp;
	struct kgsl_event_group events;
	struct adreno_context *drawctxt_active;
	struct kgsl_memdesc preemption_desc;
	struct kgsl_memdesc pagetable_desc;
	struct adreno_dispatcher_drawqueue dispatch_q;
	wait_queue_head_t ts_expire_waitq;
	unsigned int wptr_preempt_end;
	unsigned int gpr11;
	int preempted_midway;
	unsigned long sched_timer;
	enum adreno_dispatcher_starve_timer_states starve_timer_state;
	spinlock_t preempt_lock;
	/**
	 * @profile_desc: global memory to construct IB1s to do user side
	 * profiling
	 */
	struct kgsl_memdesc profile_desc;
	/**
	 * @profile_index: Pointer to the next "slot" in profile_desc for a user
	 * profiling IB1.  This allows for PAGE_SIZE / 16 = 256 simultaneous
	 * commands per ringbuffer with user profiling enabled
	 * enough.
	 */
	u32 profile_index;
};

/* Returns the current ringbuffer */
#define ADRENO_CURRENT_RINGBUFFER(a)	((a)->cur_rb)

int cp_secure_mode(struct adreno_device *adreno_dev, uint *cmds, int set);

int adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv,
				struct kgsl_context *context,
				struct kgsl_drawobj *drawobj,
				uint32_t *timestamp);

int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev,
		struct kgsl_drawobj_cmd *cmdobj,
		struct adreno_submit_time *time);

int adreno_ringbuffer_probe(struct adreno_device *adreno_dev, bool nopreempt);

int adreno_ringbuffer_start(struct adreno_device *adreno_dev,
		unsigned int start_type);

void adreno_ringbuffer_stop(struct adreno_device *adreno_dev);

void adreno_ringbuffer_close(struct adreno_device *adreno_dev);

int adreno_ringbuffer_issuecmds(struct adreno_ringbuffer *rb,
					unsigned int flags,
					unsigned int *cmdaddr,
					int sizedwords);

void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb,
		struct adreno_submit_time *time);

int adreno_ringbuffer_submit_spin_nosync(struct adreno_ringbuffer *rb,
		struct adreno_submit_time *time, unsigned int timeout);

int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb,
		struct adreno_submit_time *time, unsigned int timeout);

void kgsl_cp_intrcallback(struct kgsl_device *device);

unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb,
						unsigned int numcmds);

void adreno_ringbuffer_read_pfp_ucode(struct kgsl_device *device);

void adreno_ringbuffer_read_pm4_ucode(struct kgsl_device *device);

int adreno_ringbuffer_waittimestamp(struct adreno_ringbuffer *rb,
					unsigned int timestamp,
					unsigned int msecs);

int adreno_rb_readtimestamp(struct adreno_device *adreno_dev,
	void *priv, enum kgsl_timestamp_type type,
	unsigned int *timestamp);

static inline int adreno_ringbuffer_count(struct adreno_ringbuffer *rb,
	unsigned int rptr)
{
	if (rb->wptr >= rptr)
		return rb->wptr - rptr;
	return rb->wptr + KGSL_RB_DWORDS - rptr;
}

/* Increment a value by 4 bytes with wrap-around based on size */
static inline unsigned int adreno_ringbuffer_inc_wrapped(unsigned int val,
							unsigned int size)
{
	return (val + sizeof(unsigned int)) % size;
}

/* Decrement a value by 4 bytes with wrap-around based on size */
static inline unsigned int adreno_ringbuffer_dec_wrapped(unsigned int val,
							unsigned int size)
{
	return (val + size - sizeof(unsigned int)) % size;
}

static inline int adreno_ringbuffer_set_pt_ctx(struct adreno_ringbuffer *rb,
		struct kgsl_pagetable *pt, struct adreno_context *context,
		unsigned long flags)
{
	return adreno_iommu_set_pt_ctx(rb, pt, context, flags);
}

#endif  /* __ADRENO_RINGBUFFER_H */