_mali_osk_errcode_t _ump_ukk_allocate( _ump_uk_allocate_s *user_interaction )
{
	ump_session_data * session_data = NULL;
	ump_dd_mem *new_allocation = NULL;
	ump_session_memory_list_element * session_memory_element = NULL;
	int map_id;

	DEBUG_ASSERT_POINTER( user_interaction );
	DEBUG_ASSERT_POINTER( user_interaction->ctx );

	session_data = (ump_session_data *) user_interaction->ctx;

	session_memory_element = _mali_osk_calloc( 1, sizeof(ump_session_memory_list_element));
	if (NULL == session_memory_element)
	{
		DBG_MSG(1, ("Failed to allocate ump_session_memory_list_element in ump_ioctl_allocate()\n"));
		return _MALI_OSK_ERR_NOMEM;
	}


	new_allocation = _mali_osk_calloc( 1, sizeof(ump_dd_mem));
	if (NULL==new_allocation)
	{
		_mali_osk_free(session_memory_element);
		DBG_MSG(1, ("Failed to allocate ump_dd_mem in _ump_ukk_allocate()\n"));
		return _MALI_OSK_ERR_NOMEM;
	}

	/* Create a secure ID for this allocation */
	_mali_osk_lock_wait(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
	map_id = ump_descriptor_mapping_allocate_mapping(device.secure_id_map, (void*)new_allocation);

	if (map_id < 0)
	{
		_mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
		_mali_osk_free(session_memory_element);
		_mali_osk_free(new_allocation);
		DBG_MSG(1, ("Failed to allocate secure ID in ump_ioctl_allocate()\n"));
		return - _MALI_OSK_ERR_INVALID_FUNC;
	}

	/* Initialize the part of the new_allocation that we know so for */
	new_allocation->secure_id = (ump_secure_id)map_id;
	_mali_osk_atomic_init(&new_allocation->ref_count,1);
	if ( 0==(UMP_REF_DRV_UK_CONSTRAINT_USE_CACHE & user_interaction->constraints) )
		 new_allocation->is_cached = 0;
	else new_allocation->is_cached = 1;

	/* special case a size of 0, we should try to emulate what malloc does in this case, which is to return a valid pointer that must be freed, but can't be dereferences */
	if (0 == user_interaction->size)
	{
		user_interaction->size = 1; /* emulate by actually allocating the minimum block size */
	}

	new_allocation->size_bytes = UMP_SIZE_ALIGN(user_interaction->size); /* Page align the size */
	new_allocation->lock_usage = UMP_NOT_LOCKED;

	/* Now, ask the active memory backend to do the actual memory allocation */
	if (!device.backend->allocate( device.backend->ctx, new_allocation ) )
	{
		DBG_MSG(3, ("OOM: No more UMP memory left. Failed to allocate memory in ump_ioctl_allocate(). Size: %lu, requested size: %lu\n", new_allocation->size_bytes, (unsigned long)user_interaction->size));
		ump_descriptor_mapping_free(device.secure_id_map, map_id);
		_mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
		_mali_osk_free(new_allocation);
		_mali_osk_free(session_memory_element);
		return _MALI_OSK_ERR_INVALID_FUNC;
	}
	new_allocation->hw_device = _UMP_UK_USED_BY_CPU;
	new_allocation->ctx = device.backend->ctx;
	new_allocation->release_func = device.backend->release;

	_mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);

	/* Initialize the session_memory_element, and add it to the session object */
	session_memory_element->mem = new_allocation;
	_mali_osk_lock_wait(session_data->lock, _MALI_OSK_LOCKMODE_RW);
	_mali_osk_list_add(&(session_memory_element->list), &(session_data->list_head_session_memory_list));
	_mali_osk_lock_signal(session_data->lock, _MALI_OSK_LOCKMODE_RW);

	user_interaction->secure_id = new_allocation->secure_id;
	user_interaction->size = new_allocation->size_bytes;
	DBG_MSG(3, ("UMP memory allocated. ID: %u, size: %lu\n", new_allocation->secure_id, new_allocation->size_bytes));

	return _MALI_OSK_ERR_OK;
}
UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd_physical_block * blocks, unsigned long num_blocks)
{
	ump_dd_mem * mem;
	unsigned long size_total = 0;
	int map_id;
	u32 i;

	/* Go through the input blocks and verify that they are sane */
	for (i=0; i < num_blocks; i++)
	{
		unsigned long addr = blocks[i].addr;
		unsigned long size = blocks[i].size;

		DBG_MSG(5, ("Adding physical memory to new handle. Address: 0x%08lx, size: %lu\n", addr, size));
		size_total += blocks[i].size;

		if (0 != UMP_ADDR_ALIGN_OFFSET(addr))
		{
			MSG_ERR(("Trying to create UMP memory from unaligned physical address. Address: 0x%08lx\n", addr));
			return UMP_DD_HANDLE_INVALID;
		}

		if (0 != UMP_ADDR_ALIGN_OFFSET(size))
		{
			MSG_ERR(("Trying to create UMP memory with unaligned size. Size: %lu\n", size));
			return UMP_DD_HANDLE_INVALID;
		}
	}

	/* Allocate the ump_dd_mem struct for this allocation */
	mem = _mali_osk_malloc(sizeof(*mem));
	if (NULL == mem)
	{
		DBG_MSG(1, ("Could not allocate ump_dd_mem in ump_dd_handle_create_from_phys_blocks()\n"));
		return UMP_DD_HANDLE_INVALID;
	}

	/* Find a secure ID for this allocation */
	_mali_osk_lock_wait(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
	map_id = ump_descriptor_mapping_allocate_mapping(device.secure_id_map, (void*) mem);

	if (map_id < 0)
	{
		_mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
		_mali_osk_free(mem);
		DBG_MSG(1, ("Failed to allocate secure ID in ump_dd_handle_create_from_phys_blocks()\n"));
		return UMP_DD_HANDLE_INVALID;
	}

	/* Now, make a copy of the block information supplied by the user */
	mem->block_array = _mali_osk_malloc(sizeof(ump_dd_physical_block)* num_blocks);
	if (NULL == mem->block_array)
	{
		ump_descriptor_mapping_free(device.secure_id_map, map_id);
		_mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
		_mali_osk_free(mem);
		DBG_MSG(1, ("Could not allocate a mem handle for function ump_dd_handle_create_from_phys_blocks().\n"));
		return UMP_DD_HANDLE_INVALID;
	}

	_mali_osk_memcpy(mem->block_array, blocks, sizeof(ump_dd_physical_block) * num_blocks);

	/* And setup the rest of the ump_dd_mem struct */
	_mali_osk_atomic_init(&mem->ref_count, 1);
	mem->secure_id = (ump_secure_id)map_id;
	mem->size_bytes = size_total;
	mem->nr_blocks = num_blocks;
	mem->backend_info = NULL;
	mem->ctx = NULL;
	mem->release_func = phys_blocks_release;
	/* For now UMP handles created by ump_dd_handle_create_from_phys_blocks() is forced to be Uncached */
	mem->is_cached = 0;
	mem->hw_device = _UMP_UK_USED_BY_CPU;
	mem->lock_usage = UMP_NOT_LOCKED;

	_mali_osk_lock_signal(device.secure_id_map_lock, _MALI_OSK_LOCKMODE_RW);
	DBG_MSG(3, ("UMP memory created. ID: %u, size: %lu\n", mem->secure_id, mem->size_bytes));

	return (ump_dd_handle)mem;
}
MALI_STATIC_INLINE void mali_gp_scheduler_unlock(void)
{
	MALI_DEBUG_PRINT(5, ("Mali GP scheduler: Releasing GP scheduler lock\n"));
	_mali_osk_lock_signal(gp_scheduler_lock, _MALI_OSK_LOCKMODE_RW);
}
Exemple #4
0
mali_bool mali_clk_set_rate(unsigned int clk, unsigned int mhz)
{
	unsigned long rate = 0;
	mali_bool bis_vpll = MALI_TRUE;

#ifndef CONFIG_VPLL_USE_FOR_TVENC
	bis_vpll = MALI_TRUE;
#endif

	_mali_osk_lock_wait(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);

	if (mali_clk_get(bis_vpll) == MALI_FALSE)
		return MALI_FALSE;

	rate = (unsigned long)clk * (unsigned long)mhz;
	MALI_DEBUG_PRINT(3,("= clk_set_rate : %d , %d \n",clk, mhz ));

	if (bis_vpll)
	{
		clk_set_rate(fout_vpll_clock, (unsigned int)clk * GPU_MHZ);
		clk_set_parent(vpll_src_clock, ext_xtal_clock);
		clk_set_parent(sclk_vpll_clock, fout_vpll_clock);

		clk_set_parent(mali_parent_clock, sclk_vpll_clock);
		clk_set_parent(mali_clock, mali_parent_clock);
	}
	else
	{
		clk_set_parent(mali_parent_clock, mpll_clock);
		clk_set_parent(mali_clock, mali_parent_clock);
	}

	if (clk_enable(mali_clock) < 0)
		return MALI_FALSE;

#if MALI_TIMELINE_PROFILING_ENABLED
    _mali_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SINGLE |
                               MALI_PROFILING_EVENT_CHANNEL_SOFTWARE |
                               MALI_PROFILING_EVENT_REASON_SINGLE_SW_GPU_FREQ,
                               rate, 0, 0, 0, 0);
#endif

	clk_set_rate(mali_clock, rate);
	rate = clk_get_rate(mali_clock);

#if MALI_TIMELINE_PROFILING_ENABLED
    _mali_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SINGLE |
                               MALI_PROFILING_EVENT_CHANNEL_SOFTWARE |
                               MALI_PROFILING_EVENT_REASON_SINGLE_SW_GPU_FREQ,
                               rate, 1, 0, 0, 0);
#endif

	if (bis_vpll)
		mali_gpu_clk = (int)(rate / mhz);
	else
		mali_gpu_clk = (int)((rate + 500000) / mhz);

	GPU_MHZ = mhz;
	MALI_DEBUG_PRINT(3,("= clk_get_rate: %d \n",mali_gpu_clk));

	mali_clk_put(MALI_FALSE);

	_mali_osk_lock_signal(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);

	return MALI_TRUE;
}
mali_bool mali_clk_set_rate(unsigned int clk, unsigned int mhz)
{
	unsigned long rate = 0;
	mali_bool bis_vpll = MALI_TRUE;

#ifndef CONFIG_VPLL_USE_FOR_TVENC
	bis_vpll = MALI_TRUE;
#endif

#ifndef CONFIG_MALI_DVFS
	clk = mali_gpu_clk;
#endif

	_mali_osk_lock_wait(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);

	if (mali_clk_get(bis_vpll) == MALI_FALSE)
	{
		printk("~~~~~~~~ERROR: [%s] %d\n ",__func__,__LINE__);
		return MALI_FALSE;
	}

	rate = (unsigned long)clk * (unsigned long)mhz;
	MALI_DEBUG_PRINT(3,("= clk_set_rate : %d , %d \n",clk, mhz ));

	if (bis_vpll)
	{
		clk_set_rate(fout_vpll_clock, (unsigned int)clk * GPU_MHZ);
		//clk_set_parent(vpll_src_clock, ext_xtal_clock);
		clk_set_parent(sclk_vpll_clock, fout_vpll_clock);

		clk_set_parent(mali_parent_clock, sclk_vpll_clock);
		clk_set_parent(mali_clock, mali_parent_clock);
	}
	else
	{
		clk_set_parent(mali_parent_clock, mpll_clock);
		clk_set_parent(mali_clock, mali_parent_clock);
	}

	if (clk_enable(mali_clock) < 0)
	{
		printk("~~~~~~~~ERROR: [%s] %d\n ",__func__,__LINE__);
		return MALI_FALSE;
	}

	clk_set_rate(mali_clock, rate);
	rate = clk_get_rate(mali_clock);

	if (bis_vpll)
		mali_gpu_clk = (int)(rate / mhz);
	else
		mali_gpu_clk = (int)((rate + 500000) / mhz);

	GPU_MHZ = mhz;
	MALI_DEBUG_PRINT(3,("= clk_get_rate: %d \n",mali_gpu_clk));

	mali_clk_put(MALI_FALSE);

	_mali_osk_lock_signal(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);

	return MALI_TRUE;
}
void mali_group_unlock(struct mali_group *group)
{
	MALI_DEBUG_PRINT(5, ("Mali group: Releasing group lock 0x%08X\n", group));
	_mali_osk_lock_signal(group->lock, _MALI_OSK_LOCKMODE_RW);
}
void mali_clk_set_rate(unsigned int clk, unsigned int mhz)
{
	int err;
	unsigned long rate = (unsigned long)clk * (unsigned long)mhz;
	unsigned int read_val;

	_mali_osk_lock_wait(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);
	MALI_DEBUG_PRINT(3, ("Mali platform: Setting frequency to %d mhz\n", clk));

	if (mali_clk_get() == MALI_FALSE) {
		_mali_osk_lock_signal(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);
		return;
	}

	clk_set_parent(mali_parent_clock, mout_epll_clock);

	do {
		cpu_relax();
		read_val = __raw_readl(EXYNOS4_CLKMUX_STAT_G3D0);
	} while (((read_val >> 4) & 0x7) != 0x1);
	MALI_DEBUG_PRINT(3, ("Mali platform: set to EPLL EXYNOS4270_CLKMUX_STAT_G3D0 : 0x%08x\n", __raw_readl(EXYNOS4270_CLKMUX_STAT_G3D0)));

	err = clk_set_parent(sclk_vpll_clock, ext_xtal_clock);

	if (err)
		MALI_PRINT_ERROR(("sclk_vpll set parent to ext_xtal failed\n"));

	MALI_DEBUG_PRINT(3, ("Mali platform: set_parent_vpll : %8.x \n", (__raw_readl(EXYNOS4_CLKSRC_TOP0) >> 8) & 0x1));

	clk_set_rate(fout_vpll_clock, (unsigned int)clk * GPU_MHZ);
	clk_set_parent(vpll_src_clock, ext_xtal_clock);

	err = clk_set_parent(sclk_vpll_clock, fout_vpll_clock);

	if (err)
		MALI_PRINT_ERROR(("sclk_vpll set parent to fout_vpll failed\n"));

	MALI_DEBUG_PRINT(3, ("Mali platform: set_parent_vpll : %8.x \n", (__raw_readl(EXYNOS4_CLKSRC_TOP0) >> 8) & 0x1));

	clk_set_parent(mali_parent_clock, sclk_vpll_clock);

	do {
		cpu_relax();
		read_val = __raw_readl(EXYNOS4_CLKMUX_STAT_G3D0);
	} while (((read_val >> 4) & 0x7) != 0x2);

	MALI_DEBUG_PRINT(3, ("SET to VPLL EXYNOS4270_CLKMUX_STAT_G3D0 : 0x%08x\n", __raw_readl(EXYNOS4270_CLKMUX_STAT_G3D0)));

	clk_set_parent(mali_clock, mali_parent_clock);

	if (!atomic_read(&clk_active)) {
		if (clk_enable(mali_clock) < 0) {
			_mali_osk_lock_signal(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);
			return;
		}
		atomic_set(&clk_active, 1);
	}

	err = clk_set_rate(mali_clock, rate);

	if (err)
		MALI_PRINT_ERROR(("Failed to set Mali clock: %d\n", err));

	rate = clk_get_rate(mali_clock);

	MALI_DEBUG_PRINT(1, ("Mali frequency %d\n", rate / mhz));
	GPU_MHZ = mhz;

	mali_gpu_clk = clk;
	mali_clk_put(MALI_FALSE);

	_mali_osk_lock_signal(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);
}
void mali_regulator_set_voltage(int min_uV, int max_uV)
{
	int voltage;
#if !MALI_DVFS_ENABLED
	min_uV = mali_gpu_vol;
	max_uV = mali_gpu_vol;
#endif
#if MALI_VOLTAGE_LOCK
	if (mali_vol_lock_flag == MALI_FALSE) {
		if (min_uV < MALI_BOTTOMLOCK_VOL || max_uV < MALI_BOTTOMLOCK_VOL) {
			min_uV = MALI_BOTTOMLOCK_VOL;
			max_uV = MALI_BOTTOMLOCK_VOL;
		}
	} else if (_mali_osk_atomic_read(&voltage_lock_status) > 0 ) {
		if (min_uV < mali_lock_vol || max_uV < mali_lock_vol) {
#if MALI_DVFS_ENABLED
			int mali_vol_get;
			mali_vol_get = mali_vol_get_from_table(mali_lock_vol);
			if (mali_vol_get) {
				min_uV = mali_vol_get;
				max_uV = mali_vol_get;
			}
#else
			min_uV = mali_lock_vol;
			max_uV = mali_lock_vol;
#endif
		}
	}
#endif

	_mali_osk_lock_wait(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);

	if( IS_ERR_OR_NULL(g3d_regulator) )
	{
		MALI_DEBUG_PRINT(1, ("error on mali_regulator_set_voltage : g3d_regulator is null\n"));
		return;
	}

    MALI_DEBUG_PRINT(2, ("= regulator_set_voltage: %d, %d \n",min_uV, max_uV));

#if MALI_TIMELINE_PROFILING_ENABLED
    _mali_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SINGLE |
                               MALI_PROFILING_EVENT_CHANNEL_SOFTWARE |
                               MALI_PROFILING_EVENT_REASON_SINGLE_SW_GPU_VOLTS,
                               min_uV, max_uV, 1, 0, 0);
#endif

    regulator_set_voltage(g3d_regulator,min_uV,max_uV);
	voltage = regulator_get_voltage(g3d_regulator);

#if MALI_TIMELINE_PROFILING_ENABLED
    _mali_profiling_add_event( MALI_PROFILING_EVENT_TYPE_SINGLE |
                               MALI_PROFILING_EVENT_CHANNEL_SOFTWARE |
                               MALI_PROFILING_EVENT_REASON_SINGLE_SW_GPU_VOLTS,
                               voltage, 0, 2, 0, 0);
#endif

	mali_gpu_vol = voltage;
	MALI_DEBUG_PRINT(1, ("= regulator_get_voltage: %d \n",mali_gpu_vol));

	_mali_osk_lock_signal(mali_dvfs_lock, _MALI_OSK_LOCKMODE_RW);
}
Exemple #9
0
_mali_osk_errcode_t _mali_ukk_get_system_info( _mali_uk_get_system_info_s *args )
{
	_mali_core_info * current_core;
	_mali_mem_info * current_mem;
	_mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT;
	void * current_write_pos, ** current_patch_pos;
    u32 adjust_ptr_base;

	/* check input */
	MALI_DEBUG_ASSERT_POINTER(args);
    MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS);
    MALI_CHECK_NON_NULL(args->system_info, _MALI_OSK_ERR_INVALID_ARGS);

	/* lock the system info */
	_mali_osk_lock_wait( system_info_lock, _MALI_OSK_LOCKMODE_RW );

	/* first check size */
	if (args->size < system_info_size) goto exit_when_locked;

	/* we build a copy of system_info in the user space buffer specified by the user and
     * patch up the pointers. The ukk_private members of _mali_uk_get_system_info_s may
     * indicate a different base address for patching the pointers (normally the
     * address of the provided system_info buffer would be used). This is helpful when
     * the system_info buffer needs to get copied to user space and the pointers need
     * to be in user space.
     */
    if (0 == args->ukk_private)
    {
        adjust_ptr_base = (u32)args->system_info;
    }
    else
    {
        adjust_ptr_base = args->ukk_private;
    }

	/* copy each struct into the buffer, and update its pointers */
	current_write_pos = (void *)args->system_info;

	/* first, the master struct */
	_mali_osk_memcpy(current_write_pos, system_info, sizeof(_mali_system_info));

	/* advance write pointer */
	current_write_pos = (void *)((u32)current_write_pos + sizeof(_mali_system_info));

	/* first we write the core info structs, patch starts at master's core_info pointer */
	current_patch_pos = (void **)((u32)args->system_info + offsetof(_mali_system_info, core_info));

	for (current_core = system_info->core_info; NULL != current_core; current_core = current_core->next)
	{

		/* patch the pointer pointing to this core */
		*current_patch_pos = (void*)(adjust_ptr_base + ((u32)current_write_pos - (u32)args->system_info));

		/* copy the core info */
		_mali_osk_memcpy(current_write_pos, current_core, sizeof(_mali_core_info));

		/* update patch pos */
		current_patch_pos = (void **)((u32)current_write_pos + offsetof(_mali_core_info, next));

		/* advance write pos in memory */
		current_write_pos = (void *)((u32)current_write_pos + sizeof(_mali_core_info));
	}
	/* patching of last patch pos is not needed, since we wrote NULL there in the first place */

	/* then we write the mem info structs, patch starts at master's mem_info pointer */
	current_patch_pos = (void **)((u32)args->system_info + offsetof(_mali_system_info, mem_info));

	for (current_mem = system_info->mem_info; NULL != current_mem; current_mem = current_mem->next)
	{
		/* patch the pointer pointing to this core */
		*current_patch_pos = (void*)(adjust_ptr_base + ((u32)current_write_pos - (u32)args->system_info));

		/* copy the core info */
		_mali_osk_memcpy(current_write_pos, current_mem, sizeof(_mali_mem_info));

		/* update patch pos */
		current_patch_pos = (void **)((u32)current_write_pos + offsetof(_mali_mem_info, next));

		/* advance write pos in memory */
		current_write_pos = (void *)((u32)current_write_pos + sizeof(_mali_mem_info));
	}
	/* patching of last patch pos is not needed, since we wrote NULL there in the first place */

	err = _MALI_OSK_ERR_OK;
exit_when_locked:
	_mali_osk_lock_signal( system_info_lock, _MALI_OSK_LOCKMODE_RW );
    MALI_ERROR(err);
}
Exemple #10
0
static _mali_osk_errcode_t build_system_info(void)
{
	unsigned int i;
	int err = _MALI_OSK_ERR_FAULT;
	_mali_system_info * new_info, * cleanup;
	_mali_core_info * current_core;
	_mali_mem_info * current_mem;
	u32 new_size = 0;

	/* create a new system info struct */
	MALI_CHECK_NON_NULL(new_info = (_mali_system_info *)_mali_osk_malloc(sizeof(_mali_system_info)), _MALI_OSK_ERR_NOMEM);

	_mali_osk_memset(new_info, 0, sizeof(_mali_system_info));

	/* if an error happens during any of the system_info_fill calls cleanup the new info structs */
	cleanup = new_info;

	/* ask each subsystems to fill in their info */
	for (i = 0; i < SUBSYSTEMS_COUNT; ++i)
	{
		if (NULL != subsystems[i]->system_info_fill)
		{
			err = subsystems[i]->system_info_fill(new_info);
			if (_MALI_OSK_ERR_OK != err) goto error_exit;
		}
	}

	/* building succeeded, calculate the size */

	/* size needed of the system info struct itself */
	new_size = sizeof(_mali_system_info);

	/* size needed for the cores */
	for (current_core = new_info->core_info; NULL != current_core; current_core = current_core->next)
	{
		new_size += sizeof(_mali_core_info);
	}

	/* size needed for the memory banks */
	for (current_mem = new_info->mem_info; NULL != current_mem; current_mem = current_mem->next)
	{
		new_size += sizeof(_mali_mem_info);
	}

	/* lock system info access so a user wont't get a corrupted version */
	_mali_osk_lock_wait( system_info_lock, _MALI_OSK_LOCKMODE_RW );

	/* cleanup the old one */
	cleanup = system_info;
	/* set new info */
	system_info = new_info;
	system_info_size = new_size;

	/* we're safe */
	_mali_osk_lock_signal( system_info_lock, _MALI_OSK_LOCKMODE_RW );

	/* ok result */
	err = _MALI_OSK_ERR_OK;

	/* we share the cleanup routine with the error case */
error_exit:
	if (NULL == cleanup) MALI_ERROR((_mali_osk_errcode_t)err); /* no cleanup needed, return what err contains */

	/* cleanup */
	cleanup_system_info(cleanup);

	/* return whatever err is, we could end up here in both the error and success cases */
	MALI_ERROR((_mali_osk_errcode_t)err);
}
static mali_physical_memory_allocation_result block_allocator_allocate(void* ctx, mali_allocation_engine * engine, mali_memory_allocation * descriptor, u32* offset, mali_physical_memory_allocation * alloc_info)
{
    block_allocator * info;
    u32 left;
    block_info * last_allocated = NULL;
    mali_physical_memory_allocation_result result = MALI_MEM_ALLOC_NONE;
    block_allocator_allocation *ret_allocation;

    MALI_DEBUG_ASSERT_POINTER(ctx);
    MALI_DEBUG_ASSERT_POINTER(descriptor);
    MALI_DEBUG_ASSERT_POINTER(offset);
    MALI_DEBUG_ASSERT_POINTER(alloc_info);

    info = (block_allocator*)ctx;
    left = descriptor->size - *offset;
    MALI_DEBUG_ASSERT(0 != left);

    if (_MALI_OSK_ERR_OK != _mali_osk_lock_wait(info->mutex, _MALI_OSK_LOCKMODE_RW)) return MALI_MEM_ALLOC_INTERNAL_FAILURE;

    ret_allocation = _mali_osk_malloc( sizeof(block_allocator_allocation) );

    if ( NULL == ret_allocation )
    {
        /* Failure; try another allocator by returning MALI_MEM_ALLOC_NONE */
        _mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);
        return result;
    }

    ret_allocation->start_offset = *offset;
    ret_allocation->mapping_length = 0;

    while ((left > 0) && (info->first_free))
    {
        block_info * block;
        u32 phys_addr;
        u32 padding;
        u32 current_mapping_size;

        block = info->first_free;
        info->first_free = info->first_free->next;
        block->next = last_allocated;
        last_allocated = block;

        phys_addr = get_phys(info, block);

        padding = *offset & (MALI_BLOCK_SIZE-1);

        if (MALI_BLOCK_SIZE - padding < left)
        {
            current_mapping_size = MALI_BLOCK_SIZE - padding;
        }
        else
        {
            current_mapping_size = left;
        }

        if (_MALI_OSK_ERR_OK != mali_allocation_engine_map_physical(engine, descriptor, *offset, phys_addr + padding, info->cpu_usage_adjust, current_mapping_size))
        {
            MALI_DEBUG_PRINT(1, ("Mapping of physical memory  failed\n"));
            result = MALI_MEM_ALLOC_INTERNAL_FAILURE;
            mali_allocation_engine_unmap_physical(engine, descriptor, ret_allocation->start_offset, ret_allocation->mapping_length, (_mali_osk_mem_mapregion_flags_t)0);

            /* release all memory back to the pool */
            while (last_allocated)
            {
                /* This relinks every block we've just allocated back into the free-list */
                block = last_allocated->next;
                last_allocated->next = info->first_free;
                info->first_free = last_allocated;
                last_allocated = block;
            }

            break;
        }

        *offset += current_mapping_size;
        left -= current_mapping_size;
        ret_allocation->mapping_length += current_mapping_size;
    }

    _mali_osk_lock_signal(info->mutex, _MALI_OSK_LOCKMODE_RW);

    if (last_allocated)
    {
        if (left) result = MALI_MEM_ALLOC_PARTIAL;
        else result = MALI_MEM_ALLOC_FINISHED;

        /* Record all the information about this allocation */
        ret_allocation->last_allocated = last_allocated;
        ret_allocation->engine = engine;
        ret_allocation->descriptor = descriptor;

        alloc_info->ctx = info;
        alloc_info->handle = ret_allocation;
        alloc_info->release = block_allocator_release;
    }
    else
    {
        /* Free the allocation information - nothing to be passed back */
        _mali_osk_free( ret_allocation );
    }

    return result;
}
_mali_osk_errcode_t _mali_ukk_open(void **context)
{
	int i;
    _mali_osk_errcode_t err;
#ifdef MALI_SESSION_MEMORY_USAGE
	struct mali_session_data_list * session_data_list;
#endif
	struct mali_session_data * session_data;

	/* allocated struct to track this session */
	session_data = (struct mali_session_data *)_mali_osk_malloc(sizeof(struct mali_session_data));
    MALI_CHECK_NON_NULL(session_data, _MALI_OSK_ERR_NOMEM);

#ifdef MALI_SESSION_MEMORY_USAGE
	session_data_list = (struct mali_session_data_list *)_mali_osk_malloc(sizeof(struct mali_session_data_list));
	if (session_data_list == NULL)
	{
		_mali_osk_free(session_data);
		return _MALI_OSK_ERR_NOMEM;
	}

	_MALI_OSK_INIT_LIST_HEAD(&session_data_list->list_head);
	session_data_list->pid = _mali_osk_get_pid();
	session_data_list->session_data = session_data;
	session_data->list = session_data_list;
#endif

	_mali_osk_memset(session_data->subsystem_data, 0, sizeof(session_data->subsystem_data));

	/* create a response queue for this session */
	session_data->ioctl_queue = _mali_osk_notification_queue_init();
	if (NULL == session_data->ioctl_queue)
	{
		_mali_osk_free(session_data);
#ifdef MALI_SESSION_MEMORY_USAGE
		_mali_osk_free(session_data_list);
#endif
        MALI_ERROR(_MALI_OSK_ERR_NOMEM);
	}

	MALI_DEBUG_PRINT(3, ("Session starting\n"));

	/* call session_begin on all subsystems */
	for (i = 0; i < (int)SUBSYSTEMS_COUNT; ++i)
	{
		if (NULL != subsystems[i]->session_begin)
		{
			/* subsystem has a session_begin */
			err = subsystems[i]->session_begin(session_data, &session_data->subsystem_data[i], session_data->ioctl_queue);
            MALI_CHECK_GOTO(err == _MALI_OSK_ERR_OK, cleanup);
		}
	}

    *context = (void*)session_data;

#ifdef MALI_SESSION_MEMORY_USAGE
	_mali_osk_lock_wait( session_data_lock, _MALI_OSK_LOCKMODE_RW );
	_mali_osk_list_addtail(&session_data_list->list_head, &session_data_head);
	_mali_osk_lock_signal( session_data_lock, _MALI_OSK_LOCKMODE_RW );
#endif

	MALI_DEBUG_PRINT(3, ("Session started\n"));
	MALI_SUCCESS;

cleanup:
	MALI_DEBUG_PRINT(2, ("Session startup failed\n"));
	/* i is index of subsystem which failed session begin, all indices before that has to be ended */
	/* end subsystem sessions in the reverse order they where started in */
	for (i = i - 1; i >= 0; --i)
	{
		if (NULL != subsystems[i]->session_end) subsystems[i]->session_end(session_data, &session_data->subsystem_data[i]);
	}

	_mali_osk_notification_queue_term(session_data->ioctl_queue);
	_mali_osk_free(session_data);
#ifdef MALI_SESSION_MEMORY_USAGE
	_mali_osk_free(session_data_list);
#endif

	/* return what the subsystem which failed session start returned */
    MALI_ERROR(err);
}
void _mali_session_data_unlock(void)
{
	_mali_osk_lock_signal( session_data_lock, _MALI_OSK_LOCKMODE_RW );
}