PageRenderTime 108ms CodeModel.GetById 45ms app.highlight 29ms RepoModel.GetById 26ms app.codeStats 0ms

/drivers/gpu/mali/mali/common/mali_group.c

https://bitbucket.org/ndreys/linux-sunxi
C | 841 lines | 639 code | 144 blank | 58 comment | 122 complexity | d431b92d3073507f55fe78dce03ebea8 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  1/*
  2 * Copyright (C) 2011-2012 ARM Limited. All rights reserved.
  3 * 
  4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
  5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
  6 * 
  7 * A copy of the licence is included with the program, and can also be obtained from Free Software
  8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  9 */
 10
 11#include "mali_kernel_common.h"
 12#include "mali_group.h"
 13#include "mali_osk.h"
 14#include "mali_cluster.h"
 15#include "mali_gp.h"
 16#include "mali_pp.h"
 17#include "mali_mmu.h"
 18#include "mali_gp_scheduler.h"
 19#include "mali_pp_scheduler.h"
 20#include "mali_pm.h"
 21
 22/*
 23 * The group object is the most important object in the device driver,
 24 * and acts as the center of many HW operations.
 25 * The reason for this is that operations on the MMU will affect all
 26 * cores connected to this MMU (a group is defined by the MMU and the
 27 * cores which are connected to this).
 28 * The group lock is thus the most important lock, followed by the
 29 * GP and PP scheduler locks. They must be taken in the following
 30 * order:
 31 * GP/PP lock first, then group lock(s).
 32 */
 33
 34/**
 35 * The structure represents a render group
 36 * A render group is defined by all the cores that share the same Mali MMU
 37 */
 38
 39struct mali_group
 40{
 41	struct mali_cluster *cluster;
 42
 43	struct mali_mmu_core *mmu;
 44	struct mali_session_data *session;
 45	int page_dir_ref_count;
 46	mali_bool power_is_on;
 47#if defined(USING_MALI200)
 48	mali_bool pagedir_activation_failed;
 49#endif
 50
 51	struct mali_gp_core         *gp_core;
 52	enum mali_group_core_state  gp_state;
 53	struct mali_gp_job          *gp_running_job;
 54
 55	struct mali_pp_core         *pp_core;
 56	enum mali_group_core_state  pp_state;
 57	struct mali_pp_job          *pp_running_job;
 58	u32                         pp_running_sub_job;
 59
 60	_mali_osk_lock_t *lock;
 61};
 62
 63static struct mali_group *mali_global_groups[MALI_MAX_NUMBER_OF_GROUPS];
 64static u32 mali_global_num_groups = 0;
 65
 66enum mali_group_activate_pd_status
 67{
 68	MALI_GROUP_ACTIVATE_PD_STATUS_FAILED,
 69	MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD,
 70	MALI_GROUP_ACTIVATE_PD_STATUS_OK_SWITCHED_PD,
 71};
 72
 73/* local helper functions */
 74static enum mali_group_activate_pd_status mali_group_activate_page_directory(struct mali_group *group, struct mali_session_data *session);
 75static void mali_group_deactivate_page_directory(struct mali_group *group, struct mali_session_data *session);
 76static void mali_group_recovery_reset(struct mali_group *group);
 77static void mali_group_complete_jobs(struct mali_group *group, mali_bool complete_gp, mali_bool complete_pp, bool success);
 78
 79void mali_group_lock(struct mali_group *group)
 80{
 81	if(_MALI_OSK_ERR_OK != _mali_osk_lock_wait(group->lock, _MALI_OSK_LOCKMODE_RW))
 82	{
 83		/* Non-interruptable lock failed: this should never happen. */
 84		MALI_DEBUG_ASSERT(0);
 85	}
 86	MALI_DEBUG_PRINT(5, ("Mali group: Group lock taken 0x%08X\n", group));
 87}
 88
 89void mali_group_unlock(struct mali_group *group)
 90{
 91	MALI_DEBUG_PRINT(5, ("Mali group: Releasing group lock 0x%08X\n", group));
 92	_mali_osk_lock_signal(group->lock, _MALI_OSK_LOCKMODE_RW);
 93}
 94
 95#ifdef DEBUG
 96void mali_group_assert_locked(struct mali_group *group)
 97{
 98	MALI_DEBUG_ASSERT_LOCK_HELD(group->lock);
 99}
100#endif
101
102
103struct mali_group *mali_group_create(struct mali_cluster *cluster, struct mali_mmu_core *mmu)
104{
105	struct mali_group *group = NULL;
106
107	if (mali_global_num_groups >= MALI_MAX_NUMBER_OF_GROUPS)
108	{
109		MALI_PRINT_ERROR(("Mali group: Too many group objects created\n"));
110		return NULL;
111	}
112
113	group = _mali_osk_malloc(sizeof(struct mali_group));
114	if (NULL != group)
115	{
116		_mali_osk_memset(group, 0, sizeof(struct mali_group));
117		group->lock = _mali_osk_lock_init(_MALI_OSK_LOCKFLAG_ORDERED | _MALI_OSK_LOCKFLAG_SPINLOCK_IRQ |_MALI_OSK_LOCKFLAG_NONINTERRUPTABLE, 0, _MALI_OSK_LOCK_ORDER_GROUP);
118		if (NULL != group->lock)
119		{
120			group->cluster = cluster;
121			group->mmu = mmu; /* This group object now owns the MMU object */
122			group->session = NULL;
123			group->page_dir_ref_count = 0;
124			group->power_is_on = MALI_TRUE;
125
126			group->gp_state = MALI_GROUP_CORE_STATE_IDLE;
127			group->pp_state = MALI_GROUP_CORE_STATE_IDLE;
128#if defined(USING_MALI200)
129			group->pagedir_activation_failed = MALI_FALSE;
130#endif
131			mali_global_groups[mali_global_num_groups] = group;
132			mali_global_num_groups++;
133
134			return group;
135		}
136		_mali_osk_free(group);
137	}
138
139	return NULL;
140}
141
142void mali_group_add_gp_core(struct mali_group *group, struct mali_gp_core* gp_core)
143{
144	/* This group object now owns the GP core object */
145	group->gp_core = gp_core;
146}
147
148void mali_group_add_pp_core(struct mali_group *group, struct mali_pp_core* pp_core)
149{
150	/* This group object now owns the PP core object */
151	group->pp_core = pp_core;
152}
153
154void mali_group_delete(struct mali_group *group)
155{
156	u32 i;
157
158	/* Delete the resources that this group owns */
159	if (NULL != group->gp_core)
160	{
161		mali_gp_delete(group->gp_core);
162	}
163
164	if (NULL != group->pp_core)
165	{
166		mali_pp_delete(group->pp_core);
167	}
168
169	if (NULL != group->mmu)
170	{
171		mali_mmu_delete(group->mmu);
172	}
173
174	for (i = 0; i < mali_global_num_groups; i++)
175	{
176		if (mali_global_groups[i] == group)
177		{
178			mali_global_groups[i] = NULL;
179			mali_global_num_groups--;
180			break;
181		}
182	}
183
184	_mali_osk_lock_term(group->lock);
185
186	_mali_osk_free(group);
187}
188
189/* Called from mali_cluster_reset() when the system is re-turned on */
190void mali_group_reset(struct mali_group *group)
191{
192	mali_group_lock(group);
193
194	group->session = NULL;
195
196	if (NULL != group->mmu)
197	{
198		mali_mmu_reset(group->mmu);
199	}
200
201	if (NULL != group->gp_core)
202	{
203		mali_gp_reset(group->gp_core);
204	}
205
206	if (NULL != group->pp_core)
207	{
208		mali_pp_reset(group->pp_core);
209	}
210
211	mali_group_unlock(group);
212}
213
214struct mali_gp_core* mali_group_get_gp_core(struct mali_group *group)
215{
216	return group->gp_core;
217}
218
219struct mali_pp_core* mali_group_get_pp_core(struct mali_group *group)
220{
221	return group->pp_core;
222}
223
224_mali_osk_errcode_t mali_group_start_gp_job(struct mali_group *group, struct mali_gp_job *job)
225{
226	struct mali_session_data *session;
227	enum mali_group_activate_pd_status activate_status;
228
229	MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->gp_state);
230
231	mali_pm_core_event(MALI_CORE_EVENT_GP_START);
232
233	session = mali_gp_job_get_session(job);
234
235	mali_group_lock(group);
236
237	mali_cluster_l2_cache_invalidate_all(group->cluster, mali_gp_job_get_id(job));
238
239	activate_status = mali_group_activate_page_directory(group, session);
240	if (MALI_GROUP_ACTIVATE_PD_STATUS_FAILED != activate_status)
241	{
242		/* if session is NOT kept Zapping is done as part of session switch */
243		if (MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD == activate_status)
244		{
245			mali_mmu_zap_tlb_without_stall(group->mmu);
246		}
247		mali_gp_job_start(group->gp_core, job);
248		group->gp_running_job = job;
249		group->gp_state = MALI_GROUP_CORE_STATE_WORKING;
250
251		mali_group_unlock(group);
252
253		return _MALI_OSK_ERR_OK;
254	}
255
256#if defined(USING_MALI200)
257	group->pagedir_activation_failed = MALI_TRUE;
258#endif
259
260	mali_group_unlock(group);
261
262	mali_pm_core_event(MALI_CORE_EVENT_GP_STOP); /* Failed to start, so "cancel" the MALI_CORE_EVENT_GP_START */
263	return _MALI_OSK_ERR_FAULT;
264}
265
266_mali_osk_errcode_t mali_group_start_pp_job(struct mali_group *group, struct mali_pp_job *job, u32 sub_job)
267{
268	struct mali_session_data *session;
269	enum mali_group_activate_pd_status activate_status;
270
271	MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->pp_state);
272
273	mali_pm_core_event(MALI_CORE_EVENT_PP_START);
274
275	session = mali_pp_job_get_session(job);
276
277	mali_group_lock(group);
278
279	mali_cluster_l2_cache_invalidate_all(group->cluster, mali_pp_job_get_id(job));
280
281	activate_status = mali_group_activate_page_directory(group, session);
282	if (MALI_GROUP_ACTIVATE_PD_STATUS_FAILED != activate_status)
283	{
284		/* if session is NOT kept Zapping is done as part of session switch */
285		if (MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD == activate_status)
286		{
287			MALI_DEBUG_PRINT(3, ("PP starting job PD_Switch 0 Flush 1 Zap 1\n"));
288			mali_mmu_zap_tlb_without_stall(group->mmu);
289		}
290		mali_pp_job_start(group->pp_core, job, sub_job);
291		group->pp_running_job = job;
292		group->pp_running_sub_job = sub_job;
293		group->pp_state = MALI_GROUP_CORE_STATE_WORKING;
294
295		mali_group_unlock(group);
296
297		return _MALI_OSK_ERR_OK;
298	}
299
300#if defined(USING_MALI200)
301	group->pagedir_activation_failed = MALI_TRUE;
302#endif
303
304	mali_group_unlock(group);
305
306	mali_pm_core_event(MALI_CORE_EVENT_PP_STOP); /* Failed to start, so "cancel" the MALI_CORE_EVENT_PP_START */
307	return _MALI_OSK_ERR_FAULT;
308}
309
310void mali_group_resume_gp_with_new_heap(struct mali_group *group, u32 job_id, u32 start_addr, u32 end_addr)
311{
312	mali_group_lock(group);
313
314	if (group->gp_state != MALI_GROUP_CORE_STATE_OOM ||
315	    mali_gp_job_get_id(group->gp_running_job) != job_id)
316	{
317		mali_group_unlock(group);
318		return; /* Illegal request or job has already been aborted */
319	}
320
321	mali_cluster_l2_cache_invalidate_all_force(group->cluster);
322	mali_mmu_zap_tlb_without_stall(group->mmu);
323
324	mali_gp_resume_with_new_heap(group->gp_core, start_addr, end_addr);
325	group->gp_state = MALI_GROUP_CORE_STATE_WORKING;
326
327	mali_group_unlock(group);
328}
329
330void mali_group_abort_gp_job(struct mali_group *group, u32 job_id)
331{
332	mali_group_lock(group);
333
334	if (group->gp_state == MALI_GROUP_CORE_STATE_IDLE ||
335	    mali_gp_job_get_id(group->gp_running_job) != job_id)
336	{
337		mali_group_unlock(group);
338		return; /* No need to cancel or job has already been aborted or completed */
339	}
340
341	mali_group_complete_jobs(group, MALI_TRUE, MALI_FALSE, MALI_FALSE); /* Will release group lock */
342}
343
344void mali_group_abort_pp_job(struct mali_group *group, u32 job_id)
345{
346	mali_group_lock(group);
347
348	if (group->pp_state == MALI_GROUP_CORE_STATE_IDLE ||
349	    mali_pp_job_get_id(group->pp_running_job) != job_id)
350	{
351		mali_group_unlock(group);
352		return; /* No need to cancel or job has already been aborted or completed */
353	}
354
355	mali_group_complete_jobs(group, MALI_FALSE, MALI_TRUE, MALI_FALSE); /* Will release group lock */
356}
357
358void mali_group_abort_session(struct mali_group *group, struct mali_session_data *session)
359{
360	struct mali_gp_job *gp_job;
361	struct mali_pp_job *pp_job;
362	u32 gp_job_id = 0;
363	u32 pp_job_id = 0;
364	mali_bool abort_pp = MALI_FALSE;
365	mali_bool abort_gp = MALI_FALSE;
366
367	mali_group_lock(group);
368
369	gp_job = group->gp_running_job;
370	pp_job = group->pp_running_job;
371
372	if (gp_job && mali_gp_job_get_session(gp_job) == session)
373	{
374		MALI_DEBUG_PRINT(4, ("Aborting GP job 0x%08x from session 0x%08x\n", gp_job, session));
375
376		gp_job_id = mali_gp_job_get_id(gp_job);
377		abort_gp = MALI_TRUE;
378	}
379
380	if (pp_job && mali_pp_job_get_session(pp_job) == session)
381	{
382		MALI_DEBUG_PRINT(4, ("Mali group: Aborting PP job 0x%08x from session 0x%08x\n", pp_job, session));
383
384		pp_job_id = mali_pp_job_get_id(pp_job);
385		abort_pp = MALI_TRUE;
386	}
387
388	mali_group_unlock(group);
389
390	/* These functions takes and releases the group lock */
391	if (0 != abort_gp)
392	{
393		mali_group_abort_gp_job(group, gp_job_id);
394	}
395	if (0 != abort_pp)
396	{
397		mali_group_abort_pp_job(group, pp_job_id);
398	}
399
400	mali_group_lock(group);
401	mali_group_remove_session_if_unused(group, session);
402	mali_group_unlock(group);
403}
404
405enum mali_group_core_state mali_group_gp_state(struct mali_group *group)
406{
407	return group->gp_state;
408}
409
410enum mali_group_core_state mali_group_pp_state(struct mali_group *group)
411{
412	return group->pp_state;
413}
414
415/* group lock need to be taken before calling mali_group_bottom_half */
416void mali_group_bottom_half(struct mali_group *group, enum mali_group_event_t event)
417{
418	MALI_ASSERT_GROUP_LOCKED(group);
419
420	switch (event)
421	{
422		case GROUP_EVENT_PP_JOB_COMPLETED:
423			mali_group_complete_jobs(group, MALI_FALSE, MALI_TRUE, MALI_TRUE); /* PP job SUCCESS */
424			/* group lock is released by mali_group_complete_jobs() call above */
425			break;
426		case GROUP_EVENT_PP_JOB_FAILED:
427			mali_group_complete_jobs(group, MALI_FALSE, MALI_TRUE, MALI_FALSE); /* PP job FAIL */
428			/* group lock is released by mali_group_complete_jobs() call above */
429			break;
430		case GROUP_EVENT_PP_JOB_TIMED_OUT:
431			mali_group_complete_jobs(group, MALI_FALSE, MALI_TRUE, MALI_FALSE); /* PP job TIMEOUT */
432			/* group lock is released by mali_group_complete_jobs() call above */
433			break;
434		case GROUP_EVENT_GP_JOB_COMPLETED:
435			mali_group_complete_jobs(group, MALI_TRUE, MALI_FALSE, MALI_TRUE); /* GP job SUCCESS */
436			/* group lock is released by mali_group_complete_jobs() call above */
437			break;
438		case GROUP_EVENT_GP_JOB_FAILED:
439			mali_group_complete_jobs(group, MALI_TRUE, MALI_FALSE, MALI_FALSE); /* GP job FAIL */
440			/* group lock is released by mali_group_complete_jobs() call above */
441			break;
442		case GROUP_EVENT_GP_JOB_TIMED_OUT:
443			mali_group_complete_jobs(group, MALI_TRUE, MALI_FALSE, MALI_FALSE); /* GP job TIMEOUT */
444			/* group lock is released by mali_group_complete_jobs() call above */
445			break;
446		case GROUP_EVENT_GP_OOM:
447			group->gp_state = MALI_GROUP_CORE_STATE_OOM;
448			mali_group_unlock(group); /* Nothing to do on the HW side, so just release group lock right away */
449			mali_gp_scheduler_oom(group, group->gp_running_job);
450			break;
451		case GROUP_EVENT_MMU_PAGE_FAULT:
452			mali_group_complete_jobs(group, MALI_TRUE, MALI_TRUE, MALI_FALSE); /* GP and PP job FAIL */
453			/* group lock is released by mali_group_complete_jobs() call above */
454			break;
455		default:
456			break;
457	}
458}
459
460struct mali_mmu_core *mali_group_get_mmu(struct mali_group *group)
461{
462	return group->mmu;
463}
464
465struct mali_session_data *mali_group_get_session(struct mali_group *group)
466{
467	return group->session;
468}
469
470struct mali_group *mali_group_get_glob_group(u32 index)
471{
472	if(mali_global_num_groups > index)
473	{
474		return mali_global_groups[index];
475	}
476
477	return NULL;
478}
479
480u32 mali_group_get_glob_num_groups(void)
481{
482	return mali_global_num_groups;
483}
484
485/* Used to check if scheduler for the other core type needs to be called on job completion.
486 *
487 * Used only for Mali-200, where job start may fail if the only MMU is busy
488 * with another session's address space.
489 */
490static inline mali_bool mali_group_other_reschedule_needed(struct mali_group *group)
491{
492	MALI_ASSERT_GROUP_LOCKED(group);
493
494#if defined(USING_MALI200)
495	if (group->pagedir_activation_failed)
496	{
497		group->pagedir_activation_failed = MALI_FALSE;
498		return MALI_TRUE;
499	}
500	else
501#endif
502	{
503		return MALI_FALSE;
504	}
505}
506
507static enum mali_group_activate_pd_status mali_group_activate_page_directory(struct mali_group *group, struct mali_session_data *session)
508{
509	enum mali_group_activate_pd_status retval;
510	MALI_ASSERT_GROUP_LOCKED(group);
511
512	MALI_DEBUG_PRINT(5, ("Mali group: Activating page directory 0x%08X from session 0x%08X on group 0x%08X\n", mali_session_get_page_directory(session), session, group));
513	MALI_DEBUG_ASSERT(0 <= group->page_dir_ref_count);
514
515	if (0 != group->page_dir_ref_count)
516	{
517		if (group->session != session)
518		{
519			MALI_DEBUG_PRINT(4, ("Mali group: Activating session FAILED: 0x%08x on group 0x%08X. Existing session: 0x%08x\n", session, group, group->session));
520			return MALI_GROUP_ACTIVATE_PD_STATUS_FAILED;
521		}
522		else
523		{
524			MALI_DEBUG_PRINT(4, ("Mali group: Activating session already activated: 0x%08x on group 0x%08X. New Ref: %d\n", session, group, 1+group->page_dir_ref_count));
525			retval = MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD;
526
527		}
528	}
529	else
530	{
531		/* There might be another session here, but it is ok to overwrite it since group->page_dir_ref_count==0 */
532		if (group->session != session)
533		{
534			mali_bool activate_success;
535			MALI_DEBUG_PRINT(5, ("Mali group: Activate session: %08x previous: %08x on group 0x%08X. Ref: %d\n", session, group->session, group, 1+group->page_dir_ref_count));
536
537			activate_success = mali_mmu_activate_page_directory(group->mmu, mali_session_get_page_directory(session));
538			MALI_DEBUG_ASSERT(activate_success);
539			if ( MALI_FALSE== activate_success ) return MALI_FALSE;
540			group->session = session;
541			retval = MALI_GROUP_ACTIVATE_PD_STATUS_OK_SWITCHED_PD;
542		}
543		else
544		{
545			MALI_DEBUG_PRINT(4, ("Mali group: Activate existing session 0x%08X on group 0x%08X. Ref: %d\n", session->page_directory, group, 1+group->page_dir_ref_count));
546			retval = MALI_GROUP_ACTIVATE_PD_STATUS_OK_KEPT_PD;
547		}
548	}
549
550	group->page_dir_ref_count++;
551	return retval;
552}
553
554static void mali_group_deactivate_page_directory(struct mali_group *group, struct mali_session_data *session)
555{
556	MALI_ASSERT_GROUP_LOCKED(group);
557
558	MALI_DEBUG_ASSERT(0 < group->page_dir_ref_count);
559	MALI_DEBUG_ASSERT(session == group->session);
560
561	group->page_dir_ref_count--;
562
563	/* As an optimization, the MMU still points to the group->session even if (0 == group->page_dir_ref_count),
564	   and we do not call mali_mmu_activate_empty_page_directory(group->mmu); */
565	MALI_DEBUG_ASSERT(0 <= group->page_dir_ref_count);
566}
567
568void mali_group_remove_session_if_unused(struct mali_group *group, struct mali_session_data *session)
569{
570	MALI_ASSERT_GROUP_LOCKED(group);
571
572	if (0 == group->page_dir_ref_count)
573	{
574		MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->gp_state);
575		MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->pp_state);
576
577		if (group->session == session)
578		{
579			MALI_DEBUG_ASSERT(MALI_TRUE == group->power_is_on);
580			MALI_DEBUG_PRINT(3, ("Mali group: Deactivating unused session 0x%08X on group %08X\n", session, group));
581			mali_mmu_activate_empty_page_directory(group->mmu);
582			group->session = NULL;
583		}
584	}
585}
586
587void mali_group_power_on(void)
588{
589	int i;
590	for (i = 0; i < mali_global_num_groups; i++)
591	{
592		struct mali_group *group = mali_global_groups[i];
593		mali_group_lock(group);
594		MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->gp_state);
595		MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->pp_state);
596		MALI_DEBUG_ASSERT_POINTER(group->cluster);
597		group->power_is_on = MALI_TRUE;
598		mali_cluster_power_is_enabled_set(group->cluster, MALI_TRUE);
599		mali_group_unlock(group);
600	}
601	MALI_DEBUG_PRINT(3,("group: POWER ON\n"));
602}
603
604mali_bool mali_group_power_is_on(struct mali_group *group)
605{
606	MALI_ASSERT_GROUP_LOCKED(group);
607	return group->power_is_on;
608}
609
610void mali_group_power_off(void)
611{
612	int i;
613	/* It is necessary to set group->session = NULL; so that the powered off MMU is not written to on map /unmap */
614	/* It is necessary to set group->power_is_on=MALI_FALSE so that pending bottom_halves does not access powered off cores. */
615	for (i = 0; i < mali_global_num_groups; i++)
616	{
617		struct mali_group *group = mali_global_groups[i];
618		mali_group_lock(group);
619		MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->gp_state);
620		MALI_DEBUG_ASSERT(MALI_GROUP_CORE_STATE_IDLE == group->pp_state);
621		MALI_DEBUG_ASSERT_POINTER(group->cluster);
622		group->session = NULL;
623		MALI_DEBUG_ASSERT(MALI_TRUE == group->power_is_on);
624		group->power_is_on = MALI_FALSE;
625		mali_cluster_power_is_enabled_set(group->cluster, MALI_FALSE);
626		mali_group_unlock(group);
627	}
628	MALI_DEBUG_PRINT(3,("group: POWER OFF\n"));
629}
630
631
632static void mali_group_recovery_reset(struct mali_group *group)
633{
634	MALI_ASSERT_GROUP_LOCKED(group);
635
636	/* Stop cores, bus stop */
637	if (NULL != group->pp_core)
638	{
639		mali_pp_stop_bus(group->pp_core);
640	}
641	if (NULL != group->gp_core)
642	{
643		mali_gp_stop_bus(group->gp_core);
644	}
645
646	/* Flush MMU */
647	mali_mmu_activate_fault_flush_page_directory(group->mmu);
648	mali_mmu_page_fault_done(group->mmu);
649
650	/* Wait for cores to stop bus */
651	if (NULL != group->pp_core)
652	{
653		mali_pp_stop_bus_wait(group->pp_core);
654	}
655	if (NULL != group->gp_core)
656	{
657		mali_gp_stop_bus_wait(group->gp_core);
658	}
659
660	/* Reset cores */
661	if (NULL != group->pp_core)
662	{
663		mali_pp_hard_reset(group->pp_core);
664	}
665	if (NULL != group->gp_core)
666	{
667		mali_gp_hard_reset(group->gp_core);
668	}
669
670	/* Reset MMU */
671	mali_mmu_reset(group->mmu);
672	group->session = NULL;
673}
674
675/* Group lock need to be taken before calling mali_group_complete_jobs. Will release the lock here. */
676static void mali_group_complete_jobs(struct mali_group *group, mali_bool complete_gp, mali_bool complete_pp, bool success)
677{
678	mali_bool need_group_reset = MALI_FALSE;
679	mali_bool gp_success = success;
680	mali_bool pp_success = success;
681
682	MALI_ASSERT_GROUP_LOCKED(group);
683
684	if (complete_gp && !complete_pp)
685	{
686		MALI_DEBUG_ASSERT_POINTER(group->gp_core);
687		if (_MALI_OSK_ERR_OK == mali_gp_reset(group->gp_core))
688		{
689			struct mali_gp_job *gp_job_to_return = group->gp_running_job;
690			group->gp_state = MALI_GROUP_CORE_STATE_IDLE;
691			group->gp_running_job = NULL;
692
693			MALI_DEBUG_ASSERT_POINTER(gp_job_to_return);
694
695			mali_group_deactivate_page_directory(group, mali_gp_job_get_session(gp_job_to_return));
696
697			if(mali_group_other_reschedule_needed(group))
698			{
699				mali_group_unlock(group);
700				mali_pp_scheduler_do_schedule();
701			}
702			else
703			{
704				mali_group_unlock(group);
705			}
706
707			mali_gp_scheduler_job_done(group, gp_job_to_return, gp_success);
708			mali_pm_core_event(MALI_CORE_EVENT_GP_STOP); /* It is ok to do this after schedule, since START/STOP is simply ++ and -- anyways */
709
710			return;
711		}
712		else
713		{
714			need_group_reset = MALI_TRUE;
715			MALI_DEBUG_PRINT(3, ("Mali group: Failed to reset GP, need to reset entire group\n"));
716			pp_success = MALI_FALSE; /* This might kill PP as well, so this should fail */
717		}
718	}
719	if (complete_pp && !complete_gp)
720	{
721		MALI_DEBUG_ASSERT_POINTER(group->pp_core);
722		if (_MALI_OSK_ERR_OK == mali_pp_reset(group->pp_core))
723		{
724			struct mali_pp_job *pp_job_to_return = group->pp_running_job;
725			u32 pp_sub_job_to_return = group->pp_running_sub_job;
726			group->pp_state = MALI_GROUP_CORE_STATE_IDLE;
727			group->pp_running_job = NULL;
728
729			MALI_DEBUG_ASSERT_POINTER(pp_job_to_return);
730
731			mali_group_deactivate_page_directory(group, mali_pp_job_get_session(pp_job_to_return));
732
733			if(mali_group_other_reschedule_needed(group))
734			{
735				mali_group_unlock(group);
736				mali_gp_scheduler_do_schedule();
737			}
738			else
739			{
740				mali_group_unlock(group);
741			}
742
743			mali_pp_scheduler_job_done(group, pp_job_to_return, pp_sub_job_to_return, pp_success);
744			mali_pm_core_event(MALI_CORE_EVENT_PP_STOP); /* It is ok to do this after schedule, since START/STOP is simply ++ and -- anyways */
745
746			return;
747		}
748		else
749		{
750			need_group_reset = MALI_TRUE;
751			MALI_DEBUG_PRINT(3, ("Mali group: Failed to reset PP, need to reset entire group\n"));
752			gp_success = MALI_FALSE; /* This might kill GP as well, so this should fail */
753		}
754	}
755	else if (complete_gp && complete_pp)
756	{
757		need_group_reset = MALI_TRUE;
758	}
759
760	if (MALI_TRUE == need_group_reset)
761	{
762		struct mali_gp_job *gp_job_to_return = group->gp_running_job;
763		struct mali_pp_job *pp_job_to_return = group->pp_running_job;
764		u32 pp_sub_job_to_return = group->pp_running_sub_job;
765		mali_bool schedule_other = MALI_FALSE;
766
767		MALI_DEBUG_PRINT(3, ("Mali group: Resetting entire group\n"));
768
769		group->gp_state = MALI_GROUP_CORE_STATE_IDLE;
770		group->gp_running_job = NULL;
771		if (NULL != gp_job_to_return)
772		{
773			mali_group_deactivate_page_directory(group, mali_gp_job_get_session(gp_job_to_return));
774		}
775
776		group->pp_state = MALI_GROUP_CORE_STATE_IDLE;
777		group->pp_running_job = NULL;
778		if (NULL != pp_job_to_return)
779		{
780			mali_group_deactivate_page_directory(group, mali_pp_job_get_session(pp_job_to_return));
781		}
782
783		/* The reset has to be done after mali_group_deactivate_page_directory() */
784		mali_group_recovery_reset(group);
785
786		if (mali_group_other_reschedule_needed(group) && (NULL == gp_job_to_return || NULL == pp_job_to_return))
787		{
788			schedule_other = MALI_TRUE;
789		}
790
791		mali_group_unlock(group);
792
793		if (NULL != gp_job_to_return)
794		{
795			mali_gp_scheduler_job_done(group, gp_job_to_return, gp_success);
796			mali_pm_core_event(MALI_CORE_EVENT_GP_STOP); /* It is ok to do this after schedule, since START/STOP is simply ++ and -- anyways */
797		}
798		else if (schedule_other)
799		{
800			mali_pp_scheduler_do_schedule();
801		}
802
803		if (NULL != pp_job_to_return)
804		{
805			mali_pp_scheduler_job_done(group, pp_job_to_return, pp_sub_job_to_return, pp_success);
806			mali_pm_core_event(MALI_CORE_EVENT_PP_STOP); /* It is ok to do this after schedule, since START/STOP is simply ++ and -- anyways */
807		}
808		else if (schedule_other)
809		{
810			mali_gp_scheduler_do_schedule();
811		}
812
813		return;
814	}
815
816	mali_group_unlock(group);
817}
818
819#if MALI_STATE_TRACKING
820u32 mali_group_dump_state(struct mali_group *group, char *buf, u32 size)
821{
822	int n = 0;
823
824	n += _mali_osk_snprintf(buf + n, size - n, "Group: %p\n", group);
825	if (group->gp_core)
826	{
827		n += mali_gp_dump_state(group->gp_core, buf + n, size - n);
828		n += _mali_osk_snprintf(buf + n, size - n, "\tGP state: %d\n", group->gp_state);
829		n += _mali_osk_snprintf(buf + n, size - n, "\tGP job: %p\n", group->gp_running_job);
830	}
831	if (group->pp_core)
832	{
833		n += mali_pp_dump_state(group->pp_core, buf + n, size - n);
834		n += _mali_osk_snprintf(buf + n, size - n, "\tPP state: %d\n", group->pp_state);
835		n += _mali_osk_snprintf(buf + n, size - n, "\tPP job: %p, subjob %d \n",
836		                        group->pp_running_job, group->pp_running_sub_job);
837	}
838
839	return n;
840}
841#endif