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 */
	}
/* Start this job on this core. Return MALI_TRUE if the job was started. */
static _mali_osk_errcode_t subsystem_mali200_start_job(mali_core_job * job, mali_core_renderunit * core)
{
	mali200_job 	*job200;

	/* The local extended version of the general structs */
	job200  = _MALI_OSK_CONTAINER_OF(job, mali200_job, embedded_core_job);

	if ( (0 == job200->user_input.frame_registers[0]) ||
	     (0 == job200->user_input.frame_registers[1]) )
	{
		MALI_DEBUG_PRINT(4, ("Mali PP: Job: 0x%08x  WILL NOT START SINCE JOB HAS ILLEGAL ADDRESSES\n",
				(u32)job200->user_input.user_job_ptr));
        MALI_ERROR(_MALI_OSK_ERR_FAULT);
	}

	MALI_DEBUG_PRINT(4, ("Mali PP: Job: 0x%08x  START_RENDER  Tile_list: 0x%08x\n",
			(u32)job200->user_input.user_job_ptr,
			job200->user_input.frame_registers[0]));
	MALI_DEBUG_PRINT(6, ("Mali PP:      RSW base addr: 0x%08x  Vertex base addr: 0x%08x\n",
			job200->user_input.frame_registers[1], job200->user_input.frame_registers[2]));

	/* Frame registers. Copy from mem to physical registers */
	mali_core_renderunit_register_write_array(
			core,
			MALI200_REG_ADDR_FRAME,
			&(job200->user_input.frame_registers[0]),
			MALI200_NUM_REGS_FRAME);

	/* Write Back unit 0. Copy from mem to physical registers only if the WB unit will be used. */
	if (job200->user_input.wb0_registers[0])
	{
		mali_core_renderunit_register_write_array(
				core,
				MALI200_REG_ADDR_WB0,
				&(job200->user_input.wb0_registers[0]),
				MALI200_NUM_REGS_WBx);
	}

	/* Write Back unit 1. Copy from mem to physical registers only if the WB unit will be used. */
	if (job200->user_input.wb1_registers[0])
	{
		mali_core_renderunit_register_write_array(
				core,
				MALI200_REG_ADDR_WB1,
				&(job200->user_input.wb1_registers[0]),
				MALI200_NUM_REGS_WBx);
	}

	/* Write Back unit 2. Copy from mem to physical registers only if the WB unit will be used. */
	if (job200->user_input.wb2_registers[0])
	{
		mali_core_renderunit_register_write_array(
				core,
				MALI200_REG_ADDR_WB2,
				&(job200->user_input.wb2_registers[0]),
				MALI200_NUM_REGS_WBx);
	}


	/* This selects which performance counters we are reading */
	if ( 0 != job200->user_input.perf_counter_flag )
	{
		if ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE)
		{
			mali_core_renderunit_register_write_relaxed(
					core,
					MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE,
					MALI200_REG_VAL_PERF_CNT_ENABLE);
			mali_core_renderunit_register_write_relaxed(
					core,
					MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC,
					job200->user_input.perf_counter_src0);

		}

		if ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE)
		{
			mali_core_renderunit_register_write_relaxed(
					core,
					MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE,
					MALI200_REG_VAL_PERF_CNT_ENABLE);
			mali_core_renderunit_register_write_relaxed(
					core,
					MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC,
					job200->user_input.perf_counter_src1);

		}

#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) )
		{
			int force_reset = ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_RESET ) ? 1 : 0;
			u32 src0 = 0;
			u32 src1 = 0;

			if ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC0_ENABLE )
			{
				src0 = job200->user_input.perf_counter_l2_src0;
			}
			if ( job200->user_input.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_L2_SRC1_ENABLE )
			{
				src1 = job200->user_input.perf_counter_l2_src1;
			}

			mali_kernel_l2_cache_set_perf_counters(src0, src1, force_reset); /* will activate and possibly reset counters */

			/* Now, retrieve the current values, so we can substract them when the job has completed */
			mali_kernel_l2_cache_get_perf_counters(&job200->perf_counter_l2_src0,
			                                       &job200->perf_counter_l2_val0,
			                                       &job200->perf_counter_l2_src1,
			                                       &job200->perf_counter_l2_val1);
		}
#endif
	}

	subsystem_flush_mapped_mem_cache();

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

	/* This is the command that starts the Core */
	mali_core_renderunit_register_write(
			core,
			MALI200_REG_ADDR_MGMT_CTRL_MGMT,
			MALI200_REG_VAL_CTRL_MGMT_START_RENDERING);
	_mali_osk_write_mem_barrier();

#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_FLUSH, job200->user_input.frame_builder_id, job200->user_input.flush_id, 0, 0, 0); 
	_mali_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START|MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_number), job200->pid, job200->tid,
#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, job200->perf_counter_l2_val1
#else
				0, 0, 0
#endif
				);
#endif

    MALI_SUCCESS;
}
/* Sets the registers on mali200 according to the const default_mgmt_regs array. */
static void mali200_initialize_registers_mgmt(mali_core_renderunit *core )
{
	MALI_DEBUG_PRINT(6, ("Mali PP: mali200_initialize_registers_mgmt: %s\n", core->description)) ;
	mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED);
}
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 void subsystem_mali200_renderunit_stop_bus(struct mali_core_renderunit* core)
{
	mali_core_renderunit_register_write(core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_STOP_BUS);
}