/drivers/gpu/mali/mali/common/mali_group.c
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