static u32 subsystem_mali200_irq_handler_upper_half(mali_core_renderunit * core)
{
	u32 irq_readout;

	if (mali_benchmark) {
		return (core->current_job ? 1 : 0); /* simulate irq is pending when a job is pending */
	}

	MALI_DEBUG_PRINT(5, ("Mali PP: subsystem_mali200_irq_handler_upper_half: %s\n", core->description)) ;
	irq_readout = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_INT_STATUS);

	if ( MALI200_REG_VAL_IRQ_MASK_NONE != irq_readout )
	{
		/* Mask out all IRQs from this core until IRQ is handled */
		mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_NONE);
		return 1;
	}
	return 0;
}
static u32 subsystem_mali200_irq_handler_upper_half(mali_core_renderunit * core)
{
	u32 irq_readout;

	if (mali_benchmark) {
		return (core->current_job ? 1 : 0); /* simulate irq is pending when a job is pending */
	}

	irq_readout = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_INT_STATUS);

	if ( MALI200_REG_VAL_IRQ_MASK_NONE != irq_readout )
	{
		/* Mask out all IRQs from this core until IRQ is handled */
		mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_NONE);

#if MALI_TIMELINE_PROFILING_ENABLED
		_mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number)|MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT, irq_readout, 0, 0, 0, 0);
#endif

		return 1;
	}
	return 0;
}
static int subsystem_mali200_irq_handler_bottom_half(struct mali_core_renderunit* core)
{
	u32 irq_readout;
	u32 current_tile_addr;
	u32 core_status;
	mali_core_job * job;
	mali200_job * job200;

	job = core->current_job;
	job200 = GET_JOB200_PTR(job);


	if (mali_benchmark) {
		irq_readout = MALI200_REG_VAL_IRQ_END_OF_FRAME;
		current_tile_addr = 0;
		core_status = 0;
	} else {
		irq_readout = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT) & MALI200_REG_VAL_IRQ_MASK_USED;
		current_tile_addr = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_CURRENT_REND_LIST_ADDR);
		core_status = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_STATUS);
	}

	if (NULL == job)
	{
		MALI_DEBUG_ASSERT(CORE_IDLE==core->state);
		if ( 0 != irq_readout )
		{
			MALI_PRINT_ERROR(("Interrupt from a core not running a job. IRQ: 0x%04x Status: 0x%04x", irq_readout, core_status));
		}
		return JOB_STATUS_END_UNKNOWN_ERR;
	}
	MALI_DEBUG_ASSERT(CORE_IDLE!=core->state);

	job200->irq_status |= irq_readout;

	MALI_DEBUG_PRINT_IF( 3, ( 0 != irq_readout ),
	            ("Mali PP: Job: 0x%08x  IRQ RECEIVED  Rawstat: 0x%x Tile_addr: 0x%x Status: 0x%x\n",
	            (u32)job200->user_input.user_job_ptr, irq_readout ,current_tile_addr ,core_status));

	if ( MALI200_REG_VAL_IRQ_END_OF_FRAME & irq_readout)
	{
#if defined(USING_MALI200)
		mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_FLUSH_CACHES);
#endif

		if (0 != job200->user_input.perf_counter_flag )
		{
			if (job200->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE) )
			{
				job200->perf_counter0 = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE);
				job200->perf_counter1 = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE);
			}

#if defined(USING_MALI400_L2_CACHE)
			if (job200->user_input.perf_counter_flag & (_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE|_MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE) )
			{
				u32 src0;
				u32 val0;
				u32 src1;
				u32 val1;
				mali_kernel_l2_cache_get_perf_counters(&src0, &val0, &src1, &val1);

				if (job200->perf_counter_l2_src0 == src0)
				{
					job200->perf_counter_l2_val0_raw = val0;
					job200->perf_counter_l2_val0 = val0 - job200->perf_counter_l2_val0;
				}
				else
				{
					job200->perf_counter_l2_val0_raw = 0;
					job200->perf_counter_l2_val0 = 0;
				}

				if (job200->perf_counter_l2_src1 == src1)
				{
					job200->perf_counter_l2_val1_raw = val1;
					job200->perf_counter_l2_val1 = val1 - job200->perf_counter_l2_val1;
				}
				else
				{
					job200->perf_counter_l2_val1_raw = 0;
					job200->perf_counter_l2_val1 = 0;
				}
			}
#endif

		}

#if MALI_TIMELINE_PROFILING_ENABLED
		_mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number),
				job200->perf_counter0, job200->perf_counter1,
				job200->user_input.perf_counter_src0 | (job200->user_input.perf_counter_src1 << 8)
#if defined(USING_MALI400_L2_CACHE)
				| (job200->user_input.perf_counter_l2_src0 << 16) | (job200->user_input.perf_counter_l2_src1 << 24),
				job200->perf_counter_l2_val0_raw, job200->perf_counter_l2_val1_raw
#else
				, 0, 0
#endif
				);
#endif


#if MALI_STATE_TRACKING
		_mali_osk_atomic_inc(&job->session->jobs_ended);
#endif
		return JOB_STATUS_END_SUCCESS; /* reschedule */
	}
	/* Overall SW watchdog timeout or (time to do hang checking and progress detected)? */
	else if (
	         (CORE_WATCHDOG_TIMEOUT == core->state) ||
	         ((CORE_HANG_CHECK_TIMEOUT == core->state) && (current_tile_addr == job200->last_tile_list_addr))
	        )
	{
#if MALI_TIMELINE_PROFILING_ENABLED
		_mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status */
#endif
		/* no progress detected, killed by the watchdog */
		MALI_DEBUG_PRINT(2, ("M200: SW-Timeout Rawstat: 0x%x Tile_addr: 0x%x Status: 0x%x.\n", irq_readout ,current_tile_addr ,core_status) );
		/* In this case will the system outside cleanup and reset the core */

#if MALI_STATE_TRACKING
		_mali_osk_atomic_inc(&job->session->jobs_ended);
#endif

		return JOB_STATUS_END_HANG;
   	}
	/* HW watchdog triggered or an existing hang check passed? */
	else if	((CORE_HANG_CHECK_TIMEOUT == core->state) || (irq_readout & job200->active_mask & MALI200_REG_VAL_IRQ_HANG))
	{
		/* check interval in ms */
		u32 timeout = mali_core_hang_check_timeout_get();
		MALI_DEBUG_PRINT(3, ("M200: HW/SW Watchdog triggered, checking for progress in %d ms\n", timeout));
		job200->last_tile_list_addr = current_tile_addr;
		/* hw watchdog triggered, set up a progress checker every HANGCHECK ms */
		_mali_osk_timer_add(core->timer_hang_detection, _mali_osk_time_mstoticks(timeout));
		job200->active_mask &= ~MALI200_REG_VAL_IRQ_HANG; /* ignore the hw watchdoig from now on */
		mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, irq_readout & ~MALI200_REG_VAL_IRQ_HANG);
		mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, job200->active_mask);
		return JOB_STATUS_CONTINUE_RUN; /* not finished */
	}
	/* No irq pending, core still busy */
	else if ((0 == (irq_readout & MALI200_REG_VAL_IRQ_MASK_USED)) && ( 0 != (core_status & MALI200_REG_VAL_STATUS_RENDERING_ACTIVE)))
	{
		mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, irq_readout);
		mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, job200->active_mask);
		return JOB_STATUS_CONTINUE_RUN; /* Not finished */
	}
	else
	{
#if MALI_TIMELINE_PROFILING_ENABLED
		_mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number), 0, 0, 0, 0, 0); /* add GP and L2 counters and return status */
#endif

		MALI_DEBUG_PRINT(1, ("Mali PP: Job: 0x%08x  CRASH?  Rawstat: 0x%x Tile_addr: 0x%x Status: 0x%x\n",
				(u32)job200->user_input.user_job_ptr, irq_readout ,current_tile_addr ,core_status) ) ;

		if (irq_readout & MALI200_REG_VAL_IRQ_BUS_ERROR)
		{
			u32 bus_error = mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_BUS_ERROR_STATUS);

			MALI_DEBUG_PRINT(1, ("Bus error status: 0x%08X\n", bus_error));
			MALI_DEBUG_PRINT_IF(1, (bus_error & 0x01), ("Bus write error from id 0x%02x\n", (bus_error>>2) & 0x0F));
			MALI_DEBUG_PRINT_IF(1, (bus_error & 0x02), ("Bus read error from id 0x%02x\n", (bus_error>>6) & 0x0F));
			MALI_DEBUG_PRINT_IF(1, (0 == (bus_error & 0x03)), ("Bus error but neither read or write was set as the error reason\n"));
			(void)bus_error;
		}

#if MALI_STATE_TRACKING
		_mali_osk_atomic_inc(&job->session->jobs_ended);
#endif
		return JOB_STATUS_END_UNKNOWN_ERR; /* reschedule */
	}
static void mali200_raw_reset( mali_core_renderunit *core )
{
	int i;
	const int request_loop_count = 20;

	MALI_DEBUG_PRINT(4, ("Mali PP: mali200_raw_reset: %s\n", core->description));
	if (mali_benchmark) return;

	mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, 0); /* disable IRQs */

#if defined(USING_MALI200)

    mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_STOP_BUS);

	for (i = 0; i < request_loop_count; i++)
	{
		if (mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_STATUS) & MALI200_REG_VAL_STATUS_BUS_STOPPED) break;
		_mali_osk_time_ubusydelay(10);
	}

	MALI_DEBUG_PRINT_IF(1, request_loop_count == i, ("Mali PP: Bus was never stopped during core reset\n"));


	if (request_loop_count==i)
	{
#if USING_MMU
		if ((NULL!=core->mmu) && (MALI_FALSE == core->error_recovery))
		{
			/* Could not stop bus connections from core, probably because some of the already pending
			   bus request has had a page fault, and therefore can not complete before the MMU does PageFault
			   handling. This can be treated as a heavier reset function - which unfortunately reset all
			   the cores on this MMU in addition to the MMU itself */
			MALI_DEBUG_PRINT(1, ("Mali PP: Forcing Bus reset\n"));
			mali_kernel_mmu_force_bus_reset(core->mmu);
			return;
		}
#endif
		MALI_PRINT(("A MMU reset did not allow PP  to stop its bus, system failure, unable to recover\n"));
		return;
	}

	/* use the hard reset routine to do the actual reset */
	mali200_reset_hard(core);

#elif defined(USING_MALI400)

	mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI400PP_REG_VAL_IRQ_RESET_COMPLETED);
	mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI400PP_REG_VAL_CTRL_MGMT_SOFT_RESET);

	for (i = 0; i < request_loop_count; i++)
	{
		if (mali_core_renderunit_register_read(core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT) & MALI400PP_REG_VAL_IRQ_RESET_COMPLETED) break;
		_mali_osk_time_ubusydelay(10);
	}

	if (request_loop_count==i)
	{
#if USING_MMU
		if ((NULL!=core->mmu) && (MALI_FALSE == core->error_recovery))
		{
			/* Could not stop bus connections from core, probably because some of the already pending
			   bus request has had a page fault, and therefore can not complete before the MMU does PageFault
			   handling. This can be treated as a heavier reset function - which unfortunately reset all
			   the cores on this MMU in addition to the MMU itself */
			MALI_DEBUG_PRINT(1, ("Mali PP: Forcing Bus reset\n"));
			mali_kernel_mmu_force_bus_reset(core->mmu);
			return;
		}
#endif
		MALI_PRINT(("A MMU reset did not allow PP  to stop its bus, system failure, unable to recover\n"));
		return;
	}
	else
		mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_MASK_ALL);

#else
#error "no supported mali core defined"
#endif
}
static _mali_osk_errcode_t mali200_renderunit_create(_mali_osk_resource_t * resource)
{
	mali_core_renderunit *core;
	_mali_osk_errcode_t err;

	MALI_DEBUG_PRINT(3, ("Mali PP: mali200_renderunit_create\n") ) ;
	/* Checking that the resource settings are correct */
#if defined(USING_MALI200)
	if(MALI200 != resource->type)
	{
		MALI_PRINT_ERROR(("Can not register this resource as a " MALI_PP_SUBSYSTEM_NAME " core."));
		MALI_ERROR(_MALI_OSK_ERR_FAULT);
	}
#elif defined(USING_MALI400)
	if(MALI400PP != resource->type)
	{
		MALI_PRINT_ERROR(("Can not register this resource as a " MALI_PP_SUBSYSTEM_NAME " core."));
		MALI_ERROR(_MALI_OSK_ERR_FAULT);
	}
#endif
	if ( 0 != resource->size )
	{
		MALI_PRINT_ERROR(("Memory size set to " MALI_PP_SUBSYSTEM_NAME " core should be zero."));
		MALI_ERROR(_MALI_OSK_ERR_FAULT);
	}

	if ( NULL == resource->description )
	{
		MALI_PRINT_ERROR(("A " MALI_PP_SUBSYSTEM_NAME " core needs a unique description field"));
		MALI_ERROR(_MALI_OSK_ERR_FAULT);
	}

	/* Create a new core object */
	core = (mali_core_renderunit*) _mali_osk_malloc(sizeof(*core));
	if ( NULL == core )
	{
		MALI_ERROR(_MALI_OSK_ERR_NOMEM);
	}

	/* Variables set to be able to open and register the core */
	core->subsystem = &subsystem_mali200 ;
	core->registers_base_addr 	= resource->base ;
	core->size 					= MALI200_REG_SIZEOF_REGISTER_BANK ;
	core->irq_nr 				= resource->irq ;
	core->description 			= resource->description;
#if USING_MMU
	core->mmu_id                = resource->mmu_id;
	core->mmu                   = NULL;
#endif
#if USING_MALI_PMM
	/* Set up core's PMM id */
	switch( subsystem_mali200.number_of_cores )
	{
	case 0:
		core->pmm_id = MALI_PMM_CORE_PP0;
		break;
	case 1:
		core->pmm_id = MALI_PMM_CORE_PP1;
		break;
	case 2:
		core->pmm_id = MALI_PMM_CORE_PP2;
		break;
	case 3:
		core->pmm_id = MALI_PMM_CORE_PP3;
		break;
	default:
		MALI_DEBUG_PRINT(1, ("Unknown supported core for PMM\n"));
		err = _MALI_OSK_ERR_FAULT;
		goto exit_on_error0;
	}
#endif

	err = mali_core_renderunit_init( core );
    if (_MALI_OSK_ERR_OK != err)
    {
		MALI_DEBUG_PRINT(1, ("Failed to initialize renderunit\n"));
		goto exit_on_error0;
    }

	/* Map the new core object, setting: core->registers_mapped  */
	err = mali_core_renderunit_map_registers(core);
	if (_MALI_OSK_ERR_OK != err)
	{
		MALI_DEBUG_PRINT(1, ("Failed to map register\n"));
		goto exit_on_error1;
	}

	/* Check that the register mapping of the core works.
	Return 0 if Mali PP core is present and accessible. */
	if (mali_benchmark) {
#if defined(USING_MALI200)
		core->core_version = (((u32)MALI_PP_PRODUCT_ID) << 16) | 5 /* Fake Mali200-r0p5 */;
#elif defined(USING_MALI400)
		core->core_version = (((u32)MALI_PP_PRODUCT_ID) << 16) | 0x0101 /* Fake Mali400-r1p1 */;
#else
#error "No supported mali core defined"
#endif
	} else {
		core->core_version = mali_core_renderunit_register_read(
		                     core,
		                     MALI200_REG_ADDR_MGMT_VERSION);
	}

	err = mali200_core_version_legal(core);
	if (_MALI_OSK_ERR_OK != err)
	{
		MALI_DEBUG_PRINT(1, ("Invalid core\n"));
		goto exit_on_error2;
	}

	/* Reset the core. Put the core into a state where it can start to render. */
	mali200_reset(core);

	/* Registering IRQ, init the work_queue_irq_handle */
	/* Adding this core as an available renderunit in the subsystem. */
	err = mali_core_subsystem_register_renderunit(&subsystem_mali200, core);
	if (_MALI_OSK_ERR_OK != err)
	{
		MALI_DEBUG_PRINT(1, ("Failed to register with core\n"));
		goto exit_on_error2;
	}
	MALI_DEBUG_PRINT(6, ("Mali PP: mali200_renderunit_create\n") ) ;

	MALI_SUCCESS;

exit_on_error2:
	mali_core_renderunit_unmap_registers(core);
exit_on_error1:
    mali_core_renderunit_term(core);
exit_on_error0:
	_mali_osk_free( core ) ;
	MALI_PRINT_ERROR(("Renderunit NOT created."));
    MALI_ERROR(err);
}