summaryrefslogtreecommitdiff
path: root/drivers/gpu/mali/mali400ko/driver/src/devicedrv/mali/common/mali_kernel_rendercore.h
blob: 94bce94d4e101c06261cbbe0c78a1a5ee20ce0ac (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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
/*
 * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
 * 
 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
 * 
 * A copy of the licence is included with the program, and can also be obtained from Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#ifndef __MALI_RENDERCORE_H__
#define __MALI_RENDERCORE_H__

#include "mali_osk.h"
#include "mali_kernel_common.h"
#include "mali_kernel_subsystem.h"

#define PRIORITY_LEVELS 3
#define PRIORITY_MAX 0
#define PRIORITY_MIN (PRIORITY_MAX+PRIORITY_LEVELS-1)

/* This file contains what we need in kernel for all core types. */

typedef enum
{
	CORE_IDLE,              /**< Core is ready for a new job */
	CORE_WORKING,           /**< Core is working on a job */
	CORE_WATCHDOG_TIMEOUT,  /**< Core is working but it has timed out */
	CORE_POLL,              /**< Poll timer triggered, pending handling */
	CORE_HANG_CHECK_TIMEOUT,/**< Timeout for hang detection */
	CORE_OFF                /**< Core is powered off */
} mali_core_status;

typedef enum
{
	SUBSYSTEM_RESCHEDULE,
	SUBSYSTEM_WAIT
} mali_subsystem_reschedule_option;

typedef enum
{
	MALI_CORE_RESET_STYLE_RUNABLE,
	MALI_CORE_RESET_STYLE_DISABLE,
	MALI_CORE_RESET_STYLE_HARD
} mali_core_reset_style;

typedef enum
{
	JOB_STATUS_CONTINUE_RUN			= 0x01,
	JOB_STATUS_END_SUCCESS			= 1<<(16+0),
	JOB_STATUS_END_OOM				= 1<<(16+1),
	JOB_STATUS_END_ABORT			= 1<<(16+2),
	JOB_STATUS_END_TIMEOUT_SW		= 1<<(16+3),
	JOB_STATUS_END_HANG				= 1<<(16+4),
	JOB_STATUS_END_SEG_FAULT		= 1<<(16+5),
	JOB_STATUS_END_ILLEGAL_JOB		= 1<<(16+6),
	JOB_STATUS_END_UNKNOWN_ERR		= 1<<(16+7),
	JOB_STATUS_END_SHUTDOWN			= 1<<(16+8),
	JOB_STATUS_END_SYSTEM_UNUSABLE	= 1<<(16+9)
} mali_subsystem_job_end_code;


struct mali_core_job;
struct mali_core_subsystem;
struct mali_core_renderunit;
struct mali_core_session;

/* We have one of these subsystems for each core type */
typedef struct mali_core_subsystem
{
	struct mali_core_renderunit ** mali_core_array; /* An array of all cores of this type */
	u32 number_of_cores; /* Number of cores in this list */

	_mali_core_type core_type;

	u32 magic_nr;

	_mali_osk_list_t renderunit_idle_head; /* Idle cores of this type */
	_mali_osk_list_t renderunit_off_head;  /* Powered off cores of this type */

	/* Linked list for each priority of sessions with a job ready for scheduelling */
	_mali_osk_list_t awaiting_sessions_head[PRIORITY_LEVELS];
	u32 awaiting_sessions_sum_all_priorities;

	/* Linked list of all sessions connected to this coretype */
	_mali_osk_list_t all_sessions_head;

	/* Linked list of all sessions connected to this coretype */
    struct _mali_osk_notification_queue_t * notification_queue;

	const char * name;
	mali_kernel_subsystem_identifier id;

	/**** Functions registered for this core type. Set during mali_core_init ******/
	/* Start this job on this core. Return MALI_TRUE if the job was started. */
	_mali_osk_errcode_t (*start_job)(struct mali_core_job * job, struct mali_core_renderunit * core);

	/* Check if given core has an interrupt pending. Return MALI_TRUE and set mask to 0 if pending */
	u32 (*irq_handler_upper_half)(struct mali_core_renderunit * core);

	/* This function should check if the interrupt indicates that job was finished.
	If so it should update the job-struct, reset the core registers, and return MALI_TRUE, .
	If the job is still working after this function it should return MALI_FALSE.
	The function must also enable the bits in the interrupt mask for the core.
	Called by the bottom half interrupt function.	*/
	int (*irq_handler_bottom_half)(struct mali_core_renderunit* core);

	/* This function is called from the ioctl function and should return a mali_core_job pointer
	to a created mali_core_job object with the data given from userspace */
	_mali_osk_errcode_t (*get_new_job_from_user)(struct mali_core_session * session, void * argument);

	_mali_osk_errcode_t (*suspend_response)(struct mali_core_session * session, void * argument);

	/* This function is called from the ioctl function and should write the necessary data
	 to userspace telling which job was finished and the status and debuginfo for this job.
	 The function must also free and cleanup the input job object. */
	void (*return_job_to_user)(struct mali_core_job * job, mali_subsystem_job_end_code end_status);

	/* Is called when a subsystem shuts down. This function needs to
	   release internal pointers in the core struct, and free the
	   core struct before returning.
	   It is not allowed to write to any registers, since this
	   unmapping is already done. */
	void (*renderunit_delete)(struct mali_core_renderunit * core);

	/* Is called when we want to abort a job that is running on the core.
	   This is done if program exits while core is running */
	void (*reset_core)(struct mali_core_renderunit * core, mali_core_reset_style style);

	/* Is called when the rendercore wants the core to give an interrupt */
	void (*probe_core_irq_trigger)(struct mali_core_renderunit* core);

	/* Is called when the irq probe wants the core to acknowledge an interrupt from the hw */
	_mali_osk_errcode_t (*probe_core_irq_acknowledge)(struct mali_core_renderunit* core);

	/* Called when the rendercore want to issue a bus stop request to a core */
	void (*stop_bus)(struct mali_core_renderunit* core);
} mali_core_subsystem;


/* Per core data. This must be embedded into each core type internal core info. */
typedef struct mali_core_renderunit
{
	struct mali_core_subsystem * subsystem; /* The core belongs to this subsystem */
	_mali_osk_list_t list;                  /* Is always in subsystem->idle_list OR session->renderunits_working */
	mali_core_status  state;
	mali_bool error_recovery;               /* Indicates if the core is waiting for external help to recover (typically the MMU) */
	mali_bool in_detach_function;
	struct mali_core_job * current_job;     /* Current job being processed on this core ||NULL */
	u32 magic_nr;
 	_mali_osk_timer_t * timer;
	_mali_osk_timer_t * timer_hang_detection;

	mali_io_address registers_mapped;       /* IO-mapped pointer to registers */
	u32   registers_base_addr;              /* Base addres of the registers */
	u32 size;                               /* The size of registers_mapped */
	const char * description;               /* Description of this core. */
	u32 irq_nr;                             /* The IRQ nr for this core */
	u32 core_version;
#if USING_MMU
	u32 mmu_id;
	void * mmu;                             /* The MMU this rendercore is behind.*/
#endif
#if USING_MALI_PMM
	mali_pmm_core_id pmm_id;                /* The PMM core id */
	mali_bool pend_power_down;              /* Power down is requested */
#endif

	u32 core_number;                        /* 0 for first detected core of this type, 1 for second and so on */

    _mali_osk_irq_t *irq;
} mali_core_renderunit;


/* Per open FILE data. */
/* You must held subsystem->mutex before any transactions to this datatype. */
typedef struct mali_core_session
{
	struct mali_core_subsystem * subsystem;	   /* The session belongs to this subsystem */
	_mali_osk_list_t renderunits_working_head; /* List of renderunits working for this session */
	struct mali_core_job *job_waiting_to_run;  /* The next job from this session to run */

	_mali_osk_list_t awaiting_sessions_list; /* Linked list of sessions with jobs, for each priority */
	_mali_osk_list_t all_sessions_list;      /* Linked list of all sessions on the system. */

    _mali_osk_notification_queue_t * notification_queue; /* Messages back to Base in userspace*/
#if USING_MMU
	struct mali_session_data * mmu_session; /* The session associated with the MMU page tables for this core */
#endif
	u32 magic_nr;
} mali_core_session;


/* This must be embedded into a specific mali_core_job struct */
/* use this macro to get spesific mali_core_job:  container_of(ptr, type, member)*/
typedef struct mali_core_job
{
	_mali_osk_list_t list; /* Linked list of jobs. Used by struct mali_core_session */
	struct mali_core_session *session;
	u32 magic_nr;
	u32 priority;
	u32 watchdog_msecs;
	u32 render_time_msecs ;
	u32 start_time_jiffies;
	unsigned long watchdog_jiffies;
	u32 abort_id;
} mali_core_job;

/*
 * The rendercode subsystem is included in the subsystems[] array.
 */
extern struct mali_kernel_subsystem mali_subsystem_rendercore;

void subsystem_flush_mapped_mem_cache(void);


#define SUBSYSTEM_MAGIC_NR 	0xdeadbeef
#define CORE_MAGIC_NR 		0xcafebabe
#define SESSION_MAGIC_NR 	0xbabe1234
#define JOB_MAGIC_NR 		0x0123abcd


#define MALI_CHECK_SUBSYSTEM(subsystem)\
	do { \
		if ( SUBSYSTEM_MAGIC_NR != subsystem->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\
	} while (0)

#define MALI_CHECK_CORE(CORE)\
	do { \
		if ( CORE_MAGIC_NR != CORE->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\
} while (0)

#define MALI_CHECK_SESSION(SESSION)\
	do { \
		if ( SESSION_MAGIC_NR != SESSION->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\
} while (0)

#define MALI_CHECK_JOB(JOB)\
	do { \
		if ( JOB_MAGIC_NR != JOB->magic_nr) MALI_PRINT_ERROR(("Wrong magic number"));\
} while (0)


/* Check if job_a has higher priority than job_b */
MALI_STATIC_INLINE int job_has_higher_priority(mali_core_job * job_a, mali_core_job * job_b)
{
	/* The lowest number has the highest priority */
	return (int) (job_a->priority < job_b->priority);
}

MALI_STATIC_INLINE void job_priority_set(mali_core_job * job, u32 priority)
{
	if (priority > PRIORITY_MIN) job->priority = PRIORITY_MIN;
	else job->priority = priority;
}

void job_watchdog_set(mali_core_job * job, u32 watchdog_msecs);

/* For use by const default register settings (e.g. set these after reset) */
typedef struct register_address_and_value
{
	u32 address;
	u32 value;
} register_address_and_value ;


/* For use by dynamic default register settings (e.g. set these after reset) */
typedef struct register_address_and_value_list
{
	_mali_osk_list_t list;
	register_address_and_value item;
} register_address_and_value_list ;

/* Used if the user wants to set a continious block of registers */
typedef struct register_array_user
{
	u32 entries_in_array;
	u32 start_address;
	void __user * reg_array;
}register_array_user;


#define MALI_CORE_SUBSYSTEM_MUTEX_GRAB(subsys) \
	do { \
		MALI_DEBUG_PRINT(5, ("MUTEX: GRAB %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \
		_mali_osk_lock_wait( rendercores_global_mutex, _MALI_OSK_LOCKMODE_RW); \
		MALI_DEBUG_PRINT(5, ("MUTEX: GRABBED %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \
		if ( SUBSYSTEM_MAGIC_NR != subsys->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\
		rendercores_global_mutex_is_held = 1; \
		rendercores_global_mutex_owner = _mali_osk_get_tid();  \
	} while (0) ;

#define MALI_CORE_SUBSYSTEM_MUTEX_RELEASE(subsys) \
	do { \
		MALI_DEBUG_PRINT(5, ("MUTEX: RELEASE %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \
		rendercores_global_mutex_is_held = 0; \
		 rendercores_global_mutex_owner = 0; \
		if ( SUBSYSTEM_MAGIC_NR != subsys->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\
		_mali_osk_lock_signal( rendercores_global_mutex, _MALI_OSK_LOCKMODE_RW); \
		MALI_DEBUG_PRINT(5, ("MUTEX: RELEASED %s() %d on %s\n",__FUNCTION__, __LINE__, subsys->name)); \
		if ( SUBSYSTEM_MAGIC_NR != subsys->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\
	} while (0) ;


#define MALI_ASSERT_MUTEX_IS_GRABBED(input_pointer)\
	do { \
		if ( 0 == rendercores_global_mutex_is_held ) MALI_PRINT_ERROR(("ASSERT MUTEX SHOULD BE GRABBED"));\
		if ( SUBSYSTEM_MAGIC_NR != input_pointer->magic_nr ) MALI_PRINT_ERROR(("Wrong magic number"));\
		if ( rendercores_global_mutex_owner != _mali_osk_get_tid() ) MALI_PRINT_ERROR(("Owner mismatch"));\
	} while (0)


u32   mali_core_renderunit_register_read(struct mali_core_renderunit *core, u32 relative_address);
void  mali_core_renderunit_register_read_array(struct mali_core_renderunit *core, u32 relative_address,  u32 * result_array, u32 nr_of_regs);
void  mali_core_renderunit_register_write(struct mali_core_renderunit *core, u32 relative_address, u32 new_val);
void  mali_core_renderunit_register_write_array(struct mali_core_renderunit *core, u32 relative_address,  u32 * write_array, u32 nr_of_regs);

_mali_osk_errcode_t  mali_core_renderunit_init(struct mali_core_renderunit * core);
void  mali_core_renderunit_term(struct mali_core_renderunit * core);
int   mali_core_renderunit_map_registers(struct mali_core_renderunit *core);
void  mali_core_renderunit_unmap_registers(struct mali_core_renderunit *core);
int   mali_core_renderunit_irq_handler_add(struct mali_core_renderunit *core);
mali_core_renderunit * mali_core_renderunit_get_mali_core_nr(mali_core_subsystem *subsys, u32 mali_core_nr);

int mali_core_subsystem_init(struct mali_core_subsystem * new_subsys);
#if USING_MMU
void mali_core_subsystem_attach_mmu(mali_core_subsystem* subsys);
#endif
int mali_core_subsystem_register_renderunit(struct mali_core_subsystem * subsys, struct mali_core_renderunit * core);
int mali_core_subsystem_system_info_fill(mali_core_subsystem* subsys, _mali_system_info* info);
void mali_core_subsystem_cleanup(struct mali_core_subsystem * subsys);
#if USING_MMU
void mali_core_subsystem_broadcast_notification(struct mali_core_subsystem * subsys, mali_core_notification_message message, u32 data);
#endif
void mali_core_session_begin(mali_core_session *session);
void mali_core_session_close(mali_core_session * session);
int mali_core_session_add_job(mali_core_session * session, mali_core_job *job, mali_core_job **job_return);
u32 mali_core_hang_check_timeout_get(void);

_mali_osk_errcode_t mali_core_subsystem_ioctl_start_job(mali_core_session * session, void *job_data);
_mali_osk_errcode_t mali_core_subsystem_ioctl_number_of_cores_get(mali_core_session * session, u32 *number_of_cores);
_mali_osk_errcode_t mali_core_subsystem_ioctl_core_version_get(mali_core_session * session, _mali_core_version *version);
_mali_osk_errcode_t mali_core_subsystem_ioctl_suspend_response(mali_core_session * session, void* argument);
void mali_core_subsystem_ioctl_abort_job(mali_core_session * session, u32 id);

#if USING_MALI_PMM
_mali_osk_errcode_t mali_core_subsystem_signal_power_down(mali_core_subsystem *subsys, u32 mali_core_nr, mali_bool immediate_only);
_mali_osk_errcode_t mali_core_subsystem_signal_power_up(mali_core_subsystem *subsys, u32 mali_core_nr, mali_bool queue_only);
#endif

#if MALI_STATE_TRACKING
void mali_core_renderunit_dump_state(mali_core_subsystem* subsystem);
#endif

#endif /* __MALI_RENDERCORE_H__ */