/*
 * User Space library to access the Security hardware
 * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of the
 * License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 * USA
 */


/**
 * @file fsl_shw_keystore.c
 *
 * File which implements a default keystore policy, for use as the system
 * keystore.
 */
#include "fsl_platform.h"
#include "fsl_shw.h"
#include "fsl_shw_keystore.h"

#if defined(DIAG_DRV_IF)
#include <diagnostic.h>
#endif

/* Define a semaphore to protect the keystore data */
#ifdef __KERNEL__
#define LOCK_INCLUDES os_lock_context_t context
#define ACQUIRE_LOCK os_lock_save_context(keystore->lock, context)
#define RELEASE_LOCK os_unlock_restore_context(keystore->lock, context);
#else
#define LOCK_INCLUDES
#define ACQUIRE_LOCK
#define RELEASE_LOCK
#endif	/* __KERNEL__ */

/**
 * Calculates the byte offset into a word
 *  @param   bp  The byte (char*) pointer
 *  @return      The offset (0, 1, 2, or 3)
 */
#define SCC_BYTE_OFFSET(bp) ((uint32_t)(bp) % sizeof(uint32_t))

/**
 * Converts (by rounding down) a byte pointer into a word pointer
 *  @param  bp  The byte (char*) pointer
 *  @return     The word (uint32_t) as though it were an aligned (uint32_t*)
 */
#define SCC_WORD_PTR(bp) (((uint32_t)(bp)) & ~(sizeof(uint32_t)-1))

/* Depending on the architecture, these functions should be defined
 * differently.  On Platforms with SCC2, the functions use the secure
 * partition interface and should be available in both user and kernel space.
 * On platforms with SCC, they use the SCC keystore interface.  This is only
 * available in kernel mode, so they should be stubbed out in user mode.
 */
#if defined(FSL_HAVE_SCC2) || (defined(FSL_HAVE_SCC) && defined(__KERNEL__))
void fsl_shw_init_keystore(
			    fsl_shw_kso_t *keystore,
			    fsl_shw_return_t(*data_init) (fsl_shw_uco_t *user_ctx,
							   void **user_data),
			    void (*data_cleanup) (fsl_shw_uco_t *user_ctx,
						   void **user_data),
			    fsl_shw_return_t(*slot_alloc) (void *user_data,
							    uint32_t size,
							    uint64_t owner_id,
							    uint32_t *slot),
			    fsl_shw_return_t(*slot_dealloc) (void *user_data,
							      uint64_t
							      owner_id,
							      uint32_t slot),
			    fsl_shw_return_t(*slot_verify_access) (void
								    *user_data,
								    uint64_t
								    owner_id,
								    uint32_t
								    slot),
			    void *(*slot_get_address) (void *user_data,
							uint32_t handle),
			    uint32_t(*slot_get_base) (void *user_data,
						       uint32_t handle),
			    uint32_t(*slot_get_offset) (void *user_data,
							 uint32_t handle),
			    uint32_t(*slot_get_slot_size) (void *user_data,
							    uint32_t handle))
{
	keystore->data_init = data_init;
	keystore->data_cleanup = data_cleanup;
	keystore->slot_alloc = slot_alloc;
	keystore->slot_dealloc = slot_dealloc;
	keystore->slot_verify_access = slot_verify_access;
	keystore->slot_get_address = slot_get_address;
	keystore->slot_get_base = slot_get_base;
	keystore->slot_get_offset = slot_get_offset;
	keystore->slot_get_slot_size = slot_get_slot_size;
}
void fsl_shw_init_keystore_default(fsl_shw_kso_t *keystore)
{
	keystore->data_init = shw_kso_init_data;
	keystore->data_cleanup = shw_kso_cleanup_data;
	keystore->slot_alloc = shw_slot_alloc;
	keystore->slot_dealloc = shw_slot_dealloc;
	keystore->slot_verify_access = shw_slot_verify_access;
	keystore->slot_get_address = shw_slot_get_address;
	keystore->slot_get_base = shw_slot_get_base;
	keystore->slot_get_offset = shw_slot_get_offset;
	keystore->slot_get_slot_size = shw_slot_get_slot_size;
}

/**
 * Do any keystore specific initializations
 */
fsl_shw_return_t fsl_shw_establish_keystore(fsl_shw_uco_t *user_ctx,
						fsl_shw_kso_t *keystore)
{
	if (keystore->data_init == NULL) {
		return FSL_RETURN_ERROR_S;
	}

    /* Call the data_init function for any user setup */
    return keystore->data_init(user_ctx, &(keystore->user_data));
}
void fsl_shw_release_keystore(fsl_shw_uco_t *user_ctx,
				 fsl_shw_kso_t *keystore)
{

    /* Call the data_cleanup function for any keystore cleanup.
	  * NOTE: The keystore doesn't have any way of telling which keys are using
	  * it, so it is up to the user program to manage their key objects
	  * correctly.
	  */
	 if ((keystore != NULL) && (keystore->data_cleanup != NULL)) {
		keystore->data_cleanup(user_ctx, &(keystore->user_data));
	}
	return;
}

fsl_shw_return_t keystore_slot_alloc(fsl_shw_kso_t *keystore, uint32_t size,
				       uint64_t owner_id, uint32_t *slot)
{
	LOCK_INCLUDES;
	fsl_shw_return_t retval = FSL_RETURN_ERROR_S;

#ifdef DIAG_DRV_IF
	    LOG_DIAG("In keystore_slot_alloc.");

#endif
	ACQUIRE_LOCK;
	if ((keystore->slot_alloc == NULL) || (keystore->user_data == NULL)) {
		goto out;
	}

#ifdef DIAG_DRV_IF
	    LOG_DIAG_ARGS("key length: %i, handle: %i\n", size, *slot);

#endif
retval = keystore->slot_alloc(keystore->user_data, size, owner_id, slot);
out:RELEASE_LOCK;
	return retval;
}

fsl_shw_return_t keystore_slot_dealloc(fsl_shw_kso_t *keystore,
					 uint64_t owner_id, uint32_t slot)
{
	LOCK_INCLUDES;
	fsl_shw_return_t retval = FSL_RETURN_ERROR_S;
	ACQUIRE_LOCK;
	if ((keystore->slot_alloc == NULL) || (keystore->user_data == NULL)) {
		goto out;
	}
	retval =
	    keystore->slot_dealloc(keystore->user_data, owner_id, slot);
out:RELEASE_LOCK;
	return retval;
}

fsl_shw_return_t
keystore_load_slot(fsl_shw_kso_t * keystore, uint64_t owner_id, uint32_t slot,
		   const uint8_t * key_data, uint32_t key_length)
{

#ifdef FSL_HAVE_SCC2
	    LOCK_INCLUDES;
	fsl_shw_return_t retval = FSL_RETURN_ERROR_S;
	uint32_t slot_size;
	uint32_t i;
	uint8_t * slot_location;
	ACQUIRE_LOCK;
	if ((keystore->slot_verify_access == NULL) ||
	      (keystore->user_data == NULL))
		goto out;
	if (keystore->
	      slot_verify_access(keystore->user_data, owner_id,
				 slot) !=FSL_RETURN_OK_S) {
		retval = FSL_RETURN_AUTH_FAILED_S;
		goto out;
	}
	slot_size = keystore->slot_get_slot_size(keystore->user_data, slot);
	if (key_length > slot_size) {
		retval = FSL_RETURN_BAD_DATA_LENGTH_S;
		goto out;
	}
	slot_location = keystore->slot_get_address(keystore->user_data, slot);
	for (i = 0; i < key_length; i++) {
		slot_location[i] = key_data[i];
	}
	retval = FSL_RETURN_OK_S;
out:RELEASE_LOCK;
	return retval;

#else	/* FSL_HAVE_SCC2 */
	fsl_shw_return_t retval;
	scc_return_t scc_ret;
	scc_ret =
	    scc_load_slot(owner_id, slot, (uint8_t *) key_data, key_length);
	switch (scc_ret) {
	case SCC_RET_OK:
		retval = FSL_RETURN_OK_S;
		break;
	case SCC_RET_VERIFICATION_FAILED:
		retval = FSL_RETURN_AUTH_FAILED_S;
		break;
	case SCC_RET_INSUFFICIENT_SPACE:
		retval = FSL_RETURN_BAD_DATA_LENGTH_S;
		break;
	default:
		retval = FSL_RETURN_ERROR_S;
	}
	return retval;

#endif	/* FSL_HAVE_SCC2 */
}

fsl_shw_return_t
keystore_slot_encrypt(fsl_shw_uco_t *user_ctx, fsl_shw_kso_t *keystore,
		      uint64_t owner_id, uint32_t slot, uint32_t length,
		      uint8_t *destination)
{

#ifdef FSL_HAVE_SCC2
	LOCK_INCLUDES;
	fsl_shw_return_t retval = FSL_RETURN_ERROR_S;
	uint32_t slot_length;
	uint32_t IV[4];
	uint32_t * iv_ptr = (uint32_t *) & (owner_id);

	/* Build the IV */
	IV[0] = iv_ptr[0];
	IV[1] = iv_ptr[1];
	IV[2] = 0;
	IV[3] = 0;
	ACQUIRE_LOCK;

	/* Ensure that the data will fit in the key slot */
	slot_length =
	    keystore->slot_get_slot_size(keystore->user_data, slot);
	if (length > slot_length) {
		goto out;
	}

	  /* Call scc encrypt function to encrypt the data. */
	    retval = do_scc_encrypt_region(user_ctx,
					   (void *)keystore->
					   slot_get_base(keystore->user_data,
							 slot),
					   keystore->slot_get_offset(keystore->
								      user_data,
								      slot),
					   length, destination, IV,
					   FSL_SHW_CYPHER_MODE_CBC);
	goto out;
out:RELEASE_LOCK;
	return retval;

#else
	scc_return_t retval;
	retval = scc_encrypt_slot(owner_id, slot, length, destination);
	if (retval == SCC_RET_OK)
		return FSL_RETURN_OK_S;
	return FSL_RETURN_ERROR_S;

#endif	/* FSL_HAVE_SCC2 */
}

fsl_shw_return_t
keystore_slot_decrypt(fsl_shw_uco_t *user_ctx, fsl_shw_kso_t *keystore,
		      uint64_t owner_id, uint32_t slot, uint32_t length,
		      const uint8_t *source)
{

#ifdef FSL_HAVE_SCC2
	LOCK_INCLUDES;
	fsl_shw_return_t retval = FSL_RETURN_ERROR_S;
	uint32_t slot_length;
	uint32_t IV[4];
	uint32_t *iv_ptr = (uint32_t *) & (owner_id);

    /* Build the IV */
    IV[0] = iv_ptr[0];
	IV[1] = iv_ptr[1];
	IV[2] = 0;
	IV[3] = 0;
	ACQUIRE_LOCK;

	/* Call scc decrypt function to decrypt the data. */

	/* Ensure that the data will fit in the key slot */
	    slot_length =
	    keystore->slot_get_slot_size(keystore->user_data, slot);
	if (length > slot_length)
		goto out;

	/* Call scc decrypt function to encrypt the data. */
	    retval = do_scc_decrypt_region(user_ctx,
					   (void *)keystore->
					   slot_get_base(keystore->user_data,
							 slot),
					   keystore->slot_get_offset(keystore->
								      user_data,
								      slot),
					   length, source, IV,
					   FSL_SHW_CYPHER_MODE_CBC);
	goto out;
out:RELEASE_LOCK;
	return retval;

#else
	scc_return_t retval;
	retval = scc_decrypt_slot(owner_id, slot, length, source);
	if (retval == SCC_RET_OK)
		return FSL_RETURN_OK_S;
	return FSL_RETURN_ERROR_S;

#endif	/* FSL_HAVE_SCC2 */
}

#else	/* SCC in userspace */
void fsl_shw_init_keystore(
			    fsl_shw_kso_t *keystore,
			    fsl_shw_return_t(*data_init) (fsl_shw_uco_t *user_ctx,
							   void **user_data),
			    void (*data_cleanup) (fsl_shw_uco_t *user_ctx,
						   void **user_data),
			    fsl_shw_return_t(*slot_alloc) (void *user_data,
							    uint32_t size,
							    uint64_t owner_id,
							    uint32_t *slot),
			    fsl_shw_return_t(*slot_dealloc) (void *user_data,
							      uint64_t
							      owner_id,
							      uint32_t slot),
			    fsl_shw_return_t(*slot_verify_access) (void
								    *user_data,
								    uint64_t
								    owner_id,
								    uint32_t
								    slot),
			    void *(*slot_get_address) (void *user_data,
							uint32_t handle),
			    uint32_t(*slot_get_base) (void *user_data,
						       uint32_t handle),
			    uint32_t(*slot_get_offset) (void *user_data,
							 uint32_t handle),
			    uint32_t(*slot_get_slot_size) (void *user_data,
							    uint32_t handle))
{
	(void)keystore;
	(void)data_init;
	(void)data_cleanup;
	(void)slot_alloc;
	(void)slot_dealloc;
	(void)slot_verify_access;
	(void)slot_get_address;
	(void)slot_get_base;
	(void)slot_get_offset;
	(void)slot_get_slot_size;
}

void fsl_shw_init_keystore_default(fsl_shw_kso_t * keystore)
{
	(void)keystore;
}
fsl_shw_return_t fsl_shw_establish_keystore(fsl_shw_uco_t *user_ctx,
						 fsl_shw_kso_t *keystore)
{
	(void)user_ctx;
	(void)keystore;
	return FSL_RETURN_NO_RESOURCE_S;
}
void fsl_shw_release_keystore(fsl_shw_uco_t *user_ctx,
				fsl_shw_kso_t *keystore)
{
	(void)user_ctx;
	(void)keystore;
	return;
}

fsl_shw_return_t keystore_slot_alloc(fsl_shw_kso_t *keystore, uint32_t size,
					uint64_t owner_id, uint32_t *slot)
{
	(void)keystore;
	(void)size;
	(void)owner_id;
	(void)slot;
	return FSL_RETURN_NO_RESOURCE_S;
}

fsl_shw_return_t keystore_slot_dealloc(fsl_shw_kso_t *keystore,
					 uint64_t owner_id, uint32_t slot)
{
	(void)keystore;
	(void)owner_id;
	(void)slot;
	return FSL_RETURN_NO_RESOURCE_S;
}

fsl_shw_return_t
keystore_load_slot(fsl_shw_kso_t *keystore, uint64_t owner_id, uint32_t slot,
		   const uint8_t *key_data, uint32_t key_length)
{
	(void)keystore;
	(void)owner_id;
	(void)slot;
	(void)key_data;
	(void)key_length;
	return FSL_RETURN_NO_RESOURCE_S;
}

fsl_shw_return_t
keystore_slot_decrypt(fsl_shw_uco_t *user_ctx, fsl_shw_kso_t *keystore,
		      uint64_t owner_id, uint32_t slot, uint32_t length,
		      const uint8_t *source)
{
	(void)user_ctx;
	(void)keystore;
	(void)owner_id;
	(void)slot;
	(void)length;
	(void)source;
	return FSL_RETURN_NO_RESOURCE_S;
}

fsl_shw_return_t
keystore_slot_encrypt(fsl_shw_uco_t *user_ctx, fsl_shw_kso_t *keystore,
		      uint64_t owner_id, uint32_t slot, uint32_t length,
		      uint8_t *destination)
{
	(void)user_ctx;
	(void)keystore;
	(void)owner_id;
	(void)slot;
	(void)length;
	(void)destination;
	return FSL_RETURN_NO_RESOURCE_S;
}


#endif	/* FSL_HAVE_SCC2 */

/***** Default keystore implementation **************************************/

#ifdef FSL_HAVE_SCC2
    fsl_shw_return_t shw_kso_init_data(fsl_shw_uco_t *user_ctx,
					void **user_data)
{
	int retval = FSL_RETURN_ERROR_S;
	keystore_data_t *keystore_data = NULL;
	fsl_shw_pco_t *capabilities = fsl_shw_get_capabilities(user_ctx);
	uint32_t partition_size;
	uint32_t slot_count;
	uint32_t keystore_data_size;
	uint8_t UMID[16] = {
	0x42, 0, 0, 0, 0x43, 0, 0, 0, 0x19, 0, 0, 0, 0x59, 0, 0, 0};
	uint32_t permissions =
	    FSL_PERM_TH_R | FSL_PERM_TH_W | FSL_PERM_HD_R | FSL_PERM_HD_W |
	    FSL_PERM_HD_X;

	/* Look up the size of a partition to see how big to make the keystore */
	partition_size = fsl_shw_pco_get_spo_size_bytes(capabilities);

	/* Calculate the required size of the keystore data structure, based on the
	  * number of keys that can fit in the partition.
	  */
	slot_count = partition_size / KEYSTORE_SLOT_SIZE;
	keystore_data_size =
	    sizeof(keystore_data_t) +
	    slot_count * sizeof(keystore_data_slot_info_t);

#ifdef __KERNEL__
	keystore_data = os_alloc_memory(keystore_data_size, GFP_KERNEL);

#else
	keystore_data = malloc(keystore_data_size);

#endif
	if (keystore_data == NULL) {
		retval = FSL_RETURN_NO_RESOURCE_S;
		goto out;
	}

    /* Clear the memory (effectively clear all key assignments) */
    memset(keystore_data, 0, keystore_data_size);

   /* Place the slot information structure directly after the keystore data
   	* structure.
	*/
	    keystore_data->slot =
	    (keystore_data_slot_info_t *) (keystore_data + 1);
	keystore_data->slot_count = slot_count;

	/* Retrieve a secure partition to put the keystore in. */
	keystore_data->base_address =
	    fsl_shw_smalloc(user_ctx, partition_size, UMID, permissions);
	if (keystore_data->base_address == NULL) {
		retval = FSL_RETURN_NO_RESOURCE_S;
		goto out;
	}
	*user_data = keystore_data;
	retval = FSL_RETURN_OK_S;
out:if (retval != FSL_RETURN_OK_S) {
		if (keystore_data != NULL) {
			if (keystore_data->base_address != NULL)
				fsl_shw_sfree(NULL,
					       keystore_data->base_address);

#ifdef __KERNEL__
			    os_free_memory(keystore_data);

#else
			    free(keystore_data);

#endif
		}
	}
	return retval;
}
void shw_kso_cleanup_data(fsl_shw_uco_t *user_ctx, void **user_data)
{
	if (user_data != NULL) {
		keystore_data_t * keystore_data =
		    (keystore_data_t *) (*user_data);
		fsl_shw_sfree(user_ctx, keystore_data->base_address);

#ifdef __KERNEL__
		    os_free_memory(*user_data);

#else
		    free(*user_data);

#endif
	}
	return;
}

fsl_shw_return_t shw_slot_verify_access(void *user_data, uint64_t owner_id,
					  uint32_t slot)
{
	keystore_data_t * data = user_data;
	if (data->slot[slot].owner == owner_id) {
		return FSL_RETURN_OK_S;
	} else {

#ifdef DIAG_DRV_IF
		    LOG_DIAG_ARGS("Access to slot %i fails.\n", slot);

#endif
		    return FSL_RETURN_AUTH_FAILED_S;
	}
}

fsl_shw_return_t shw_slot_alloc(void *user_data, uint32_t size,
				   uint64_t owner_id, uint32_t *slot)
{
	keystore_data_t *data = user_data;
	uint32_t i;
	if (size > KEYSTORE_SLOT_SIZE)
		return FSL_RETURN_BAD_KEY_LENGTH_S;
	for (i = 0; i < data->slot_count; i++) {
		if (data->slot[i].allocated == 0) {
			data->slot[i].allocated = 1;
			data->slot[i].owner = owner_id;
			(*slot) = i;

#ifdef DIAG_DRV_IF
			    LOG_DIAG_ARGS("Keystore: allocated slot %i. Slot "
					  "address: %p\n",
					  (*slot),
					  data->base_address +
					  (*slot) * KEYSTORE_SLOT_SIZE);

#endif
			    return FSL_RETURN_OK_S;
		}
	}
	return FSL_RETURN_NO_RESOURCE_S;
}

fsl_shw_return_t shw_slot_dealloc(void *user_data, uint64_t owner_id,
				    uint32_t slot)
{
	keystore_data_t * data = user_data;
	(void)owner_id;
	(void)slot;
	if (slot >= data->slot_count)
		return FSL_RETURN_ERROR_S;
	if (data->slot[slot].allocated == 1) {
		data->slot[slot].allocated = 0;
		return FSL_RETURN_OK_S;
	}
	return FSL_RETURN_ERROR_S;
}

void *shw_slot_get_address(void *user_data, uint32_t slot)
{
	keystore_data_t * data = user_data;
	if (slot >= data->slot_count)
		return NULL;
	return data->base_address + slot * KEYSTORE_SLOT_SIZE;
}

uint32_t shw_slot_get_base(void *user_data, uint32_t slot)
{
	keystore_data_t * data = user_data;

	/* There could potentially be more than one secure partition object
	  * associated with this keystore.  For now, there is just one.
	  */
	(void)slot;
	return (uint32_t) (data->base_address);
}

uint32_t shw_slot_get_offset(void *user_data, uint32_t slot)
{
	keystore_data_t *data = user_data;
	if (slot >= data->slot_count)
		return FSL_RETURN_ERROR_S;
	return (slot * KEYSTORE_SLOT_SIZE);
}

uint32_t shw_slot_get_slot_size(void *user_data, uint32_t slot)
{
	(void)user_data;
	(void)slot;

	/* All slots are the same size in the default implementation */
	return KEYSTORE_SLOT_SIZE;
}

#else	/* FSL_HAVE_SCC2 */

#ifdef __KERNEL__
    fsl_shw_return_t shw_kso_init_data(fsl_shw_uco_t *user_ctx,
					void **user_data)
{

   /* The SCC does its own initialization.  All that needs to be done here is
   	* make sure an SCC exists.
	*/
	*user_data = (void *)0xFEEDFEED;
	return FSL_RETURN_OK_S;
}
void shw_kso_cleanup_data(fsl_shw_uco_t *user_ctx, void **user_data)
{

    /* The SCC does its own cleanup. */
	*user_data = NULL;
	return;
}

fsl_shw_return_t shw_slot_verify_access(void *user_data, uint64_t owner_id,
					  uint32_t slot)
{

	/* Zero is used for the size because the newer interface does bounds
	  * checking later.
	  */
	scc_return_t retval;
	retval = scc_verify_slot_access(owner_id, slot, 0);
	if (retval == SCC_RET_OK) {
		return FSL_RETURN_OK_S;
	}
	return FSL_RETURN_AUTH_FAILED_S;
}

fsl_shw_return_t shw_slot_alloc(void *user_data, uint32_t size,
				   uint64_t owner_id, uint32_t *slot)
{
	scc_return_t retval;

#ifdef DIAG_DRV_IF
	    LOG_DIAG_ARGS("key length: %i, handle: %i\n", size, *slot);

#endif
	retval = scc_alloc_slot(size, owner_id, slot);
	if (retval == SCC_RET_OK)
		return FSL_RETURN_OK_S;

	return FSL_RETURN_NO_RESOURCE_S;
}

fsl_shw_return_t shw_slot_dealloc(void *user_data, uint64_t owner_id,
				    uint32_t slot)
{
	scc_return_t retval;
	retval = scc_dealloc_slot(owner_id, slot);
	if (retval == SCC_RET_OK)
		return FSL_RETURN_OK_S;

	return FSL_RETURN_ERROR_S;
}
void *shw_slot_get_address(void *user_data, uint32_t slot)
{
	uint64_t owner_id = *((uint64_t *) user_data);
	uint32_t address;
	uint32_t value_size_bytes;
	uint32_t slot_size_bytes;
	scc_return_t scc_ret;
	scc_ret =
	    scc_get_slot_info(owner_id, slot, &address, &value_size_bytes,
			      &slot_size_bytes);
	if (scc_ret == SCC_RET_OK) {
		return (void *)address;
	}
	return NULL;
}

uint32_t shw_slot_get_base(void *user_data, uint32_t slot)
{
	return 0;
}

uint32_t shw_slot_get_offset(void *user_data, uint32_t slot)
{
	return 0;
}


/* Return the size of the key slot, in octets */
uint32_t shw_slot_get_slot_size(void *user_data, uint32_t slot)
{
	uint64_t owner_id = *((uint64_t *) user_data);
	uint32_t address;
	uint32_t value_size_bytes;
	uint32_t slot_size_bytes;
	scc_return_t scc_ret;
	scc_ret =
	    scc_get_slot_info(owner_id, slot, &address, &value_size_bytes,
			      &slot_size_bytes);
	if (scc_ret == SCC_RET_OK)
		return slot_size_bytes;
	return 0;
}


#endif	/* __KERNEL__ */

#endif	/* FSL_HAVE_SCC2 */

/*****************************************************************************/
