forked from xuos/xiuos
				
			可以运行,但是还有BUG
This commit is contained in:
		
							parent
							
								
									cff963dab0
								
							
						
					
					
						commit
						58ee6ad53b
					
				| 
						 | 
				
			
			@ -3,8 +3,10 @@ SRC_DIR := board/rzv2l_smarc
 | 
			
		|||
SRC_DIR += fsp/src/bsp/cmsis/Device/RENESAS/Source
 | 
			
		||||
SRC_DIR += fsp/src/bsp/mcu/all
 | 
			
		||||
SRC_DIR += fsp/src/r_ioport
 | 
			
		||||
SRC_DIR += fsp/src/r_mhu_ns
 | 
			
		||||
SRC_DIR += fsp/src/r_scif_uart
 | 
			
		||||
SRC_DIR += fsp/src/r_gtm
 | 
			
		||||
SRC_DIR += linaro
 | 
			
		||||
 | 
			
		||||
SRC_FILES := $(wildcard *.c)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,172 @@
 | 
			
		|||
/***********************************************************************************************************************
 | 
			
		||||
 * Copyright [2020-2021] Renesas Electronics Corporation and/or its affiliates.  All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This software and documentation are supplied by Renesas Electronics Corporation and/or its affiliates and may only
 | 
			
		||||
 * be used with products of Renesas Electronics Corp. and its affiliates ("Renesas").  No other uses are authorized.
 | 
			
		||||
 * Renesas products are sold pursuant to Renesas terms and conditions of sale.  Purchasers are solely responsible for
 | 
			
		||||
 * the selection and use of Renesas products and Renesas assumes no liability.  No license, express or implied, to any
 | 
			
		||||
 * intellectual property right is granted by Renesas.  This software is protected under all applicable laws, including
 | 
			
		||||
 * copyright laws. Renesas reserves the right to change or discontinue this software and/or this documentation.
 | 
			
		||||
 * THE SOFTWARE AND DOCUMENTATION IS DELIVERED TO YOU "AS IS," AND RENESAS MAKES NO REPRESENTATIONS OR WARRANTIES, AND
 | 
			
		||||
 * TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, DISCLAIMS ALL WARRANTIES, WHETHER EXPLICITLY OR IMPLICITLY,
 | 
			
		||||
 * INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT, WITH RESPECT TO THE
 | 
			
		||||
 * SOFTWARE OR DOCUMENTATION.  RENESAS SHALL HAVE NO LIABILITY ARISING OUT OF ANY SECURITY VULNERABILITY OR BREACH.
 | 
			
		||||
 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT WILL RENESAS BE LIABLE TO YOU IN CONNECTION WITH THE SOFTWARE OR
 | 
			
		||||
 * DOCUMENTATION (OR ANY PERSON OR ENTITY CLAIMING RIGHTS DERIVED FROM YOU) FOR ANY LOSS, DAMAGES, OR CLAIMS WHATSOEVER,
 | 
			
		||||
 * INCLUDING, WITHOUT LIMITATION, ANY DIRECT, CONSEQUENTIAL, SPECIAL, INDIRECT, PUNITIVE, OR INCIDENTAL DAMAGES; ANY
 | 
			
		||||
 * LOST PROFITS, OTHER ECONOMIC DAMAGE, PROPERTY DAMAGE, OR PERSONAL INJURY; AND EVEN IF RENESAS HAS BEEN ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH LOSS, DAMAGES, CLAIMS OR COSTS.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************************************//**
 | 
			
		||||
 * @ingroup RENESAS_INTERFACES
 | 
			
		||||
 * @defgroup MHU_API MHU Interface (for secure and non secure channels)
 | 
			
		||||
 * @brief Interface for Message Handling Unit
 | 
			
		||||
 *
 | 
			
		||||
 * @section MHU_API_SUMMARY Summary
 | 
			
		||||
 * The Message Handling Unit interface provides a common API for MHU HAL drivers.
 | 
			
		||||
 * The Message Handling Unit interface supports:
 | 
			
		||||
 *        - Message communication between Cortex-A55 and Cortex-M33.
 | 
			
		||||
 *        - 32-bit data can be communicated between CPUs via shared memory.
 | 
			
		||||
 *
 | 
			
		||||
 * Implemented by:
 | 
			
		||||
 * - @ref MHU_S
 | 
			
		||||
 * - @ref MHU_NS
 | 
			
		||||
 *
 | 
			
		||||
 * @{
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/***********************************************************************************************************************
 | 
			
		||||
 * Includes
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/* Register definitions, common services and error codes. */
 | 
			
		||||
#include "bsp_api.h"
 | 
			
		||||
 | 
			
		||||
#ifndef R_MHU_API_H
 | 
			
		||||
 #define R_MHU_API_H
 | 
			
		||||
 | 
			
		||||
/* Common macro for FSP header files. There is also a corresponding FSP_FOOTER macro at the end of this file. */
 | 
			
		||||
FSP_HEADER
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * Macro definitions
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 #define MHU_API_VERSION_MAJOR    (1U)
 | 
			
		||||
 #define MHU_API_VERSION_MINOR    (0U)
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * Typedef definitions
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
typedef enum e_mhu_send_type
 | 
			
		||||
{
 | 
			
		||||
    MHU_SEND_TYPE_MSG = 0,             ///< Channel for sending "message" and receiving "response".
 | 
			
		||||
    MHU_SEND_TYPE_RSP,                 ///< Channel for sending "response" and receiving "message".
 | 
			
		||||
} mhu_send_type_t;
 | 
			
		||||
 | 
			
		||||
/** MHU callback parameter definition */
 | 
			
		||||
typedef struct st_mhu_callback_args
 | 
			
		||||
{
 | 
			
		||||
    /** Placeholder for user data.  Set in @ref mhu_api_t::open function in @ref mhu_cfg_t. */
 | 
			
		||||
    void const * p_context;
 | 
			
		||||
    uint32_t     channel;              ///< Channel where the receive interrupt occurred.
 | 
			
		||||
    uint32_t     msg;                  ///< 32-bit received data.
 | 
			
		||||
} mhu_callback_args_t;
 | 
			
		||||
 | 
			
		||||
/** MHU configuration block */
 | 
			
		||||
typedef struct st_mhu_cfg
 | 
			
		||||
{
 | 
			
		||||
    /** Generic configuration */
 | 
			
		||||
    uint32_t  channel;                                 ///< Identifier recognizable by implementation
 | 
			
		||||
    uint8_t   rx_ipl;                                  ///< Receive interrupt priority
 | 
			
		||||
    IRQn_Type rx_irq;                                  ///< Receive interrupt ID
 | 
			
		||||
 | 
			
		||||
    /** Parameters to control software behavior */
 | 
			
		||||
    void (* p_callback)(mhu_callback_args_t * p_args); ///< Pointer to callback function
 | 
			
		||||
 | 
			
		||||
    void const * p_shared_memory;                      ///< Pointer to 64-bit send/receive data buffer.
 | 
			
		||||
 | 
			
		||||
    /** Placeholder for user data.  Passed to the user callback in @ref mhu_callback_args_t. */
 | 
			
		||||
    void const * p_context;
 | 
			
		||||
} mhu_cfg_t;
 | 
			
		||||
 | 
			
		||||
/** MHU control block.  Allocate an instance specific control block to pass into the MHU API calls.
 | 
			
		||||
 * @par Implemented as
 | 
			
		||||
 * - mhu_instance_ctrl_t
 | 
			
		||||
 */
 | 
			
		||||
typedef void mhu_ctrl_t;
 | 
			
		||||
 | 
			
		||||
/** Interface definition for MHU */
 | 
			
		||||
typedef struct st_mhu_api
 | 
			
		||||
{
 | 
			
		||||
    /** Opens the MHU driver and initializes the hardware.
 | 
			
		||||
     * @par Implemented as
 | 
			
		||||
     * - @ref R_MHU_S_Open()
 | 
			
		||||
     * - @ref R_MHU_NS_Open()
 | 
			
		||||
     *
 | 
			
		||||
     * @param[in] p_ctrl    Pointer to control block. Must be declared by user. Elements are set here.
 | 
			
		||||
     * @param[in] p_cfg     Pointer to configuration structure.
 | 
			
		||||
     */
 | 
			
		||||
    fsp_err_t (* open)(mhu_ctrl_t * const p_ctrl, mhu_cfg_t const * const p_cfg);
 | 
			
		||||
 | 
			
		||||
    /** Performs a send operation on an MHU device.
 | 
			
		||||
     * @par Implemented as
 | 
			
		||||
     * - @ref R_MHU_S_MsgSend()
 | 
			
		||||
     * - @ref R_MHU_NS_MsgSend()
 | 
			
		||||
     *
 | 
			
		||||
     * @param[in] p_ctrl    Pointer to control block set in mhu_api_t::open call.
 | 
			
		||||
     * @param[in] msg       32bit send data.
 | 
			
		||||
     */
 | 
			
		||||
    fsp_err_t (* msgSend)(mhu_ctrl_t * const p_ctrl, uint32_t const msg);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Specify callback function and optional context pointer and working memory pointer.
 | 
			
		||||
     * @par Implemented as
 | 
			
		||||
     * - @ref R_MHU_S_CallbackSet()
 | 
			
		||||
     * - @ref R_MHU_NS_CallbackSet()
 | 
			
		||||
     *
 | 
			
		||||
     * @param[in]   p_ctrl                   Control block set in @ref mhu_api_t::open call for this channel.
 | 
			
		||||
     * @param[in]   p_callback               Callback function to register
 | 
			
		||||
     * @param[in]   p_context                Pointer to send to callback function
 | 
			
		||||
     * @param[in]   p_callback_memory        Pointer to volatile memory where callback structure can be allocated.
 | 
			
		||||
     *                                       Callback arguments allocated here are only valid during the callback.
 | 
			
		||||
     */
 | 
			
		||||
    fsp_err_t (* callbackSet)(mhu_ctrl_t * const p_api_ctrl, void (* p_callback)(mhu_callback_args_t *),
 | 
			
		||||
                              void const * const p_context, mhu_callback_args_t * const p_callback_memory);
 | 
			
		||||
 | 
			
		||||
    /** Closes the driver and releases the MHU device.
 | 
			
		||||
     * @par Implemented as
 | 
			
		||||
     * - @ref R_MHU_S_Close()
 | 
			
		||||
     * - @ref R_MHU_NS_Close()
 | 
			
		||||
     *
 | 
			
		||||
     * @param[in] p_ctrl    Pointer to control block set in mhu_api_t::open call.
 | 
			
		||||
     */
 | 
			
		||||
    fsp_err_t (* close)(mhu_ctrl_t * const p_ctrl);
 | 
			
		||||
 | 
			
		||||
    /* DEPRECATED Get version and stores it in provided pointer p_version.
 | 
			
		||||
     * @par Implemented as
 | 
			
		||||
     * - @ref R_MHU_S_VersionGet()
 | 
			
		||||
     * - @ref R_MHU_NS_VersionGet()
 | 
			
		||||
     *
 | 
			
		||||
     * @param[out] p_version  Code and API version used.
 | 
			
		||||
     */
 | 
			
		||||
    fsp_err_t (* versionGet)(fsp_version_t * const p_version);
 | 
			
		||||
} mhu_api_t;
 | 
			
		||||
 | 
			
		||||
/** This structure encompasses everything that is needed to use an instance of this interface. */
 | 
			
		||||
typedef struct st_mhu_instance
 | 
			
		||||
{
 | 
			
		||||
    mhu_ctrl_t      * p_ctrl;          ///< Pointer to the control structure for this instance
 | 
			
		||||
    mhu_cfg_t const * p_cfg;           ///< Pointer to the configuration structure for this instance
 | 
			
		||||
    mhu_api_t const * p_api;           ///< Pointer to the API structure for this instance
 | 
			
		||||
} mhu_instance_t;
 | 
			
		||||
 | 
			
		||||
/******************************************************************************************************************//**
 | 
			
		||||
 * @} (end addtogroup MHU_API)
 | 
			
		||||
 *********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/* Common macro for FSP header files. There is also a corresponding FSP_HEADER macro at the top of this file. */
 | 
			
		||||
FSP_FOOTER
 | 
			
		||||
 | 
			
		||||
#endif                                 /* R_MHU_API_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,109 @@
 | 
			
		|||
/***********************************************************************************************************************
 | 
			
		||||
 * Copyright [2020-2021] Renesas Electronics Corporation and/or its affiliates.  All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This software and documentation are supplied by Renesas Electronics Corporation and/or its affiliates and may only
 | 
			
		||||
 * be used with products of Renesas Electronics Corp. and its affiliates ("Renesas").  No other uses are authorized.
 | 
			
		||||
 * Renesas products are sold pursuant to Renesas terms and conditions of sale.  Purchasers are solely responsible for
 | 
			
		||||
 * the selection and use of Renesas products and Renesas assumes no liability.  No license, express or implied, to any
 | 
			
		||||
 * intellectual property right is granted by Renesas.  This software is protected under all applicable laws, including
 | 
			
		||||
 * copyright laws. Renesas reserves the right to change or discontinue this software and/or this documentation.
 | 
			
		||||
 * THE SOFTWARE AND DOCUMENTATION IS DELIVERED TO YOU "AS IS," AND RENESAS MAKES NO REPRESENTATIONS OR WARRANTIES, AND
 | 
			
		||||
 * TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, DISCLAIMS ALL WARRANTIES, WHETHER EXPLICITLY OR IMPLICITLY,
 | 
			
		||||
 * INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT, WITH RESPECT TO THE
 | 
			
		||||
 * SOFTWARE OR DOCUMENTATION.  RENESAS SHALL HAVE NO LIABILITY ARISING OUT OF ANY SECURITY VULNERABILITY OR BREACH.
 | 
			
		||||
 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT WILL RENESAS BE LIABLE TO YOU IN CONNECTION WITH THE SOFTWARE OR
 | 
			
		||||
 * DOCUMENTATION (OR ANY PERSON OR ENTITY CLAIMING RIGHTS DERIVED FROM YOU) FOR ANY LOSS, DAMAGES, OR CLAIMS WHATSOEVER,
 | 
			
		||||
 * INCLUDING, WITHOUT LIMITATION, ANY DIRECT, CONSEQUENTIAL, SPECIAL, INDIRECT, PUNITIVE, OR INCIDENTAL DAMAGES; ANY
 | 
			
		||||
 * LOST PROFITS, OTHER ECONOMIC DAMAGE, PROPERTY DAMAGE, OR PERSONAL INJURY; AND EVEN IF RENESAS HAS BEEN ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH LOSS, DAMAGES, CLAIMS OR COSTS.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************************************//**
 | 
			
		||||
 * @addtogroup MHU_NS
 | 
			
		||||
 * @{
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/***********************************************************************************************************************
 | 
			
		||||
 * Includes
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
#include "r_mhu_api.h"
 | 
			
		||||
 | 
			
		||||
#ifndef R_MHU_NS_H
 | 
			
		||||
 #define R_MHU_NS_H
 | 
			
		||||
 | 
			
		||||
/* Common macro for FSP header files. There is also a corresponding FSP_FOOTER macro at the end of this file. */
 | 
			
		||||
FSP_HEADER
 | 
			
		||||
 | 
			
		||||
/***********************************************************************************************************************
 | 
			
		||||
 * Macro definitions
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
 #define MHU_NS_CODE_VERSION_MAJOR    (1U)
 | 
			
		||||
 #define MHU_NS_CODE_VERSION_MINOR    (0U)
 | 
			
		||||
 | 
			
		||||
/*************************************************************************************************
 | 
			
		||||
 * Type defines
 | 
			
		||||
 *************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/** Channel control block. DO NOT INITIALIZE.  Initialization occurs when @ref mhu_api_t::open is called. */
 | 
			
		||||
typedef struct st_mhu_ns_instance_ctrl
 | 
			
		||||
{
 | 
			
		||||
    uint32_t          open;             ///< Indicates whether the open() API has been successfully called.
 | 
			
		||||
    mhu_cfg_t const * p_cfg;            ///< Pointer to instance configuration
 | 
			
		||||
    R_MHU0_Type     * p_regs;           ///< Base register for this channel
 | 
			
		||||
 | 
			
		||||
    uint32_t        channel;            ///< channel
 | 
			
		||||
    mhu_send_type_t send_type;          ///< Send Type: Message or Response
 | 
			
		||||
    uint32_t      * p_shared_memory_tx; ///< Pointer to send data area
 | 
			
		||||
    uint32_t      * p_shared_memory_rx; ///< Pointer to recv data area
 | 
			
		||||
 | 
			
		||||
 #if BSP_TZ_SECURE_BUILD
 | 
			
		||||
    bool callback_is_secure;            ///< p_callback is in secure memory
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
    /* Pointer to callback and optional working memory */
 | 
			
		||||
    void (* p_callback)(mhu_callback_args_t *);
 | 
			
		||||
 | 
			
		||||
    /* Pointer to non-secure memory that can be used to pass arguments to a callback in non-secure memory. */
 | 
			
		||||
    mhu_callback_args_t * p_callback_memory;
 | 
			
		||||
 | 
			
		||||
    /* Pointer to context to be passed into callback function */
 | 
			
		||||
    void const * p_context;
 | 
			
		||||
} mhu_ns_instance_ctrl_t;
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * Exported global variables
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/** @cond INC_HEADER_DEFS_SEC */
 | 
			
		||||
/** Filled in Interface API structure for this Instance. */
 | 
			
		||||
extern const mhu_api_t g_mhu_ns_on_mhu_ns;
 | 
			
		||||
 | 
			
		||||
/** @endcond */
 | 
			
		||||
 | 
			
		||||
/***********************************************************************************************************************
 | 
			
		||||
 * Public APIs
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
fsp_err_t R_MHU_NS_Open(mhu_ctrl_t * p_ctrl, mhu_cfg_t const * const p_cfg);
 | 
			
		||||
 | 
			
		||||
fsp_err_t R_MHU_NS_MsgSend(mhu_ctrl_t * const p_ctrl, uint32_t const msg);
 | 
			
		||||
 | 
			
		||||
fsp_err_t R_MHU_NS_Close(mhu_ctrl_t * const p_ctrl);
 | 
			
		||||
 | 
			
		||||
fsp_err_t R_MHU_NS_VersionGet(fsp_version_t * p_version);
 | 
			
		||||
 | 
			
		||||
fsp_err_t R_MHU_NS_CallbackSet(mhu_ctrl_t * const          p_api_ctrl,
 | 
			
		||||
                               void (                    * p_callback)(mhu_callback_args_t *),
 | 
			
		||||
                               void const * const          p_context,
 | 
			
		||||
                               mhu_callback_args_t * const p_callback_memory);
 | 
			
		||||
 | 
			
		||||
void R_MHU_NS_IsrSub(uint32_t irq);
 | 
			
		||||
 | 
			
		||||
/** Common macro for FSP header files. There is also a corresponding FSP_HEADER macro at the top of this file. */
 | 
			
		||||
FSP_FOOTER
 | 
			
		||||
 | 
			
		||||
#endif                                 /* R_MHU_NS_H */
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************************************//**
 | 
			
		||||
 * @} (end defgroup MHU_NS)
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
 | 
			
		||||
SRC_DIR :=
 | 
			
		||||
SRC_FILES := $(wildcard *.c)
 | 
			
		||||
 | 
			
		||||
include $(KERNEL_ROOT)/compiler.mk
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,563 @@
 | 
			
		|||
/***********************************************************************************************************************
 | 
			
		||||
 * Copyright [2020-2021] Renesas Electronics Corporation and/or its affiliates.  All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This software and documentation are supplied by Renesas Electronics Corporation and/or its affiliates and may only
 | 
			
		||||
 * be used with products of Renesas Electronics Corp. and its affiliates ("Renesas").  No other uses are authorized.
 | 
			
		||||
 * Renesas products are sold pursuant to Renesas terms and conditions of sale.  Purchasers are solely responsible for
 | 
			
		||||
 * the selection and use of Renesas products and Renesas assumes no liability.  No license, express or implied, to any
 | 
			
		||||
 * intellectual property right is granted by Renesas.  This software is protected under all applicable laws, including
 | 
			
		||||
 * copyright laws. Renesas reserves the right to change or discontinue this software and/or this documentation.
 | 
			
		||||
 * THE SOFTWARE AND DOCUMENTATION IS DELIVERED TO YOU "AS IS," AND RENESAS MAKES NO REPRESENTATIONS OR WARRANTIES, AND
 | 
			
		||||
 * TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, DISCLAIMS ALL WARRANTIES, WHETHER EXPLICITLY OR IMPLICITLY,
 | 
			
		||||
 * INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT, WITH RESPECT TO THE
 | 
			
		||||
 * SOFTWARE OR DOCUMENTATION.  RENESAS SHALL HAVE NO LIABILITY ARISING OUT OF ANY SECURITY VULNERABILITY OR BREACH.
 | 
			
		||||
 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT WILL RENESAS BE LIABLE TO YOU IN CONNECTION WITH THE SOFTWARE OR
 | 
			
		||||
 * DOCUMENTATION (OR ANY PERSON OR ENTITY CLAIMING RIGHTS DERIVED FROM YOU) FOR ANY LOSS, DAMAGES, OR CLAIMS WHATSOEVER,
 | 
			
		||||
 * INCLUDING, WITHOUT LIMITATION, ANY DIRECT, CONSEQUENTIAL, SPECIAL, INDIRECT, PUNITIVE, OR INCIDENTAL DAMAGES; ANY
 | 
			
		||||
 * LOST PROFITS, OTHER ECONOMIC DAMAGE, PROPERTY DAMAGE, OR PERSONAL INJURY; AND EVEN IF RENESAS HAS BEEN ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH LOSS, DAMAGES, CLAIMS OR COSTS.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/***********************************************************************************************************************
 | 
			
		||||
 * Includes
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
#include "r_mhu_ns.h"
 | 
			
		||||
#include <xizi.h>
 | 
			
		||||
 | 
			
		||||
/***********************************************************************************************************************
 | 
			
		||||
 * Macro definitions
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/** "MHU" in ASCII, used to determine if channel is open. */
 | 
			
		||||
#define MHU_NS_OPEN                (0x00774855ULL)
 | 
			
		||||
 | 
			
		||||
#define MHU_NS_SHMEM_CH_SIZE       (0x8)
 | 
			
		||||
#define MHU_NS_SHMEM_TXD_OFFSET    (0x0)
 | 
			
		||||
#define MHU_NS_SHMEM_RXD_OFFSET    (0x4)
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * Typedef definitions
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
#if defined(__ARMCC_VERSION) || defined(__ICCARM__)
 | 
			
		||||
typedef void (BSP_CMSE_NONSECURE_CALL * mhu_ns_prv_ns_callback)(mhu_callback_args_t * p_args);
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
typedef BSP_CMSE_NONSECURE_CALL void (*volatile mhu_ns_prv_ns_callback)(mhu_callback_args_t * p_args);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/***********************************************************************************************************************
 | 
			
		||||
 * Private function prototypes
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
static void r_mhu_ns_set_send_data(mhu_ns_instance_ctrl_t * p_instance_ctrl, uint32_t msg);
 | 
			
		||||
 | 
			
		||||
static fsp_err_t r_mhu_ns_common_preamble(mhu_ns_instance_ctrl_t * p_instance_ctrl);
 | 
			
		||||
 | 
			
		||||
#if MHU_NS_CFG_PARAM_CHECKING_ENABLE
 | 
			
		||||
static fsp_err_t r_mhu_ns_open_param_checking(mhu_ns_instance_ctrl_t * p_instance_ctrl, mhu_cfg_t const * const p_cfg);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ISRs. */
 | 
			
		||||
void mhu_ns_int_isr(void);
 | 
			
		||||
void metal_irq_isr_wrapper(void);
 | 
			
		||||
void metal_irq_isr(uint32_t vector);
 | 
			
		||||
 | 
			
		||||
/***********************************************************************************************************************
 | 
			
		||||
 * Private global variables
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/** Version data structure. */
 | 
			
		||||
static const fsp_version_t s_mhu_ns_version =
 | 
			
		||||
{
 | 
			
		||||
    .api_version_minor  = MHU_API_VERSION_MINOR,
 | 
			
		||||
    .api_version_major  = MHU_API_VERSION_MAJOR,
 | 
			
		||||
    .code_version_minor = MHU_NS_CODE_VERSION_MINOR,
 | 
			
		||||
    .code_version_major = MHU_NS_CODE_VERSION_MAJOR,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern uint32_t __mhu_shmem_start;
 | 
			
		||||
 | 
			
		||||
static const uint32_t g_shmem_base = (uint32_t) &__mhu_shmem_start;
 | 
			
		||||
 | 
			
		||||
/***********************************************************************************************************************
 | 
			
		||||
 * Global Variables
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/** MHU_NS Implementation of MHU Driver  */
 | 
			
		||||
const mhu_api_t g_mhu_ns_on_mhu_ns =
 | 
			
		||||
{
 | 
			
		||||
    .open        = R_MHU_NS_Open,
 | 
			
		||||
    .msgSend     = R_MHU_NS_MsgSend,
 | 
			
		||||
    .callbackSet = R_MHU_NS_CallbackSet,
 | 
			
		||||
    .close       = R_MHU_NS_Close,
 | 
			
		||||
    .versionGet  = R_MHU_NS_VersionGet
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************************************//**
 | 
			
		||||
 * @addtogroup MHU_NS
 | 
			
		||||
 * @{
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/***********************************************************************************************************************
 | 
			
		||||
 * Functions
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************************************//**
 | 
			
		||||
 * Initializes the MHU_NS module instance. Implements @ref mhu_api_t::open.
 | 
			
		||||
 *
 | 
			
		||||
 * @retval FSP_SUCCESS                 Initialization was successful.
 | 
			
		||||
 * @retval FSP_ERR_ASSERTION           A required input pointer is NULL.
 | 
			
		||||
 * @retval FSP_ERR_ALREADY_OPEN        R_MHU_NS_Open has already been called for this p_ctrl.
 | 
			
		||||
 * @retval FSP_ERR_INVALID_ARGUMENT    The specified IRQ number is invalid.
 | 
			
		||||
 * @retval FSP_ERR_INVALID_CHANNEL     Requested channel number is not available on MHU_NS.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
fsp_err_t R_MHU_NS_Open (mhu_ctrl_t * const p_ctrl, mhu_cfg_t const * const p_cfg)
 | 
			
		||||
{
 | 
			
		||||
    mhu_ns_instance_ctrl_t * p_instance_ctrl = (mhu_ns_instance_ctrl_t *) p_ctrl;
 | 
			
		||||
 | 
			
		||||
#if MHU_NS_CFG_PARAM_CHECKING_ENABLE
 | 
			
		||||
    fsp_err_t err = r_mhu_ns_open_param_checking(p_instance_ctrl, p_cfg);
 | 
			
		||||
    FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    p_instance_ctrl->p_regs = (R_MHU0_Type *) (R_MHU0_BASE +
 | 
			
		||||
                                               (p_cfg->channel * ((intptr_t) R_MHU1_BASE - (intptr_t) R_MHU0_BASE)));
 | 
			
		||||
    p_instance_ctrl->p_cfg   = p_cfg;
 | 
			
		||||
    p_instance_ctrl->channel = p_cfg->channel;
 | 
			
		||||
 | 
			
		||||
    switch (p_cfg->channel)
 | 
			
		||||
    {
 | 
			
		||||
        case 4:
 | 
			
		||||
        case 5:
 | 
			
		||||
        {
 | 
			
		||||
            p_instance_ctrl->send_type = MHU_SEND_TYPE_MSG;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case 1:
 | 
			
		||||
        case 3:
 | 
			
		||||
        {
 | 
			
		||||
            p_instance_ctrl->send_type = MHU_SEND_TYPE_RSP;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
        {
 | 
			
		||||
            p_instance_ctrl->send_type = MHU_SEND_TYPE_MSG;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (0 != p_cfg->p_shared_memory)
 | 
			
		||||
    {
 | 
			
		||||
        /* Use specified address */
 | 
			
		||||
        p_instance_ctrl->p_shared_memory_tx = (uint32_t *) p_cfg->p_shared_memory;
 | 
			
		||||
        p_instance_ctrl->p_shared_memory_rx = (uint32_t *) (((uint32_t) p_cfg->p_shared_memory) + 0x4);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        /* Use default location */
 | 
			
		||||
        p_instance_ctrl->p_shared_memory_tx = (uint32_t *) (g_shmem_base + (MHU_NS_SHMEM_CH_SIZE * p_cfg->channel) +
 | 
			
		||||
                                                            MHU_NS_SHMEM_TXD_OFFSET);
 | 
			
		||||
        p_instance_ctrl->p_shared_memory_rx = (uint32_t *) (g_shmem_base + (MHU_NS_SHMEM_CH_SIZE * p_cfg->channel) +
 | 
			
		||||
                                                            MHU_NS_SHMEM_RXD_OFFSET);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Power on the MHU_NS channel. */
 | 
			
		||||
    R_BSP_MODULE_START(FSP_IP_MHU, p_cfg->channel);
 | 
			
		||||
    R_BSP_MODULE_CLKON(FSP_IP_MHU, p_cfg->channel);
 | 
			
		||||
    R_BSP_MODULE_RSTOFF(FSP_IP_MHU, p_cfg->channel);
 | 
			
		||||
 | 
			
		||||
    R_BSP_IrqCfgEnable(p_cfg->rx_irq, p_cfg->rx_ipl, p_instance_ctrl);
 | 
			
		||||
 | 
			
		||||
    /* Set callback and context pointers */
 | 
			
		||||
 | 
			
		||||
#if BSP_TZ_SECURE_BUILD
 | 
			
		||||
 | 
			
		||||
    /* If this is a secure build, the callback provided in p_cfg must be secure. */
 | 
			
		||||
    p_instance_ctrl->callback_is_secure = true;
 | 
			
		||||
#endif
 | 
			
		||||
    p_instance_ctrl->p_callback        = p_cfg->p_callback;
 | 
			
		||||
    p_instance_ctrl->p_context         = p_cfg->p_context;
 | 
			
		||||
    p_instance_ctrl->p_callback_memory = NULL;
 | 
			
		||||
 | 
			
		||||
    p_instance_ctrl->open = MHU_NS_OPEN;
 | 
			
		||||
 | 
			
		||||
    /* All done.  */
 | 
			
		||||
    return FSP_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * End of function R_MHU_NS_Open
 | 
			
		||||
 *********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************************************//**
 | 
			
		||||
 * Send message via MHU.
 | 
			
		||||
 * Implements @ref mhu_api_t::msgSend.
 | 
			
		||||
 *
 | 
			
		||||
 * @retval FSP_SUCCESS                 Send message successfully.
 | 
			
		||||
 * @retval FSP_ERR_ASSERTION           A required pointer was NULL.
 | 
			
		||||
 * @retval FSP_ERR_NOT_OPEN            The instance control structure is not opened.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
fsp_err_t R_MHU_NS_MsgSend (mhu_ctrl_t * const p_ctrl, uint32_t const msg)
 | 
			
		||||
{
 | 
			
		||||
    mhu_ns_instance_ctrl_t * p_instance_ctrl = (mhu_ns_instance_ctrl_t *) p_ctrl;
 | 
			
		||||
#if MHU_NS_CFG_PARAM_CHECKING_ENABLE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    fsp_err_t err = r_mhu_ns_common_preamble(p_instance_ctrl);
 | 
			
		||||
    FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
 | 
			
		||||
 | 
			
		||||
    /* Set msg. */
 | 
			
		||||
    r_mhu_ns_set_send_data(p_instance_ctrl, msg);
 | 
			
		||||
 | 
			
		||||
    return FSP_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * End of function R_MHU_NS_MsgSend
 | 
			
		||||
 *********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************************************//**
 | 
			
		||||
 * Updates the user callback with the option to provide memory for the callback argument structure.
 | 
			
		||||
 * Implements @ref mhu_api_t::callbackSet.
 | 
			
		||||
 *
 | 
			
		||||
 * @retval  FSP_SUCCESS                  Callback updated successfully.
 | 
			
		||||
 * @retval  FSP_ERR_ASSERTION            A required pointer is NULL.
 | 
			
		||||
 * @retval  FSP_ERR_NOT_OPEN             The control block has not been opened.
 | 
			
		||||
 * @retval  FSP_ERR_NO_CALLBACK_MEMORY   p_callback is non-secure and p_callback_memory is either secure or NULL.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
fsp_err_t R_MHU_NS_CallbackSet (mhu_ctrl_t * const          p_api_ctrl,
 | 
			
		||||
                                void (                    * p_callback)(mhu_callback_args_t *),
 | 
			
		||||
                                void const * const          p_context,
 | 
			
		||||
                                mhu_callback_args_t * const p_callback_memory)
 | 
			
		||||
{
 | 
			
		||||
    mhu_ns_instance_ctrl_t * p_ctrl = (mhu_ns_instance_ctrl_t *) p_api_ctrl;
 | 
			
		||||
 | 
			
		||||
#if MHU_NS_CFG_PARAM_CHECKING_ENABLE
 | 
			
		||||
    FSP_ASSERT(p_ctrl);
 | 
			
		||||
    FSP_ASSERT(p_callback);
 | 
			
		||||
    FSP_ERROR_RETURN(MHU_NS_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if BSP_TZ_SECURE_BUILD
 | 
			
		||||
 | 
			
		||||
    /* Get security state of p_callback */
 | 
			
		||||
    p_ctrl->callback_is_secure =
 | 
			
		||||
        (NULL == cmse_check_address_range((void *) p_callback, sizeof(void *), CMSE_AU_NONSECURE));
 | 
			
		||||
 | 
			
		||||
 #if MHU_NS_CFG_PARAM_CHECKING_ENABLE
 | 
			
		||||
 | 
			
		||||
    /* In secure projects, p_callback_memory must be provided in non-secure space if p_callback is non-secure */
 | 
			
		||||
    mhu_callback_args_t * const p_callback_memory_checked = cmse_check_pointed_object(p_callback_memory,
 | 
			
		||||
                                                                                      CMSE_AU_NONSECURE);
 | 
			
		||||
    FSP_ERROR_RETURN(p_ctrl->callback_is_secure || (NULL != p_callback_memory_checked), FSP_ERR_NO_CALLBACK_MEMORY);
 | 
			
		||||
 #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /* Store callback and context */
 | 
			
		||||
 | 
			
		||||
#if BSP_TZ_SECURE_BUILD
 | 
			
		||||
 | 
			
		||||
    /* cmse_check_address_range returns NULL if p_callback is located in secure memory */
 | 
			
		||||
    p_ctrl->callback_is_secure =
 | 
			
		||||
        (NULL == cmse_check_address_range((void *) p_callback, sizeof(void *), CMSE_AU_NONSECURE));
 | 
			
		||||
#endif
 | 
			
		||||
    p_ctrl->p_callback        = p_callback;
 | 
			
		||||
    p_ctrl->p_context         = p_context;
 | 
			
		||||
    p_ctrl->p_callback_memory = p_callback_memory;
 | 
			
		||||
 | 
			
		||||
    return FSP_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * End of function R_MHU_NS_CallbackSet
 | 
			
		||||
 *********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************************************//**
 | 
			
		||||
 * Disables interrupts, clears internal driver data.
 | 
			
		||||
 * @ref mhu_api_t::close.
 | 
			
		||||
 *
 | 
			
		||||
 * @retval FSP_SUCCESS                 MHU_NS closed.
 | 
			
		||||
 * @retval FSP_ERR_ASSERTION           p_ctrl is NULL.
 | 
			
		||||
 * @retval FSP_ERR_NOT_OPEN            The instance control structure is not opened.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
fsp_err_t R_MHU_NS_Close (mhu_ctrl_t * const p_ctrl)
 | 
			
		||||
{
 | 
			
		||||
    mhu_ns_instance_ctrl_t * p_instance_ctrl = (mhu_ns_instance_ctrl_t *) p_ctrl;
 | 
			
		||||
 | 
			
		||||
    fsp_err_t err = r_mhu_ns_common_preamble(p_instance_ctrl);
 | 
			
		||||
    FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
 | 
			
		||||
 | 
			
		||||
    /* Cleanup the device: disable interrupts */
 | 
			
		||||
 | 
			
		||||
    NVIC_DisableIRQ(p_instance_ctrl->p_cfg->rx_irq);
 | 
			
		||||
    R_FSP_IsrContextSet(p_instance_ctrl->p_cfg->rx_irq, p_instance_ctrl);
 | 
			
		||||
 | 
			
		||||
    p_instance_ctrl->open = 0U;
 | 
			
		||||
 | 
			
		||||
    return FSP_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * End of function R_MHU_NS_Close
 | 
			
		||||
 *********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/***********************************************************************************************************************
 | 
			
		||||
 * DEPRECATED Sets driver version based on compile time macros.  Implements @ref mhu_api_t::versionGet.
 | 
			
		||||
 *
 | 
			
		||||
 * @retval     FSP_SUCCESS          Version in p_version.
 | 
			
		||||
 * @retval     FSP_ERR_ASSERTION    The parameter p_version is NULL.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
fsp_err_t R_MHU_NS_VersionGet (fsp_version_t * const p_version)
 | 
			
		||||
{
 | 
			
		||||
#if MHU_NS_CFG_PARAM_CHECKING_ENABLE
 | 
			
		||||
 | 
			
		||||
    /* Verify parameters are valid */
 | 
			
		||||
    FSP_ASSERT(NULL != p_version);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    p_version->version_id = s_mhu_ns_version.version_id;
 | 
			
		||||
 | 
			
		||||
    return FSP_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * End of function R_MHU_NS_VersionGet
 | 
			
		||||
 *********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/** @} (end addtogroup MHU_NS) */
 | 
			
		||||
 | 
			
		||||
/***********************************************************************************************************************
 | 
			
		||||
 * Private Functions
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
#if MHU_NS_CFG_PARAM_CHECKING_ENABLE
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************************************//**
 | 
			
		||||
 * Parameter checking for R_MHU_NS_Open.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in] p_instance_ctrl          Pointer to instance control structure.
 | 
			
		||||
 * @param[in]  p_cfg              Configuration structure for this instance
 | 
			
		||||
 *
 | 
			
		||||
 * @retval FSP_SUCCESS                 Initialization was successful.
 | 
			
		||||
 * @retval FSP_ERR_ASSERTION           A required input pointer is NULL.
 | 
			
		||||
 * @retval FSP_ERR_ALREADY_OPEN        R_MHU_NS_Open has already been called for this p_ctrl.
 | 
			
		||||
 * @retval FSP_ERR_INVALID_ARGUMENT    The specified IRQ number is invalid.
 | 
			
		||||
 * @retval FSP_ERR_INVALID_CHANNEL     Requested channel number is not available on MHU_NS.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
static fsp_err_t r_mhu_ns_open_param_checking (mhu_ns_instance_ctrl_t * p_instance_ctrl, mhu_cfg_t const * const p_cfg)
 | 
			
		||||
{
 | 
			
		||||
    FSP_ASSERT(NULL != p_instance_ctrl);
 | 
			
		||||
    FSP_ASSERT(NULL != p_cfg);
 | 
			
		||||
    FSP_ERROR_RETURN(MHU_NS_OPEN != p_instance_ctrl->open, FSP_ERR_ALREADY_OPEN);
 | 
			
		||||
 | 
			
		||||
    /* Validate channel number. */
 | 
			
		||||
    FSP_ERROR_RETURN(((1U << p_cfg->channel) & BSP_FEATURE_MHU_NS_VALID_CHANNEL_MASK), FSP_ERR_INVALID_CHANNEL);
 | 
			
		||||
 | 
			
		||||
    FSP_ERROR_RETURN(FSP_INVALID_VECTOR != p_cfg->rx_irq, FSP_ERR_INVALID_ARGUMENT);
 | 
			
		||||
 | 
			
		||||
    return FSP_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************************************//**
 | 
			
		||||
 * Common code at the beginning of all MHU_NS functions except open.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in] p_instance_ctrl          Pointer to instance control structure.
 | 
			
		||||
 *
 | 
			
		||||
 * @retval FSP_SUCCESS                 No invalid conditions detected, MHU_NS state matches expected state.
 | 
			
		||||
 * @retval FSP_ERR_ASSERTION           p_ctrl is null.
 | 
			
		||||
 * @retval FSP_ERR_NOT_OPEN            The instance control structure is not opened.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
static fsp_err_t r_mhu_ns_common_preamble (mhu_ns_instance_ctrl_t * p_instance_ctrl)
 | 
			
		||||
{
 | 
			
		||||
#if MHU_NS_CFG_PARAM_CHECKING_ENABLE
 | 
			
		||||
    FSP_ASSERT(NULL != p_instance_ctrl);
 | 
			
		||||
    FSP_ERROR_RETURN(MHU_NS_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN);
 | 
			
		||||
#else
 | 
			
		||||
    FSP_PARAMETER_NOT_USED(p_instance_ctrl);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    return FSP_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * End of function r_mhu_ns_common_preamble
 | 
			
		||||
 *********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************************************//**
 | 
			
		||||
 * Write a message to shared memory and generate inter-core interrupt
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  p_instance_ctrl    Control block for this instance
 | 
			
		||||
 * @param[in]  msg                32bit send data
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
static void r_mhu_ns_set_send_data (mhu_ns_instance_ctrl_t * p_instance_ctrl, uint32_t msg)
 | 
			
		||||
{
 | 
			
		||||
    if (MHU_SEND_TYPE_MSG == p_instance_ctrl->send_type)
 | 
			
		||||
    {
 | 
			
		||||
        /* Check interrupt status: Has the previous message been received? */
 | 
			
		||||
        do
 | 
			
		||||
        {
 | 
			
		||||
            /* Do Nothing */
 | 
			
		||||
        } while (0 != p_instance_ctrl->p_regs->MSG_INT_STSn);
 | 
			
		||||
 | 
			
		||||
        /* Store the message data. */
 | 
			
		||||
        *p_instance_ctrl->p_shared_memory_tx = msg;
 | 
			
		||||
 | 
			
		||||
        /* Assert interrupt. */
 | 
			
		||||
        p_instance_ctrl->p_regs->MSG_INT_SETn = 1;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        /* Check interrupt status: Has the previous message been received? */
 | 
			
		||||
        do
 | 
			
		||||
        {
 | 
			
		||||
            /* Do Nothing */
 | 
			
		||||
        } while (0 != p_instance_ctrl->p_regs->RSP_INT_STSn);
 | 
			
		||||
 | 
			
		||||
        /* Store the message data. */
 | 
			
		||||
        *p_instance_ctrl->p_shared_memory_tx = msg;
 | 
			
		||||
 | 
			
		||||
        /* Assert interrupt. */
 | 
			
		||||
        p_instance_ctrl->p_regs->RSP_INT_SETn = 1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * End of function r_mhu_ns_set_send_data
 | 
			
		||||
 *********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*********************************************************************************************************************
 | 
			
		||||
 * MHU_NS receive interrupt (for OpenAMP)
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
void metal_irq_isr_wrapper (void)
 | 
			
		||||
{
 | 
			
		||||
    /* Save context if RTOS is used */
 | 
			
		||||
    FSP_CONTEXT_SAVE
 | 
			
		||||
    
 | 
			
		||||
    IRQn_Type irq = R_FSP_CurrentIrqGet();
 | 
			
		||||
 | 
			
		||||
    metal_irq_isr(irq);
 | 
			
		||||
 | 
			
		||||
    /* Restore context if RTOS is used */
 | 
			
		||||
    FSP_CONTEXT_RESTORE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * End of function metal_irq_isr_wrapper
 | 
			
		||||
 *********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*********************************************************************************************************************
 | 
			
		||||
 * MHU_NS receive interrupt (for bere mhu_ns application).
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
void mhu_ns_int_isr (void)
 | 
			
		||||
{
 | 
			
		||||
    /* Save context if RTOS is used */
 | 
			
		||||
    FSP_CONTEXT_SAVE
 | 
			
		||||
 | 
			
		||||
    IRQn_Type irq = R_FSP_CurrentIrqGet();
 | 
			
		||||
 | 
			
		||||
    R_MHU_NS_IsrSub(irq);
 | 
			
		||||
 | 
			
		||||
    /* Restore context if RTOS is used */
 | 
			
		||||
    FSP_CONTEXT_RESTORE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * End of function mhu_ns_int_isr
 | 
			
		||||
 *********************************************************************************************************************/
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************************************************//**
 | 
			
		||||
 * MHU_NS receive interrupt sub function (for OpenAMP)
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  irq    irq number for inter-core interrupt
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
void R_MHU_NS_IsrSub (uint32_t irq)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t msg;
 | 
			
		||||
 | 
			
		||||
    /* Clear pending IRQ to make sure it doesn't fire again after exiting */
 | 
			
		||||
    R_BSP_IrqStatusClear(irq);
 | 
			
		||||
 | 
			
		||||
    /* Recover ISR context saved in open. */
 | 
			
		||||
    mhu_ns_instance_ctrl_t * p_instance_ctrl = (mhu_ns_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
 | 
			
		||||
 | 
			
		||||
    /* Check interrupt reason */
 | 
			
		||||
    if (
 | 
			
		||||
        ((MHU_SEND_TYPE_RSP == p_instance_ctrl->send_type) && (0 != p_instance_ctrl->p_regs->MSG_INT_STSn)) ||
 | 
			
		||||
        ((MHU_SEND_TYPE_MSG == p_instance_ctrl->send_type) && (0 != p_instance_ctrl->p_regs->RSP_INT_STSn)))
 | 
			
		||||
    {
 | 
			
		||||
        /* Read data */
 | 
			
		||||
        msg = *p_instance_ctrl->p_shared_memory_rx;
 | 
			
		||||
 | 
			
		||||
        /* Clear interrupt */
 | 
			
		||||
        if (MHU_SEND_TYPE_RSP == p_instance_ctrl->send_type)
 | 
			
		||||
        {
 | 
			
		||||
            p_instance_ctrl->p_regs->MSG_INT_CLRn = 1;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            p_instance_ctrl->p_regs->RSP_INT_CLRn = 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Invoke the callback function if it is set. */
 | 
			
		||||
        if (NULL != p_instance_ctrl->p_callback)
 | 
			
		||||
        {
 | 
			
		||||
            /* Setup parameters for the user-supplied callback function. */
 | 
			
		||||
            mhu_callback_args_t callback_args;
 | 
			
		||||
 | 
			
		||||
            /* Store callback arguments in memory provided by user if available.  This allows callback arguments to be
 | 
			
		||||
             * stored in non-secure memory so they can be accessed by a non-secure callback function. */
 | 
			
		||||
            mhu_callback_args_t * p_args = p_instance_ctrl->p_callback_memory;
 | 
			
		||||
            if (NULL == p_args)
 | 
			
		||||
            {
 | 
			
		||||
                /* Store on stack */
 | 
			
		||||
                p_args = &callback_args;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                /* Save current arguments on the stack in case this is a nested interrupt. */
 | 
			
		||||
                callback_args = *p_args;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            p_args->p_context = p_instance_ctrl->p_context;
 | 
			
		||||
 | 
			
		||||
            p_args->channel = p_instance_ctrl->channel;
 | 
			
		||||
            p_args->msg     = msg;
 | 
			
		||||
 | 
			
		||||
#if BSP_TZ_SECURE_BUILD
 | 
			
		||||
 | 
			
		||||
            /* p_callback can point to a secure function or a non-secure function. */
 | 
			
		||||
            if (p_instance_ctrl->callback_is_secure)
 | 
			
		||||
            {
 | 
			
		||||
                /* If p_callback is secure, then the project does not need to change security state. */
 | 
			
		||||
                p_instance_ctrl->p_callback(p_args);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                /* If p_callback is Non-secure, then the project must change to Non-secure state
 | 
			
		||||
                 * in order to call the callback. */
 | 
			
		||||
                mhu_ns_prv_ns_callback p_callback = (mhu_ns_prv_ns_callback) (p_instance_ctrl->p_callback);
 | 
			
		||||
                p_callback(p_args);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
            /* If the project is not Trustzone Secure, then it will never need to change security state
 | 
			
		||||
             * in order to call the callback. */
 | 
			
		||||
            p_instance_ctrl->p_callback(p_args);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
            if (NULL != p_instance_ctrl->p_callback_memory)
 | 
			
		||||
            {
 | 
			
		||||
                /* Restore callback memory in case this is a nested interrupt. */
 | 
			
		||||
                *p_instance_ctrl->p_callback_memory = callback_args;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**********************************************************************************************************************
 | 
			
		||||
 * End of function R_MHU_NS_IsrSub
 | 
			
		||||
 *********************************************************************************************************************/
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
SRC_DIR := libmetal/lib
 | 
			
		||||
SRC_DIR += open-amp/lib/remoteproc
 | 
			
		||||
SRC_DIR += open-amp/lib/rpmsg
 | 
			
		||||
SRC_DIR += open-amp/lib/virtio
 | 
			
		||||
 | 
			
		||||
SRC_FILES := $(wildcard *.c)
 | 
			
		||||
 | 
			
		||||
include $(KERNEL_ROOT)/compiler.mk
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
Software License Agreement (BSD License)
 | 
			
		||||
========================================
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
1. Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
   this list of conditions and the following disclaimer.
 | 
			
		||||
 | 
			
		||||
2. Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
   this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
   and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
3. Neither the name of Xilinx nor the names of its contributors may be used
 | 
			
		||||
   to endorse or promote products derived from this software without
 | 
			
		||||
   specific prior written permission.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | 
			
		||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
			
		||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
			
		||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Notes
 | 
			
		||||
=========================================
 | 
			
		||||
Use the following tag instead of the full license text in the individual files:
 | 
			
		||||
 | 
			
		||||
    SPDX-License-Identifier:    BSD-3-Clause
 | 
			
		||||
 | 
			
		||||
This enables machine processing of license information based on the SPDX
 | 
			
		||||
License Identifiers that are here available: http://spdx.org/licenses/
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
# libmetal Maintainers
 | 
			
		||||
 | 
			
		||||
libmetal project is maintained by the OpenAMP open source community.
 | 
			
		||||
Everyone is encouraged to submit issues and changes to improve libmetal.
 | 
			
		||||
 | 
			
		||||
The intention of this file is to provide a set of names that developers can
 | 
			
		||||
consult when they have a question about OpenAMP and to provide a a set of
 | 
			
		||||
names to be CC'd when submitting a patch.
 | 
			
		||||
 | 
			
		||||
## Project Administration
 | 
			
		||||
Wendy Liang <wendy.liang@xilinx.com>
 | 
			
		||||
 | 
			
		||||
### All patches CC here
 | 
			
		||||
open-amp@googlegroups.com
 | 
			
		||||
 | 
			
		||||
## Machines
 | 
			
		||||
### Xilinx Platform - Zynq-7000
 | 
			
		||||
Wendy Liang <wendy.liang@xilinx.com>
 | 
			
		||||
 | 
			
		||||
### Xilinx Platform - Zynq UltraScale+ MPSoC
 | 
			
		||||
Wendy Liang <wendy.liang@xilinx.com>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,220 @@
 | 
			
		|||
# libmetal
 | 
			
		||||
 | 
			
		||||
## Overview
 | 
			
		||||
 | 
			
		||||
Libmetal provides common user APIs to access devices, handle device interrupts
 | 
			
		||||
and request memory across the following operating environments:
 | 
			
		||||
  * Linux user space (based on UIO and VFIO support in the kernel)
 | 
			
		||||
  * RTOS (with and without virtual memory)
 | 
			
		||||
  * Bare-metal environments
 | 
			
		||||
 | 
			
		||||
## Build Steps
 | 
			
		||||
 | 
			
		||||
### Building for Linux Host
 | 
			
		||||
```
 | 
			
		||||
 $ git clone https://github.com/OpenAMP/libmetal.git
 | 
			
		||||
 $ mkdir -p libmetal/<build directory>
 | 
			
		||||
 $ cd libmetal/<build directory>
 | 
			
		||||
 $ cmake ..
 | 
			
		||||
 $ make VERBOSE=1 DESTDIR=<libmetal install location> install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Cross Compiling for Linux Target
 | 
			
		||||
Use [meta-openamp](https://github.com/openamp/meta-openamp) to build
 | 
			
		||||
libmetal library.
 | 
			
		||||
Use package `libmetal` in your yocto config file.
 | 
			
		||||
 | 
			
		||||
### Building for Baremetal
 | 
			
		||||
 | 
			
		||||
To build on baremetal, you will need to provide a toolchain file. Here is an
 | 
			
		||||
example toolchain file:
 | 
			
		||||
```
 | 
			
		||||
    set (CMAKE_SYSTEM_PROCESSOR "arm"              CACHE STRING "")
 | 
			
		||||
    set (MACHINE "zynqmp_r5" CACHE STRING "")
 | 
			
		||||
 | 
			
		||||
    set (CROSS_PREFIX           "armr5-none-eabi-" CACHE STRING "")
 | 
			
		||||
    set (CMAKE_C_FLAGS          "-mfloat-abi=soft -mcpu=cortex-r5 -Wall -Werror -Wextra \
 | 
			
		||||
       -flto -Os -I/ws/xsdk/r5_0_bsp/psu_cortexr5_0/include" CACHE STRING "")
 | 
			
		||||
 | 
			
		||||
    SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto")
 | 
			
		||||
    SET(CMAKE_AR  "gcc-ar" CACHE STRING "")
 | 
			
		||||
    SET(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>")
 | 
			
		||||
    SET(CMAKE_C_ARCHIVE_FINISH   true)
 | 
			
		||||
 | 
			
		||||
    include (cross-generic-gcc)
 | 
			
		||||
```
 | 
			
		||||
* Note: other toolchain files can be found in the  `cmake/platforms/` directory.
 | 
			
		||||
* Compile with your toolchain file.
 | 
			
		||||
```
 | 
			
		||||
    $ mkdir -p build-libmetal
 | 
			
		||||
    $ cd build-libmetal
 | 
			
		||||
    $ cmake <libmetal_source> -DCMAKE_TOOLCHAIN_FILE=<toolchain_file>
 | 
			
		||||
    $ make VERBOSE=1 DESTDIR=<libmetal_install> install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Building for Zephyr
 | 
			
		||||
As Zephyr uses CMake, we build libmetal library and test application as
 | 
			
		||||
targets of Zephyr CMake project. Here is how to build libmetal for Zephyr:
 | 
			
		||||
```
 | 
			
		||||
    $ export ZEPHYR_GCC_VARIANT=zephyr
 | 
			
		||||
    $ export ZEPHYR_SDK_INSTALL_DIR=<where Zephyr SDK is installed>
 | 
			
		||||
    $ source <git_clone_zephyr_project_source_root>/zephyr-env.sh
 | 
			
		||||
 | 
			
		||||
    $ cmake <libmetal_source_root> -DWITH_ZEPHYR=on -DBOARD=qemu_cortex_m3 \
 | 
			
		||||
      [-DWITH_TESTS=on]
 | 
			
		||||
    $ make VERBOSE=1 all
 | 
			
		||||
    # If we have turned on tests with "-DWITH_TESTS=on" when we run cmake,
 | 
			
		||||
    # we launch libmetal test on Zephyr QEMU platform as follows:
 | 
			
		||||
    $ make VERBOSE=1 run
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Interfaces
 | 
			
		||||
 | 
			
		||||
The following subsections give an overview of interfaces provided by libmetal.
 | 
			
		||||
 | 
			
		||||
### Platform and OS Independent Utilities
 | 
			
		||||
 | 
			
		||||
These interfaces do not need to be ported across to new operating systems.
 | 
			
		||||
 | 
			
		||||
#### I/O
 | 
			
		||||
 | 
			
		||||
The libmetal I/O region abstraction provides access to memory mapped I/O and
 | 
			
		||||
shared memory regions.  This includes:
 | 
			
		||||
  * primitives to read and write memory with ordering constraints, and
 | 
			
		||||
  * ability to translate between physical and virtual addressing on systems
 | 
			
		||||
    that support virtual memory.
 | 
			
		||||
 | 
			
		||||
#### Log
 | 
			
		||||
 | 
			
		||||
The libmetal logging interface is used to plug log messages generated by
 | 
			
		||||
libmetal into application specific logging mechanisms (e.g. syslog).  This
 | 
			
		||||
also provides basic message prioritization and filtering mechanisms.
 | 
			
		||||
 | 
			
		||||
#### List
 | 
			
		||||
 | 
			
		||||
This is a simple doubly linked list implementation used internally within
 | 
			
		||||
libmetal, and also available for application use.
 | 
			
		||||
 | 
			
		||||
#### Other Utilities
 | 
			
		||||
 | 
			
		||||
The following utilities are provided in lib/utilities.h:
 | 
			
		||||
  * Min/max, round up/down, etc.
 | 
			
		||||
  * Bitmap operations
 | 
			
		||||
  * Helper to compute container structure pointers
 | 
			
		||||
  * ... and more ...
 | 
			
		||||
 | 
			
		||||
#### Version
 | 
			
		||||
 | 
			
		||||
The libmetal version interface allows user to get the version of the library.
 | 
			
		||||
 | 
			
		||||
### Top Level Interfaces
 | 
			
		||||
 | 
			
		||||
The users will need to call two top level interfaces to use libmetal APIs:
 | 
			
		||||
  * metal_init - initialize the libmetal resource
 | 
			
		||||
  * metal_finish - release libmetal resource
 | 
			
		||||
 | 
			
		||||
Each system needs to have their own implementation inside libmetal for these
 | 
			
		||||
two APIs to call:
 | 
			
		||||
  * metal_sys_init
 | 
			
		||||
  * metal_sys_finish
 | 
			
		||||
 | 
			
		||||
For the current release, libmetal provides Linux userspace and bare-metal
 | 
			
		||||
implementation for metal_sys_init and metal_sys_finish.
 | 
			
		||||
 | 
			
		||||
For Linux userspace, metal_sys_init sets up a table for available shared pages,
 | 
			
		||||
checks whether UIO/VFIO drivers are avail, and starts interrupt handling
 | 
			
		||||
thread.
 | 
			
		||||
 | 
			
		||||
For bare-metal, metal_sys_init and metal_sys_finish just returns.
 | 
			
		||||
 | 
			
		||||
### Atomics
 | 
			
		||||
 | 
			
		||||
The libmetal atomic operations API is consistent with the C11/C++11 stdatomics
 | 
			
		||||
interface.  The stdatomics interface is commonly provided by recent toolchains
 | 
			
		||||
including GCC and LLVM/Clang.  When porting to a different toolchain, it may be
 | 
			
		||||
necessary to provide an stdatomic compatible implementation if the toolchain
 | 
			
		||||
does not already provide one.
 | 
			
		||||
 | 
			
		||||
### Alloc
 | 
			
		||||
 | 
			
		||||
libmetal provides memory allocation and release APIs.
 | 
			
		||||
 | 
			
		||||
### Locking
 | 
			
		||||
 | 
			
		||||
libmetal provides the following locking APIs.
 | 
			
		||||
 | 
			
		||||
#### Mutex
 | 
			
		||||
 | 
			
		||||
libmetal has a generic mutex implementation which is a busy wait.  It is
 | 
			
		||||
recommended to have OS specific implementation for mutex.
 | 
			
		||||
 | 
			
		||||
The Linux userspace mutex implementation uses futex to wait for the lock
 | 
			
		||||
and wakeup a waiter.
 | 
			
		||||
 | 
			
		||||
#### Condition Variable
 | 
			
		||||
libmetal condition variable APIs provide "wait" for user applications to wait
 | 
			
		||||
on some condition to be met, and "signal" to indicate a particular even occurs.
 | 
			
		||||
 | 
			
		||||
#### Spinlock
 | 
			
		||||
libmetal spinlock APIs provides busy waiting mechanism to acquire a lock.
 | 
			
		||||
 | 
			
		||||
### Shmem
 | 
			
		||||
 | 
			
		||||
libmetal has a generic static shared memory implementation.  If your OS has a
 | 
			
		||||
global shared memory allocation, you will need to port it for the OS.
 | 
			
		||||
 | 
			
		||||
The Linux userspace shmem implementation uses libhugetlbfs to support huge page
 | 
			
		||||
sizes.
 | 
			
		||||
 | 
			
		||||
### Bus and Device Abstraction
 | 
			
		||||
 | 
			
		||||
libmetal has a static generic implementation.  If your OS has a driver model
 | 
			
		||||
implementation, you will need to port it for the OS.
 | 
			
		||||
 | 
			
		||||
The Linux userspace abstraction binds the devices to UIO or VFIO driver.
 | 
			
		||||
The user applications specify which device to use, e.g. bus "platform" bus,
 | 
			
		||||
device "f8000000.slcr", and then the abstraction will check if platform UIO
 | 
			
		||||
driver or platform VFIO driver is there.  If platform VFIO driver exists,
 | 
			
		||||
it will bind the device to the platform VFIO driver, otherwise, if UIO driver
 | 
			
		||||
exists, it will bind the device to the platform UIO driver.
 | 
			
		||||
 | 
			
		||||
The VFIO support is not yet implemented.
 | 
			
		||||
 | 
			
		||||
### Interrupt
 | 
			
		||||
 | 
			
		||||
libmetal provides APIs to register an interrupt, disable interrupts and restore
 | 
			
		||||
interrupts.
 | 
			
		||||
 | 
			
		||||
The Linux userspace implementation will use a thread to call select() function
 | 
			
		||||
to listen to the file descriptors of the devices to see if there is an interrupt
 | 
			
		||||
triggered.  If there is an interrupt triggered, it will call the interrupt
 | 
			
		||||
handler registered by the user application.
 | 
			
		||||
 | 
			
		||||
### Cache
 | 
			
		||||
 | 
			
		||||
libmetal provides APIs to flush and invalidate caches.
 | 
			
		||||
 | 
			
		||||
The cache APIs for Linux userspace are empty functions for now as cache
 | 
			
		||||
operations system calls are not avaiable for all architectures.
 | 
			
		||||
 | 
			
		||||
### DMA
 | 
			
		||||
 | 
			
		||||
libmetal DMA APIs provide DMA map and unmap implementation.
 | 
			
		||||
 | 
			
		||||
After calling DMA map, the DMA device will own the memory.
 | 
			
		||||
After calling DMA unmap, the cpu will own the memory.
 | 
			
		||||
 | 
			
		||||
For Linux userspace, it only supports to use UIO device memory as DMA
 | 
			
		||||
memory for this release.
 | 
			
		||||
 | 
			
		||||
### Time
 | 
			
		||||
libmetal time APIs provide getting timestamp implementation.
 | 
			
		||||
 | 
			
		||||
### Sleep
 | 
			
		||||
libmetal sleep APIs provide getting delay execution implementation.
 | 
			
		||||
 | 
			
		||||
### Compiler
 | 
			
		||||
 | 
			
		||||
This API is for compiler dependent functions.  For this release, there is only
 | 
			
		||||
a GCC implementation, and compiler specific code is limited to atomic
 | 
			
		||||
operations.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	alloc.h
 | 
			
		||||
 * @brief	Memory allocation handling primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_ALLOC__H__
 | 
			
		||||
#define __METAL_ALLOC__H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup Memory Allocation Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief      allocate requested memory size
 | 
			
		||||
 *             return a pointer to the allocated memory
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  size        size in byte of requested memory
 | 
			
		||||
 * @return     memory pointer, or 0 if it failed to allocate
 | 
			
		||||
 */
 | 
			
		||||
static inline void *metal_allocate_memory(unsigned int size);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief      free the memory previously allocated
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  ptr       pointer to memory 
 | 
			
		||||
 */
 | 
			
		||||
static inline void metal_free_memory(void *ptr);
 | 
			
		||||
 | 
			
		||||
#include <metal/system/xizi/alloc.h>
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_ALLOC__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2018, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	assert.h
 | 
			
		||||
 * @brief	Assertion support.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_ASSERT__H__
 | 
			
		||||
#define __METAL_ASSERT__H__
 | 
			
		||||
 | 
			
		||||
#ifdef double_assert
 | 
			
		||||
#error recursive
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <metal/system/xizi/assert.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Assertion macro.
 | 
			
		||||
 * @param cond Condition to test.
 | 
			
		||||
 */
 | 
			
		||||
#define metal_assert(cond) metal_sys_assert(cond)
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_ASSERT_H__ */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	atomic.h
 | 
			
		||||
 * @brief	Atomic primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_ATOMIC__H__
 | 
			
		||||
#define __METAL_ATOMIC__H__
 | 
			
		||||
 | 
			
		||||
#include <metal/config.h>
 | 
			
		||||
 | 
			
		||||
#if defined(HAVE_STDATOMIC_H) && !defined(__STDC_NO_ATOMICS__) && \
 | 
			
		||||
	!defined(__cplusplus)
 | 
			
		||||
# include <stdatomic.h>
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
# include <metal/compiler/gcc/atomic.h>
 | 
			
		||||
#else
 | 
			
		||||
# include <metal/processor/arm/atomic.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_ATOMIC__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,57 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	cache.h
 | 
			
		||||
 * @brief	CACHE operation primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_CACHE__H__
 | 
			
		||||
#define __METAL_CACHE__H__
 | 
			
		||||
 | 
			
		||||
#include <metal/system/xizi/cache.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** \defgroup cache CACHE Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief flush specified data cache
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in] addr start memory logical address
 | 
			
		||||
 * @param[in] len  length of memory
 | 
			
		||||
 *                 If addr is NULL, and len is 0,
 | 
			
		||||
 *                 It will flush the whole data cache.
 | 
			
		||||
 */
 | 
			
		||||
static inline void metal_cache_flush(void *addr, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
	__metal_cache_flush(addr, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief invalidate specified data cache
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in] addr start memory logical address
 | 
			
		||||
 * @param[in] len  length of memory
 | 
			
		||||
 *                 If addr is NULL, and len is 0,
 | 
			
		||||
 *                 It will invalidate the whole data cache.
 | 
			
		||||
 */
 | 
			
		||||
static inline void metal_cache_invalidate(void *addr, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
	__metal_cache_invalidate(addr, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_CACHE__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	compiler.h
 | 
			
		||||
 * @brief	Compiler specific primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_COMPILER__H__
 | 
			
		||||
#define __METAL_COMPILER__H__
 | 
			
		||||
 | 
			
		||||
#if defined(__CC_ARM)
 | 
			
		||||
# include <metal/compiler/armcc/compiler.h>
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
# include <metal/compiler/gcc/compiler.h>
 | 
			
		||||
#elif defined(__ICCARM__)
 | 
			
		||||
# include <metal/compiler/iar/compiler.h>
 | 
			
		||||
#else
 | 
			
		||||
# error "Missing compiler support"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_COMPILER__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,123 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	gcc/atomic.h
 | 
			
		||||
 * @brief	GCC specific atomic primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_GCC_ATOMIC__H__
 | 
			
		||||
#define __METAL_GCC_ATOMIC__H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef int atomic_flag;
 | 
			
		||||
typedef char atomic_char;
 | 
			
		||||
typedef unsigned char atomic_uchar;
 | 
			
		||||
typedef short atomic_short;
 | 
			
		||||
typedef unsigned short atomic_ushort;
 | 
			
		||||
typedef int atomic_int;
 | 
			
		||||
typedef unsigned int atomic_uint;
 | 
			
		||||
typedef long atomic_long;
 | 
			
		||||
typedef unsigned long atomic_ulong;
 | 
			
		||||
typedef long long atomic_llong;
 | 
			
		||||
typedef unsigned long long atomic_ullong;
 | 
			
		||||
 | 
			
		||||
#define ATOMIC_FLAG_INIT	0
 | 
			
		||||
#define ATOMIC_VAR_INIT(VAL)	(VAL)
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
	memory_order_relaxed,
 | 
			
		||||
	memory_order_consume,
 | 
			
		||||
	memory_order_acquire,
 | 
			
		||||
	memory_order_release,
 | 
			
		||||
	memory_order_acq_rel,
 | 
			
		||||
	memory_order_seq_cst,
 | 
			
		||||
} memory_order;
 | 
			
		||||
 | 
			
		||||
#define atomic_flag_test_and_set(FLAG)					\
 | 
			
		||||
	__sync_lock_test_and_set((FLAG), 1)
 | 
			
		||||
#define atomic_flag_test_and_set_explicit(FLAG, MO)			\
 | 
			
		||||
	atomic_flag_test_and_set(FLAG)
 | 
			
		||||
#define atomic_flag_clear(FLAG)						\
 | 
			
		||||
	__sync_lock_release((FLAG))
 | 
			
		||||
#define atomic_flag_clear_explicit(FLAG, MO)				\
 | 
			
		||||
	atomic_flag_clear(FLAG)
 | 
			
		||||
#define atomic_init(OBJ, VAL)						\
 | 
			
		||||
	do { *(OBJ) = (VAL); } while (0)
 | 
			
		||||
#define atomic_is_lock_free(OBJ)					\
 | 
			
		||||
	(sizeof(*(OBJ)) <= sizeof(long))
 | 
			
		||||
#define atomic_store(OBJ, VAL)						\
 | 
			
		||||
	do { *(OBJ) = (VAL); __sync_synchronize(); } while (0)
 | 
			
		||||
#define atomic_store_explicit(OBJ, VAL, MO)				\
 | 
			
		||||
	atomic_store((OBJ), (VAL))
 | 
			
		||||
#define atomic_load(OBJ)						\
 | 
			
		||||
	({ __sync_synchronize(); *(OBJ); })
 | 
			
		||||
#define atomic_load_explicit(OBJ, MO)					\
 | 
			
		||||
	atomic_load(OBJ)
 | 
			
		||||
#define atomic_exchange(OBJ, DES)					\
 | 
			
		||||
	({								\
 | 
			
		||||
		typeof(OBJ) obj = (OBJ);				\
 | 
			
		||||
		typeof(*obj) des = (DES);				\
 | 
			
		||||
		typeof(*obj) expval;					\
 | 
			
		||||
		typeof(*obj) oldval = atomic_load(obj);			\
 | 
			
		||||
		do {							\
 | 
			
		||||
			expval = oldval;				\
 | 
			
		||||
			oldval = __sync_val_compare_and_swap(		\
 | 
			
		||||
				obj, expval, des);			\
 | 
			
		||||
		} while (oldval != expval);				\
 | 
			
		||||
		oldval;							\
 | 
			
		||||
	})
 | 
			
		||||
#define atomic_exchange_explicit(OBJ, DES, MO)				\
 | 
			
		||||
	atomic_exchange((OBJ), (DES))
 | 
			
		||||
#define atomic_compare_exchange_strong(OBJ, EXP, DES)			\
 | 
			
		||||
	({								\
 | 
			
		||||
		typeof(OBJ) obj = (OBJ);				\
 | 
			
		||||
		typeof(EXP) exp = (EXP);				\
 | 
			
		||||
		typeof(*obj) expval = *exp;				\
 | 
			
		||||
		typeof(*obj) oldval = __sync_val_compare_and_swap(	\
 | 
			
		||||
			obj, expval, (DES));				\
 | 
			
		||||
		*exp = oldval;						\
 | 
			
		||||
		oldval == expval;					\
 | 
			
		||||
	})
 | 
			
		||||
#define atomic_compare_exchange_strong_explicit(OBJ, EXP, DES, MO)	\
 | 
			
		||||
	atomic_compare_exchange_strong((OBJ), (EXP), (DES))
 | 
			
		||||
#define atomic_compare_exchange_weak(OBJ, EXP, DES)			\
 | 
			
		||||
	atomic_compare_exchange_strong((OBJ), (EXP), (DES))
 | 
			
		||||
#define atomic_compare_exchange_weak_explicit(OBJ, EXP, DES, MO)	\
 | 
			
		||||
	atomic_compare_exchange_weak((OBJ), (EXP), (DES))
 | 
			
		||||
#define atomic_fetch_add(OBJ, VAL)					\
 | 
			
		||||
	__sync_fetch_and_add((OBJ), (VAL))
 | 
			
		||||
#define atomic_fetch_add_explicit(OBJ, VAL, MO)				\
 | 
			
		||||
	atomic_fetch_add((OBJ), (VAL))
 | 
			
		||||
#define atomic_fetch_sub(OBJ, VAL)					\
 | 
			
		||||
	__sync_fetch_and_sub((OBJ), (VAL))
 | 
			
		||||
#define atomic_fetch_sub_explicit(OBJ, VAL, MO)				\
 | 
			
		||||
	atomic_fetch_sub((OBJ), (VAL))
 | 
			
		||||
#define atomic_fetch_or(OBJ, VAL)					\
 | 
			
		||||
	__sync_fetch_and_or((OBJ), (VAL))
 | 
			
		||||
#define atomic_fetch_or_explicit(OBJ, VAL, MO)				\
 | 
			
		||||
	atomic_fetch_or((OBJ), (VAL))
 | 
			
		||||
#define atomic_fetch_xor(OBJ, VAL)					\
 | 
			
		||||
	__sync_fetch_and_xor((OBJ), (VAL))
 | 
			
		||||
#define atomic_fetch_xor_explicit(OBJ, VAL, MO)				\
 | 
			
		||||
	atomic_fetch_xor((OBJ), (VAL))
 | 
			
		||||
#define atomic_fetch_and(OBJ, VAL)					\
 | 
			
		||||
	__sync_fetch_and_and((OBJ), (VAL))
 | 
			
		||||
#define atomic_fetch_and_explicit(OBJ, VAL, MO)				\
 | 
			
		||||
	atomic_fetch_and((OBJ), (VAL))
 | 
			
		||||
#define atomic_thread_fence(MO)						\
 | 
			
		||||
	__sync_synchronize()
 | 
			
		||||
#define atomic_signal_fence(MO)						\
 | 
			
		||||
	__sync_synchronize()
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_GCC_ATOMIC__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	gcc/compiler.h
 | 
			
		||||
 * @brief	GCC specific primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_GCC_COMPILER__H__
 | 
			
		||||
#define __METAL_GCC_COMPILER__H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define restrict __restrict__
 | 
			
		||||
#define metal_align(n) __attribute__((aligned(n)))
 | 
			
		||||
#define metal_weak __attribute__((weak))
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_GCC_COMPILER__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,73 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	condition.h
 | 
			
		||||
 * @brief	Condition variable for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_CONDITION__H__
 | 
			
		||||
#define __METAL_CONDITION__H__
 | 
			
		||||
 | 
			
		||||
#include <metal/mutex.h>
 | 
			
		||||
#include <metal/utilities.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup condition Condition Variable Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
/** Opaque libmetal condition variable data structure. */
 | 
			
		||||
struct metal_condition;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief        Initialize a libmetal condition variable.
 | 
			
		||||
 * @param[in]	 cv	condition variable to initialize.
 | 
			
		||||
 */
 | 
			
		||||
static inline void metal_condition_init(struct metal_condition *cv);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief        Notify one waiter.
 | 
			
		||||
 *               Before calling this function, the caller
 | 
			
		||||
 *               should have acquired the mutex.
 | 
			
		||||
 * @param[in]    cv    condition variable
 | 
			
		||||
 * @return       zero on no errors, non-zero on errors
 | 
			
		||||
 * @see metal_condition_wait, metal_condition_broadcast
 | 
			
		||||
 */
 | 
			
		||||
static inline int metal_condition_signal(struct metal_condition *cv);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief        Notify all waiters.
 | 
			
		||||
 *               Before calling this function, the caller
 | 
			
		||||
 *               should have acquired the mutex.
 | 
			
		||||
 * @param[in]    cv    condition variable
 | 
			
		||||
 * @return       zero on no errors, non-zero on errors
 | 
			
		||||
 * @see metal_condition_wait, metal_condition_signal
 | 
			
		||||
 */
 | 
			
		||||
static inline int metal_condition_broadcast(struct metal_condition *cv);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief        Block until the condition variable is notified.
 | 
			
		||||
 *               Before calling this function, the caller should
 | 
			
		||||
 *               have acquired the mutex.
 | 
			
		||||
 * @param[in]    cv    condition variable
 | 
			
		||||
 * @param[in]    m     mutex
 | 
			
		||||
 * @return	 0 on success, non-zero on failure.
 | 
			
		||||
 * @see metal_condition_signal
 | 
			
		||||
 */
 | 
			
		||||
int metal_condition_wait(struct metal_condition *cv, metal_mutex_t *m);
 | 
			
		||||
 | 
			
		||||
#include <metal/system/xizi/condition.h>
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_CONDITION__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	config.h
 | 
			
		||||
 * @brief	Generated configuration settings for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_CONFIG__H__
 | 
			
		||||
#define __METAL_CONFIG__H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** Library major version number. */
 | 
			
		||||
#define METAL_VER_MAJOR		0
 | 
			
		||||
 | 
			
		||||
/** Library minor version number. */
 | 
			
		||||
#define METAL_VER_MINOR		1
 | 
			
		||||
 | 
			
		||||
/** Library patch level. */
 | 
			
		||||
#define METAL_VER_PATCH		0
 | 
			
		||||
 | 
			
		||||
/** Library version string. */
 | 
			
		||||
#define METAL_VER		"0.1.0"
 | 
			
		||||
 | 
			
		||||
/** System type (linux, generic, ...). */
 | 
			
		||||
#define METAL_SYSTEM		"xizi"
 | 
			
		||||
#define METAL_SYSTEM_FREERTOS
 | 
			
		||||
 | 
			
		||||
/** Processor type (arm, x86_64, ...). */
 | 
			
		||||
#define METAL_PROCESSOR		"arm"
 | 
			
		||||
#define METAL_PROCESSOR_ARM
 | 
			
		||||
 | 
			
		||||
/** Machine type (zynq, zynqmp, ...). */
 | 
			
		||||
#define METAL_MACHINE		"generic"
 | 
			
		||||
#define METAL_MACHINE_GENERIC
 | 
			
		||||
 | 
			
		||||
#if !defined(__CC_ARM)
 | 
			
		||||
#define HAVE_STDATOMIC_H
 | 
			
		||||
#endif
 | 
			
		||||
#if (defined(__GNUC__) && !defined(__CC_ARM__)) || !defined(__ICCARM__)
 | 
			
		||||
#define HAVE_FUTEX_H
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_CONFIG__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	cpu.h
 | 
			
		||||
 * @brief	CPU primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_CPU__H__
 | 
			
		||||
#define __METAL_CPU__H__
 | 
			
		||||
 | 
			
		||||
# include <metal/processor/arm/cpu.h>
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_CPU__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,176 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	device.h
 | 
			
		||||
 * @brief	Bus abstraction for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_BUS__H__
 | 
			
		||||
#define __METAL_BUS__H__
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <metal/io.h>
 | 
			
		||||
#include <metal/list.h>
 | 
			
		||||
#include <metal/dma.h>
 | 
			
		||||
#include <metal/sys.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup device Bus Abstraction
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
#ifndef METAL_MAX_DEVICE_REGIONS
 | 
			
		||||
#define METAL_MAX_DEVICE_REGIONS	32
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct metal_bus;
 | 
			
		||||
struct metal_device;
 | 
			
		||||
 | 
			
		||||
/** Bus operations. */
 | 
			
		||||
struct metal_bus_ops {
 | 
			
		||||
	void		(*bus_close)(struct metal_bus *bus);
 | 
			
		||||
	int		(*dev_open)(struct metal_bus *bus,
 | 
			
		||||
				    const char *dev_name,
 | 
			
		||||
				    struct metal_device **device);
 | 
			
		||||
	void		(*dev_close)(struct metal_bus *bus,
 | 
			
		||||
				     struct metal_device *device);
 | 
			
		||||
	void		(*dev_irq_ack)(struct metal_bus *bus,
 | 
			
		||||
				     struct metal_device *device,
 | 
			
		||||
				     int irq);
 | 
			
		||||
	int		(*dev_dma_map)(struct metal_bus *bus,
 | 
			
		||||
				       struct metal_device *device,
 | 
			
		||||
				       uint32_t dir,
 | 
			
		||||
				       struct metal_sg *sg_in,
 | 
			
		||||
				       int nents_in,
 | 
			
		||||
				       struct metal_sg *sg_out);
 | 
			
		||||
	void		(*dev_dma_unmap)(struct metal_bus *bus,
 | 
			
		||||
				       struct metal_device *device,
 | 
			
		||||
				       uint32_t dir,
 | 
			
		||||
				       struct metal_sg *sg,
 | 
			
		||||
				       int nents);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Libmetal bus structure. */
 | 
			
		||||
struct metal_bus {
 | 
			
		||||
	const char		*name;
 | 
			
		||||
	struct metal_bus_ops	ops;
 | 
			
		||||
	struct metal_list	devices;
 | 
			
		||||
	struct metal_list	node;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Libmetal generic bus. */
 | 
			
		||||
extern struct metal_bus metal_generic_bus;
 | 
			
		||||
 | 
			
		||||
/** Libmetal device structure. */
 | 
			
		||||
struct metal_device {
 | 
			
		||||
	const char             *name;       /**< Device name */
 | 
			
		||||
	struct metal_bus       *bus;        /**< Bus that contains device */
 | 
			
		||||
	unsigned               num_regions; /**< Number of I/O regions in
 | 
			
		||||
					      device */
 | 
			
		||||
	struct metal_io_region regions[METAL_MAX_DEVICE_REGIONS]; /**< Array of
 | 
			
		||||
                                                        I/O regions in device*/
 | 
			
		||||
	struct metal_list      node;       /**< Node on bus' list of devices */
 | 
			
		||||
	int                    irq_num;    /**< Number of IRQs per device */
 | 
			
		||||
	void                   *irq_info;  /**< IRQ ID */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Register a libmetal bus.
 | 
			
		||||
 * @param[in]	bus	Pre-initialized bus structure.
 | 
			
		||||
 * @return 0 on success, or -errno on failure.
 | 
			
		||||
 */
 | 
			
		||||
extern int metal_bus_register(struct metal_bus *bus);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Unregister a libmetal bus.
 | 
			
		||||
 * @param[in]	bus	Pre-registered bus structure.
 | 
			
		||||
 * @return 0 on success, or -errno on failure.
 | 
			
		||||
 */
 | 
			
		||||
extern int metal_bus_unregister(struct metal_bus *bus);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Find a libmetal bus by name.
 | 
			
		||||
 * @param[in]	name	Bus name.
 | 
			
		||||
 * @param[out]	bus	Returned bus handle.
 | 
			
		||||
 * @return 0 on success, or -errno on failure.
 | 
			
		||||
 */
 | 
			
		||||
extern int metal_bus_find(const char *name, struct metal_bus **bus);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Statically register a generic libmetal device.
 | 
			
		||||
 *
 | 
			
		||||
 * In non-Linux systems, devices are always required to be statically
 | 
			
		||||
 * registered at application initialization.
 | 
			
		||||
 * In Linux system, devices can be dynamically opened via sysfs or libfdt based
 | 
			
		||||
 * enumeration at runtime.
 | 
			
		||||
 * This interface is used for static registration of devices. Subsequent calls
 | 
			
		||||
 * to metal_device_open() look up in this list of pre-registered devices on the
 | 
			
		||||
 * "generic" bus.
 | 
			
		||||
 * "generic" bus is used on non-Linux system to group the memory mapped devices.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]	device	Generic device.
 | 
			
		||||
 * @return 0 on success, or -errno on failure.
 | 
			
		||||
 */
 | 
			
		||||
extern int metal_register_generic_device(struct metal_device *device);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Open a libmetal device by name.
 | 
			
		||||
 * @param[in]	bus_name	Bus name.
 | 
			
		||||
 * @param[in]	dev_name	Device name.
 | 
			
		||||
 * @param[out]	device		Returned device handle.
 | 
			
		||||
 * @return 0 on success, or -errno on failure.
 | 
			
		||||
 */
 | 
			
		||||
extern int metal_device_open(const char *bus_name, const char *dev_name,
 | 
			
		||||
			     struct metal_device **device);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Close a libmetal device.
 | 
			
		||||
 * @param[in]	device		Device handle.
 | 
			
		||||
 */
 | 
			
		||||
extern void metal_device_close(struct metal_device *device);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Get an I/O region accessor for a device region.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]	device		Device handle.
 | 
			
		||||
 * @param[in]	index		Region index.
 | 
			
		||||
 * @return I/O accessor handle, or NULL on failure.
 | 
			
		||||
 */
 | 
			
		||||
static inline struct metal_io_region *
 | 
			
		||||
metal_device_io_region(struct metal_device *device, unsigned index)
 | 
			
		||||
{
 | 
			
		||||
	return (index < device->num_regions
 | 
			
		||||
		? &device->regions[index]
 | 
			
		||||
		: NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef METAL_INTERNAL
 | 
			
		||||
extern int metal_generic_dev_sys_open(struct metal_device *dev);
 | 
			
		||||
extern int metal_generic_dev_open(struct metal_bus *bus, const char *dev_name,
 | 
			
		||||
				  struct metal_device **device);
 | 
			
		||||
extern int metal_generic_dev_dma_map(struct metal_bus *bus,
 | 
			
		||||
				     struct metal_device *device,
 | 
			
		||||
				     uint32_t dir,
 | 
			
		||||
				     struct metal_sg *sg_in,
 | 
			
		||||
				     int nents_in,
 | 
			
		||||
				     struct metal_sg *sg_out);
 | 
			
		||||
extern void metal_generic_dev_dma_unmap(struct metal_bus *bus,
 | 
			
		||||
					struct metal_device *device,
 | 
			
		||||
					uint32_t dir,
 | 
			
		||||
					struct metal_sg *sg,
 | 
			
		||||
					int nents);
 | 
			
		||||
#endif /* METAL_INTERNAL */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_BUS__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,79 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	dma.h
 | 
			
		||||
 * @brief	DMA primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_DMA__H__
 | 
			
		||||
#define __METAL_DMA__H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup dma DMA Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <metal/sys.h>
 | 
			
		||||
 | 
			
		||||
#define METAL_DMA_DEV_R  1 /**< DMA direction, device read */
 | 
			
		||||
#define METAL_DMA_DEV_W  2 /**< DMA direction, device write */
 | 
			
		||||
#define METAL_DMA_DEV_WR 3 /**< DMA direction, device read/write */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief scatter/gather list element structure
 | 
			
		||||
 */
 | 
			
		||||
struct metal_sg {
 | 
			
		||||
	void *virt; /**< CPU virtual address */
 | 
			
		||||
	struct metal_io_region *io; /**< IO region */
 | 
			
		||||
	int len; /**< length */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct metal_device;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief      Map memory for DMA transaction.
 | 
			
		||||
 *             After the memory is DMA mapped, the memory should be
 | 
			
		||||
 *             accessed by the DMA device but not the CPU.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  dev       DMA device
 | 
			
		||||
 * @param[in]  dir       DMA direction
 | 
			
		||||
 * @param[in]  sg_in     sg list of memory to map
 | 
			
		||||
 * @param[in]  nents_in  number of sg list entries of memory to map
 | 
			
		||||
 * @param[out] sg_out    sg list of mapped memory
 | 
			
		||||
 * @return     number of mapped sg entries, -error on failure.
 | 
			
		||||
 */
 | 
			
		||||
int metal_dma_map(struct metal_device *dev,
 | 
			
		||||
		  uint32_t dir,
 | 
			
		||||
		  struct metal_sg *sg_in,
 | 
			
		||||
		  int nents_in,
 | 
			
		||||
		  struct metal_sg *sg_out);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief      Unmap DMA memory
 | 
			
		||||
 *             After the memory is DMA unmapped, the memory should
 | 
			
		||||
 *             be accessed by the CPU but not the DMA device.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  dev       DMA device
 | 
			
		||||
 * @param[in]  dir       DMA direction
 | 
			
		||||
 * @param[in]  sg        sg list of mapped DMA memory
 | 
			
		||||
 * @param[in]  nents     number of sg list entries of DMA memory
 | 
			
		||||
 */
 | 
			
		||||
void metal_dma_unmap(struct metal_device *dev,
 | 
			
		||||
		  uint32_t dir,
 | 
			
		||||
		  struct metal_sg *sg,
 | 
			
		||||
		  int nents);
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_DMA__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2019, eForce.Co.Ltd
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	errno.h
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_ERRNO__H__
 | 
			
		||||
#define __METAL_ERRNO__H__
 | 
			
		||||
 | 
			
		||||
#if defined(__CC_ARM) && defined(__GNUC__)
 | 
			
		||||
# include <metal/compiler/armcc/errno.h>
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
# include <sys/errno.h>
 | 
			
		||||
#elif defined(__ICCARM__)
 | 
			
		||||
# include <metal/compiler/iar/errno.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_ERRNO_H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,354 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015 - 2017, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	io.h
 | 
			
		||||
 * @brief	I/O access primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_IO__H__
 | 
			
		||||
#define __METAL_IO__H__
 | 
			
		||||
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <metal/assert.h>
 | 
			
		||||
#include <metal/compiler.h>
 | 
			
		||||
#include <metal/atomic.h>
 | 
			
		||||
#include <metal/sys.h>
 | 
			
		||||
#include <metal/cpu.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup io IO Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
#ifdef __MICROBLAZE__
 | 
			
		||||
#define NO_ATOMIC_64_SUPPORT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct metal_io_region;
 | 
			
		||||
 | 
			
		||||
/** Generic I/O operations. */
 | 
			
		||||
struct metal_io_ops {
 | 
			
		||||
	uint64_t	(*read)(struct metal_io_region *io,
 | 
			
		||||
				unsigned long offset,
 | 
			
		||||
				memory_order order,
 | 
			
		||||
				int width);
 | 
			
		||||
	void		(*write)(struct metal_io_region *io,
 | 
			
		||||
				 unsigned long offset,
 | 
			
		||||
				 uint64_t value,
 | 
			
		||||
				 memory_order order,
 | 
			
		||||
				 int width);
 | 
			
		||||
	int		(*block_read)(struct metal_io_region *io,
 | 
			
		||||
				unsigned long offset,
 | 
			
		||||
				void *restrict dst,
 | 
			
		||||
				memory_order order,
 | 
			
		||||
				int len);
 | 
			
		||||
	int		(*block_write)(struct metal_io_region *io,
 | 
			
		||||
				 unsigned long offset,
 | 
			
		||||
				 const void *restrict src,
 | 
			
		||||
				 memory_order order,
 | 
			
		||||
				 int len);
 | 
			
		||||
	void		(*block_set)(struct metal_io_region *io,
 | 
			
		||||
				 unsigned long offset,
 | 
			
		||||
				 unsigned char value,
 | 
			
		||||
				 memory_order order,
 | 
			
		||||
				 int len);
 | 
			
		||||
	void		(*close)(struct metal_io_region *io);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Libmetal I/O region structure. */
 | 
			
		||||
struct metal_io_region {
 | 
			
		||||
	void			*virt;      /**< base virtual address */
 | 
			
		||||
	const metal_phys_addr_t	*physmap;   /**< table of base physical address
 | 
			
		||||
                                                 of each of the pages in the I/O
 | 
			
		||||
                                                 region */
 | 
			
		||||
	size_t			size;       /**< size of the I/O region */
 | 
			
		||||
	unsigned long		page_shift; /**< page shift of I/O region */
 | 
			
		||||
	metal_phys_addr_t	page_mask;  /**< page mask of I/O region */
 | 
			
		||||
	unsigned int		mem_flags;  /**< memory attribute of the
 | 
			
		||||
						 I/O region */
 | 
			
		||||
	struct metal_io_ops	ops;        /**< I/O region operations */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Open a libmetal I/O region.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in, out]	io		I/O region handle.
 | 
			
		||||
 * @param[in]		virt		Virtual address of region.
 | 
			
		||||
 * @param[in]		physmap		Array of physical addresses per page.
 | 
			
		||||
 * @param[in]		size		Size of region.
 | 
			
		||||
 * @param[in]		page_shift	Log2 of page size (-1 for single page).
 | 
			
		||||
 * @param[in]		mem_flags	Memory flags
 | 
			
		||||
 * @param[in]		ops			ops
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
metal_io_init(struct metal_io_region *io, void *virt,
 | 
			
		||||
	      const metal_phys_addr_t *physmap, size_t size,
 | 
			
		||||
	      unsigned page_shift, unsigned int mem_flags,
 | 
			
		||||
	      const struct metal_io_ops *ops);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Close a libmetal shared memory segment.
 | 
			
		||||
 * @param[in]	io	I/O region handle.
 | 
			
		||||
 */
 | 
			
		||||
static inline void metal_io_finish(struct metal_io_region *io)
 | 
			
		||||
{
 | 
			
		||||
	if (io->ops.close)
 | 
			
		||||
		(*io->ops.close)(io);
 | 
			
		||||
	memset(io, 0, sizeof(*io));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Get size of I/O region.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]	io	I/O region handle.
 | 
			
		||||
 * @return	Size of I/O region.
 | 
			
		||||
 */
 | 
			
		||||
static inline size_t metal_io_region_size(struct metal_io_region *io)
 | 
			
		||||
{
 | 
			
		||||
	return io->size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Get virtual address for a given offset into the I/O region.
 | 
			
		||||
 * @param[in]	io	I/O region handle.
 | 
			
		||||
 * @param[in]	offset	Offset into shared memory segment.
 | 
			
		||||
 * @return	NULL if offset is out of range, or pointer to offset.
 | 
			
		||||
 */
 | 
			
		||||
static inline void *
 | 
			
		||||
metal_io_virt(struct metal_io_region *io, unsigned long offset)
 | 
			
		||||
{
 | 
			
		||||
	return (io->virt != METAL_BAD_VA && offset <= io->size
 | 
			
		||||
		? (uint8_t *)io->virt + offset
 | 
			
		||||
		: NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Convert a virtual address to offset within I/O region.
 | 
			
		||||
 * @param[in]	io	I/O region handle.
 | 
			
		||||
 * @param[in]	virt	Virtual address within segment.
 | 
			
		||||
 * @return	METAL_BAD_OFFSET if out of range, or offset.
 | 
			
		||||
 */
 | 
			
		||||
static inline unsigned long
 | 
			
		||||
metal_io_virt_to_offset(struct metal_io_region *io, void *virt)
 | 
			
		||||
{
 | 
			
		||||
	size_t offset = (uint8_t *)virt - (uint8_t *)io->virt;
 | 
			
		||||
	return (offset < io->size ? offset : METAL_BAD_OFFSET);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Get physical address for a given offset into the I/O region.
 | 
			
		||||
 * @param[in]	io	I/O region handle.
 | 
			
		||||
 * @param[in]	offset	Offset into shared memory segment.
 | 
			
		||||
 * @return	METAL_BAD_PHYS if offset is out of range, or physical address
 | 
			
		||||
 *		of offset.
 | 
			
		||||
 */
 | 
			
		||||
static inline metal_phys_addr_t
 | 
			
		||||
metal_io_phys(struct metal_io_region *io, unsigned long offset)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long page = (io->page_shift >=
 | 
			
		||||
			     sizeof(offset) * CHAR_BIT ?
 | 
			
		||||
			     0 : offset >> io->page_shift);
 | 
			
		||||
	return (io->physmap != NULL && offset <= io->size
 | 
			
		||||
		? io->physmap[page] + (offset & io->page_mask)
 | 
			
		||||
		: METAL_BAD_PHYS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Convert a physical address to offset within I/O region.
 | 
			
		||||
 * @param[in]	io	I/O region handle.
 | 
			
		||||
 * @param[in]	phys	Physical address within segment.
 | 
			
		||||
 * @return	METAL_BAD_OFFSET if out of range, or offset.
 | 
			
		||||
 */
 | 
			
		||||
static inline unsigned long
 | 
			
		||||
metal_io_phys_to_offset(struct metal_io_region *io, metal_phys_addr_t phys)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long offset =
 | 
			
		||||
		(io->page_mask == (metal_phys_addr_t)(-1) ?
 | 
			
		||||
		phys - io->physmap[0] :  phys & io->page_mask);
 | 
			
		||||
	do {
 | 
			
		||||
		if (metal_io_phys(io, offset) == phys)
 | 
			
		||||
			return offset;
 | 
			
		||||
		offset += io->page_mask + 1;
 | 
			
		||||
	} while (offset < io->size);
 | 
			
		||||
	return METAL_BAD_OFFSET;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Convert a physical address to virtual address.
 | 
			
		||||
 * @param[in]	io	Shared memory segment handle.
 | 
			
		||||
 * @param[in]	phys	Physical address within segment.
 | 
			
		||||
 * @return	NULL if out of range, or corresponding virtual address.
 | 
			
		||||
 */
 | 
			
		||||
static inline void *
 | 
			
		||||
metal_io_phys_to_virt(struct metal_io_region *io, metal_phys_addr_t phys)
 | 
			
		||||
{
 | 
			
		||||
	return metal_io_virt(io, metal_io_phys_to_offset(io, phys));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Convert a virtual address to physical address.
 | 
			
		||||
 * @param[in]	io	Shared memory segment handle.
 | 
			
		||||
 * @param[in]	virt	Virtual address within segment.
 | 
			
		||||
 * @return	METAL_BAD_PHYS if out of range, or corresponding
 | 
			
		||||
 *		physical address.
 | 
			
		||||
 */
 | 
			
		||||
static inline metal_phys_addr_t
 | 
			
		||||
metal_io_virt_to_phys(struct metal_io_region *io, void *virt)
 | 
			
		||||
{
 | 
			
		||||
	return metal_io_phys(io, metal_io_virt_to_offset(io, virt));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Read a value from an I/O region.
 | 
			
		||||
 * @param[in]	io	I/O region handle.
 | 
			
		||||
 * @param[in]	offset	Offset into I/O region.
 | 
			
		||||
 * @param[in]	order	Memory ordering.
 | 
			
		||||
 * @param[in]	width	Width in bytes of datatype to read.  This must be 1, 2,
 | 
			
		||||
 *			4, or 8, and a compile time constant for this function
 | 
			
		||||
 *			to inline cleanly.
 | 
			
		||||
 * @return	Value.
 | 
			
		||||
 */
 | 
			
		||||
static inline uint64_t
 | 
			
		||||
metal_io_read(struct metal_io_region *io, unsigned long offset,
 | 
			
		||||
	      memory_order order, int width)
 | 
			
		||||
{
 | 
			
		||||
	void *ptr = metal_io_virt(io, offset);
 | 
			
		||||
 | 
			
		||||
	if (io->ops.read)
 | 
			
		||||
		return (*io->ops.read)(io, offset, order, width);
 | 
			
		||||
	else if (ptr && sizeof(atomic_uchar) == width)
 | 
			
		||||
		return atomic_load_explicit((atomic_uchar *)ptr, order);
 | 
			
		||||
	else if (ptr && sizeof(atomic_ushort) == width)
 | 
			
		||||
		return atomic_load_explicit((atomic_ushort *)ptr, order);
 | 
			
		||||
	else if (ptr && sizeof(atomic_uint) == width)
 | 
			
		||||
		return atomic_load_explicit((atomic_uint *)ptr, order);
 | 
			
		||||
	else if (ptr && sizeof(atomic_ulong) == width)
 | 
			
		||||
		return atomic_load_explicit((atomic_ulong *)ptr, order);
 | 
			
		||||
#ifndef NO_ATOMIC_64_SUPPORT
 | 
			
		||||
	else if (ptr && sizeof(atomic_ullong) == width)
 | 
			
		||||
		return atomic_load_explicit((atomic_ullong *)ptr, order);
 | 
			
		||||
#endif
 | 
			
		||||
	metal_assert(0);
 | 
			
		||||
	return 0; /* quiet compiler */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Write a value into an I/O region.
 | 
			
		||||
 * @param[in]	io	I/O region handle.
 | 
			
		||||
 * @param[in]	offset	Offset into I/O region.
 | 
			
		||||
 * @param[in]	value	Value to write.
 | 
			
		||||
 * @param[in]	order	Memory ordering.
 | 
			
		||||
 * @param[in]	width	Width in bytes of datatype to read.  This must be 1, 2,
 | 
			
		||||
 *			4, or 8, and a compile time constant for this function
 | 
			
		||||
 *			to inline cleanly.
 | 
			
		||||
 */
 | 
			
		||||
static inline void
 | 
			
		||||
metal_io_write(struct metal_io_region *io, unsigned long offset,
 | 
			
		||||
	       uint64_t value, memory_order order, int width)
 | 
			
		||||
{
 | 
			
		||||
	void *ptr = metal_io_virt(io, offset);
 | 
			
		||||
	if (io->ops.write)
 | 
			
		||||
		(*io->ops.write)(io, offset, value, order, width);
 | 
			
		||||
	else if (ptr && sizeof(atomic_uchar) == width)
 | 
			
		||||
		atomic_store_explicit((atomic_uchar *)ptr, value, order);
 | 
			
		||||
	else if (ptr && sizeof(atomic_ushort) == width)
 | 
			
		||||
		atomic_store_explicit((atomic_ushort *)ptr, value, order);
 | 
			
		||||
	else if (ptr && sizeof(atomic_uint) == width)
 | 
			
		||||
		atomic_store_explicit((atomic_uint *)ptr, value, order);
 | 
			
		||||
	else if (ptr && sizeof(atomic_ulong) == width)
 | 
			
		||||
		atomic_store_explicit((atomic_ulong *)ptr, value, order);
 | 
			
		||||
#ifndef NO_ATOMIC_64_SUPPORT
 | 
			
		||||
	else if (ptr && sizeof(atomic_ullong) == width)
 | 
			
		||||
		atomic_store_explicit((atomic_ullong *)ptr, value, order);
 | 
			
		||||
#endif
 | 
			
		||||
	else
 | 
			
		||||
		metal_assert (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define metal_io_read8_explicit(_io, _ofs, _order)			\
 | 
			
		||||
	metal_io_read((_io), (_ofs), (_order), 1)
 | 
			
		||||
#define metal_io_read8(_io, _ofs)					\
 | 
			
		||||
	metal_io_read((_io), (_ofs), memory_order_seq_cst, 1)
 | 
			
		||||
#define metal_io_write8_explicit(_io, _ofs, _val, _order)		\
 | 
			
		||||
	metal_io_write((_io), (_ofs), (_val), (_order), 1)
 | 
			
		||||
#define metal_io_write8(_io, _ofs, _val)				\
 | 
			
		||||
	metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 1)
 | 
			
		||||
 | 
			
		||||
#define metal_io_read16_explicit(_io, _ofs, _order)			\
 | 
			
		||||
	metal_io_read((_io), (_ofs), (_order), 2)
 | 
			
		||||
#define metal_io_read16(_io, _ofs)					\
 | 
			
		||||
	metal_io_read((_io), (_ofs), memory_order_seq_cst, 2)
 | 
			
		||||
#define metal_io_write16_explicit(_io, _ofs, _val, _order)		\
 | 
			
		||||
	metal_io_write((_io), (_ofs), (_val), (_order), 2)
 | 
			
		||||
#define metal_io_write16(_io, _ofs, _val)				\
 | 
			
		||||
	metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 2)
 | 
			
		||||
 | 
			
		||||
#define metal_io_read32_explicit(_io, _ofs, _order)			\
 | 
			
		||||
	metal_io_read((_io), (_ofs), (_order), 4)
 | 
			
		||||
#define metal_io_read32(_io, _ofs)					\
 | 
			
		||||
	metal_io_read((_io), (_ofs), memory_order_seq_cst, 4)
 | 
			
		||||
#define metal_io_write32_explicit(_io, _ofs, _val, _order)		\
 | 
			
		||||
	metal_io_write((_io), (_ofs), (_val), (_order), 4)
 | 
			
		||||
#define metal_io_write32(_io, _ofs, _val)				\
 | 
			
		||||
	metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 4)
 | 
			
		||||
 | 
			
		||||
#define metal_io_read64_explicit(_io, _ofs, _order)			\
 | 
			
		||||
	metal_io_read((_io), (_ofs), (_order), 8)
 | 
			
		||||
#define metal_io_read64(_io, _ofs)					\
 | 
			
		||||
	metal_io_read((_io), (_ofs), memory_order_seq_cst, 8)
 | 
			
		||||
#define metal_io_write64_explicit(_io, _ofs, _val, _order)		\
 | 
			
		||||
	metal_io_write((_io), (_ofs), (_val), (_order), 8)
 | 
			
		||||
#define metal_io_write64(_io, _ofs, _val)				\
 | 
			
		||||
	metal_io_write((_io), (_ofs), (_val), memory_order_seq_cst, 8)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Read a block from an I/O region.
 | 
			
		||||
 * @param[in]	io	I/O region handle.
 | 
			
		||||
 * @param[in]	offset	Offset into I/O region.
 | 
			
		||||
 * @param[in]	dst	destination to store the read data.
 | 
			
		||||
 * @param[in]	len	length in bytes to read.
 | 
			
		||||
 * @return      On success, number of bytes read. On failure, negative value
 | 
			
		||||
 */
 | 
			
		||||
int metal_io_block_read(struct metal_io_region *io, unsigned long offset,
 | 
			
		||||
	       void *restrict dst, int len);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Write a block into an I/O region.
 | 
			
		||||
 * @param[in]	io	I/O region handle.
 | 
			
		||||
 * @param[in]	offset	Offset into I/O region.
 | 
			
		||||
 * @param[in]	src	source to write.
 | 
			
		||||
 * @param[in]	len	length in bytes to write.
 | 
			
		||||
 * @return      On success, number of bytes written. On failure, negative value
 | 
			
		||||
 */
 | 
			
		||||
int metal_io_block_write(struct metal_io_region *io, unsigned long offset,
 | 
			
		||||
	       const void *restrict src, int len);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	fill a block of an I/O region.
 | 
			
		||||
 * @param[in]	io	I/O region handle.
 | 
			
		||||
 * @param[in]	offset	Offset into I/O region.
 | 
			
		||||
 * @param[in]	value	value to fill into the block
 | 
			
		||||
 * @param[in]	len	length in bytes to fill.
 | 
			
		||||
 * @return      On success, number of bytes filled. On failure, negative value
 | 
			
		||||
 */
 | 
			
		||||
int metal_io_block_set(struct metal_io_region *io, unsigned long offset,
 | 
			
		||||
	       unsigned char value, int len);
 | 
			
		||||
 | 
			
		||||
#include <metal/system/xizi/io.h>
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_IO__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,116 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	irq.h
 | 
			
		||||
 * @brief	Interrupt handling primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_IRQ__H__
 | 
			
		||||
#define __METAL_IRQ__H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup irq Interrupt Handling Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
/** IRQ handled status */
 | 
			
		||||
#define METAL_IRQ_NOT_HANDLED 0
 | 
			
		||||
#define METAL_IRQ_HANDLED     1
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	type of interrupt handler
 | 
			
		||||
 * @param[in]   irq interrupt id
 | 
			
		||||
 * @param[in]	priv private data
 | 
			
		||||
 * @return      irq handled status
 | 
			
		||||
 */
 | 
			
		||||
typedef int (*metal_irq_handler) (int irq, void *priv);
 | 
			
		||||
 | 
			
		||||
struct metal_device;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief      Register interrupt handler for driver ID/device.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  irq         interrupt id
 | 
			
		||||
 * @param[in]  irq_handler interrupt handler
 | 
			
		||||
 * @param[in]  dev         metal device this irq belongs to (can be NULL).
 | 
			
		||||
 * @param[in]  drv_id      driver id is a unique interrupt handler identifier.
 | 
			
		||||
 *                         It can also be used for driver data.
 | 
			
		||||
 * @return     0 for success, non-zero on failure
 | 
			
		||||
 */
 | 
			
		||||
int metal_irq_register(int irq,
 | 
			
		||||
		       metal_irq_handler irq_handler,
 | 
			
		||||
		       struct metal_device *dev,
 | 
			
		||||
		       void *drv_id);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief      Unregister interrupt handler for driver ID and/or device.
 | 
			
		||||
 *
 | 
			
		||||
 *             If interrupt handler (hd), driver ID (drv_id) and device (dev)
 | 
			
		||||
 *             are NULL, unregister all handlers for this interrupt.
 | 
			
		||||
 *
 | 
			
		||||
 *             If interrupt handler (hd), device (dev) or driver ID (drv_id),
 | 
			
		||||
 *             are not NULL, unregister handlers matching non NULL criterias.
 | 
			
		||||
 *             e.g: when call is made with drv_id and dev non NULL,
 | 
			
		||||
 *             all handlers matching both are unregistered.
 | 
			
		||||
 *
 | 
			
		||||
 *             If interrupt is not found, or other criterias not matching,
 | 
			
		||||
 *             return -ENOENT
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  irq         interrupt id
 | 
			
		||||
 * @param[in]  irq_handler interrupt handler
 | 
			
		||||
 * @param[in]  dev         metal device this irq belongs to
 | 
			
		||||
 * @param[in]  drv_id      driver id. It can be used for driver data.
 | 
			
		||||
 * @return     0 for success, non-zero on failure
 | 
			
		||||
 */
 | 
			
		||||
int metal_irq_unregister(int irq,
 | 
			
		||||
			metal_irq_handler irq_handler,
 | 
			
		||||
			struct metal_device *dev,
 | 
			
		||||
			void *drv_id);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief      disable interrupts
 | 
			
		||||
 * @return     interrupts state
 | 
			
		||||
 */
 | 
			
		||||
unsigned int metal_irq_save_disable(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief      restore interrupts to their previous state
 | 
			
		||||
 * @param[in]  flags previous interrupts state
 | 
			
		||||
 */
 | 
			
		||||
void metal_irq_restore_enable(unsigned int flags);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	metal_irq_enable
 | 
			
		||||
 *
 | 
			
		||||
 * Enables the given interrupt
 | 
			
		||||
 *
 | 
			
		||||
 * @param vector   - interrupt vector number
 | 
			
		||||
 */
 | 
			
		||||
void metal_irq_enable(unsigned int vector);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	metal_irq_disable
 | 
			
		||||
 *
 | 
			
		||||
 * Disables the given interrupt
 | 
			
		||||
 *
 | 
			
		||||
 * @param vector   - interrupt vector number
 | 
			
		||||
 */
 | 
			
		||||
void metal_irq_disable(unsigned int vector);
 | 
			
		||||
 | 
			
		||||
#include <metal/system/xizi/irq.h>
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_IRQ__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,102 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	list.h
 | 
			
		||||
 * @brief	List primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_LIST__H__
 | 
			
		||||
#define __METAL_LIST__H__
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup list List Primitives
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
struct metal_list {
 | 
			
		||||
	struct metal_list *next, *prev;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * METAL_INIT_LIST - used for initializing an list elmenet in a static struct
 | 
			
		||||
 * or global
 | 
			
		||||
 */
 | 
			
		||||
#define METAL_INIT_LIST(name) { .next = &name, .prev = &name }
 | 
			
		||||
/*
 | 
			
		||||
 * METAL_DECLARE_LIST - used for defining and initializing a global or
 | 
			
		||||
 * static singleton list
 | 
			
		||||
 */
 | 
			
		||||
#define METAL_DECLARE_LIST(name)			\
 | 
			
		||||
	struct metal_list name = METAL_INIT_LIST(name)
 | 
			
		||||
 | 
			
		||||
static inline void metal_list_init(struct metal_list *list)
 | 
			
		||||
{
 | 
			
		||||
	list->next = list->prev = list;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void metal_list_add_before(struct metal_list *node,
 | 
			
		||||
					 struct metal_list *new_node)
 | 
			
		||||
{
 | 
			
		||||
	new_node->prev = node->prev;
 | 
			
		||||
	new_node->next = node;
 | 
			
		||||
	new_node->next->prev = new_node;
 | 
			
		||||
	new_node->prev->next = new_node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void metal_list_add_after(struct metal_list *node,
 | 
			
		||||
					struct metal_list *new_node)
 | 
			
		||||
{
 | 
			
		||||
	new_node->prev = node;
 | 
			
		||||
	new_node->next = node->next;
 | 
			
		||||
	new_node->next->prev = new_node;
 | 
			
		||||
	new_node->prev->next = new_node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void metal_list_add_head(struct metal_list *list,
 | 
			
		||||
				       struct metal_list *node)
 | 
			
		||||
{
 | 
			
		||||
	metal_list_add_after(list, node);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void metal_list_add_tail(struct metal_list *list,
 | 
			
		||||
				       struct metal_list *node)
 | 
			
		||||
{
 | 
			
		||||
	metal_list_add_before(list, node);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int metal_list_is_empty(struct metal_list *list)
 | 
			
		||||
{
 | 
			
		||||
	return list->next == list;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void metal_list_del(struct metal_list *node)
 | 
			
		||||
{
 | 
			
		||||
	node->next->prev = node->prev;
 | 
			
		||||
	node->prev->next = node->next;
 | 
			
		||||
	node->next = node->prev = node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline struct metal_list *metal_list_first(struct metal_list *list)
 | 
			
		||||
{
 | 
			
		||||
	return metal_list_is_empty(list) ? NULL : list->next;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define metal_list_for_each(list, node)		\
 | 
			
		||||
	for ((node) = (list)->next;		\
 | 
			
		||||
	     (node) != (list);			\
 | 
			
		||||
	     (node) = (node)->next)
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_LIST__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,93 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	log.h
 | 
			
		||||
 * @brief	Logging support for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_METAL_LOG__H__
 | 
			
		||||
#define __METAL_METAL_LOG__H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup logging Library Logging Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
/** Log message priority levels for libmetal. */
 | 
			
		||||
enum metal_log_level {
 | 
			
		||||
	METAL_LOG_EMERGENCY,	/**< system is unusable.               */
 | 
			
		||||
	METAL_LOG_ALERT,	/**< action must be taken immediately. */
 | 
			
		||||
	METAL_LOG_CRITICAL,	/**< critical conditions.              */
 | 
			
		||||
	METAL_LOG_ERROR,	/**< error conditions.                 */
 | 
			
		||||
	METAL_LOG_WARNING,	/**< warning conditions.               */
 | 
			
		||||
	METAL_LOG_NOTICE,	/**< normal but significant condition. */
 | 
			
		||||
	METAL_LOG_INFO,		/**< informational messages.           */
 | 
			
		||||
	METAL_LOG_DEBUG,	/**< debug-level messages.             */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Log message handler type. */
 | 
			
		||||
typedef void (*metal_log_handler)(enum metal_log_level level,
 | 
			
		||||
				  const char *format, ...);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Set libmetal log handler.
 | 
			
		||||
 * @param[in]	handler	log message handler.
 | 
			
		||||
 * @return	0 on success, or -errno on failure.
 | 
			
		||||
 */
 | 
			
		||||
extern void metal_set_log_handler(metal_log_handler handler);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Get the current libmetal log handler.
 | 
			
		||||
 * @return	Current log handler.
 | 
			
		||||
 */
 | 
			
		||||
extern metal_log_handler metal_get_log_handler(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Set the level for libmetal logging.
 | 
			
		||||
 * @param[in]	level	log message level.
 | 
			
		||||
 */
 | 
			
		||||
extern void metal_set_log_level(enum metal_log_level level);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Get the current level for libmetal logging.
 | 
			
		||||
 * @return	Current log level.
 | 
			
		||||
 */
 | 
			
		||||
extern enum metal_log_level metal_get_log_level(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Default libmetal log handler.  This handler prints libmetal log
 | 
			
		||||
 *		mesages to stderr.
 | 
			
		||||
 * @param[in]	level	log message level.
 | 
			
		||||
 * @param[in]	format	log message format string.
 | 
			
		||||
 * @return	0 on success, or -errno on failure.
 | 
			
		||||
 */
 | 
			
		||||
extern void metal_default_log_handler(enum metal_log_level level,
 | 
			
		||||
				      const char *format, ...);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Emit a log message if the log level permits.
 | 
			
		||||
 *
 | 
			
		||||
 * @param	level	Log level.
 | 
			
		||||
 * @param	...	Format string and arguments.
 | 
			
		||||
 */
 | 
			
		||||
#define metal_log(level, ...)						       \
 | 
			
		||||
	((level <= _metal.common.log_level && _metal.common.log_handler) \
 | 
			
		||||
	       ? (void)_metal.common.log_handler(level, __VA_ARGS__)	       \
 | 
			
		||||
	       : (void)0)
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <metal/system/xizi/log.h>
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_METAL_LOG__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,87 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	mutex.h
 | 
			
		||||
 * @brief	Mutex primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_MUTEX__H__
 | 
			
		||||
#define __METAL_MUTEX__H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup mutex Mutex Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
#include <metal/system/xizi/mutex.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Initialize a libmetal mutex.
 | 
			
		||||
 * @param[in]	mutex	Mutex to initialize.
 | 
			
		||||
 */
 | 
			
		||||
static inline void metal_mutex_init(metal_mutex_t *mutex)
 | 
			
		||||
{
 | 
			
		||||
	__metal_mutex_init(mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Deinitialize a libmetal mutex.
 | 
			
		||||
 * @param[in]	mutex	Mutex to deinitialize.
 | 
			
		||||
 */
 | 
			
		||||
static inline void metal_mutex_deinit(metal_mutex_t *mutex)
 | 
			
		||||
{
 | 
			
		||||
	__metal_mutex_deinit(mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Try to acquire a mutex 
 | 
			
		||||
 * @param[in]	mutex	Mutex to mutex.
 | 
			
		||||
 * @return	0 on failure to acquire, non-zero on success.
 | 
			
		||||
 */
 | 
			
		||||
static inline int metal_mutex_try_acquire(metal_mutex_t *mutex)
 | 
			
		||||
{
 | 
			
		||||
	return __metal_mutex_try_acquire(mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Acquire a mutex 
 | 
			
		||||
 * @param[in]	mutex	Mutex to mutex.
 | 
			
		||||
 */
 | 
			
		||||
static inline void metal_mutex_acquire(metal_mutex_t *mutex)
 | 
			
		||||
{
 | 
			
		||||
	__metal_mutex_acquire(mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Release a previously acquired mutex.
 | 
			
		||||
 * @param[in]	mutex	Mutex to mutex.
 | 
			
		||||
 * @see metal_mutex_try_acquire, metal_mutex_acquire
 | 
			
		||||
 */
 | 
			
		||||
static inline void metal_mutex_release(metal_mutex_t *mutex)
 | 
			
		||||
{
 | 
			
		||||
	__metal_mutex_release(mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Checked if a mutex has been acquired.
 | 
			
		||||
 * @param[in]	mutex	mutex to check.
 | 
			
		||||
 * @see metal_mutex_try_acquire, metal_mutex_acquire
 | 
			
		||||
 */
 | 
			
		||||
static inline int metal_mutex_is_acquired(metal_mutex_t *mutex)
 | 
			
		||||
{
 | 
			
		||||
	return __metal_mutex_is_acquired(mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_MUTEX__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	gcc/atomic.h
 | 
			
		||||
 * @brief	GCC specific atomic primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_ARM_ATOMIC__H__
 | 
			
		||||
#define __METAL_ARM_ATOMIC__H__
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_ARM_ATOMIC__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	cpu.h
 | 
			
		||||
 * @brief	CPU specific primatives
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_ARM_CPU__H__
 | 
			
		||||
#define __METAL_ARM_CPU__H__
 | 
			
		||||
 | 
			
		||||
#include <xizi.h>
 | 
			
		||||
 | 
			
		||||
#define metal_cpu_yield() YieldOsAssign()
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_ARM_CPU__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,83 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	shmem.h
 | 
			
		||||
 * @brief	Shared memory primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_SHMEM__H__
 | 
			
		||||
#define __METAL_SHMEM__H__
 | 
			
		||||
 | 
			
		||||
#include <metal/io.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup shmem Shared Memory Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
/** Generic shared memory data structure. */
 | 
			
		||||
struct metal_generic_shmem {
 | 
			
		||||
	const char		*name;
 | 
			
		||||
	struct metal_io_region	io;
 | 
			
		||||
	struct metal_list	node;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Open a libmetal shared memory segment.
 | 
			
		||||
 *
 | 
			
		||||
 * Open a shared memory segment.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]		name	Name of segment to open.
 | 
			
		||||
 * @param[in]		size	Size of segment.
 | 
			
		||||
 * @param[out]		io	I/O region handle, if successful.
 | 
			
		||||
 * @return	0 on success, or -errno on failure.
 | 
			
		||||
 *
 | 
			
		||||
 * @see metal_shmem_create
 | 
			
		||||
 */
 | 
			
		||||
extern int metal_shmem_open(const char *name, size_t size,
 | 
			
		||||
			    struct metal_io_region **io);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Statically register a generic shared memory region.
 | 
			
		||||
 *
 | 
			
		||||
 * Shared memory regions may be statically registered at application
 | 
			
		||||
 * initialization, or may be dynamically opened.  This interface is used for
 | 
			
		||||
 * static registration of regions.  Subsequent calls to metal_shmem_open() look
 | 
			
		||||
 * up in this list of pre-registered regions.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]	shmem	Generic shmem structure.
 | 
			
		||||
 * @return 0 on success, or -errno on failure.
 | 
			
		||||
 */
 | 
			
		||||
extern int metal_shmem_register_generic(struct metal_generic_shmem *shmem);
 | 
			
		||||
 | 
			
		||||
#ifdef METAL_INTERNAL
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Open a statically registered shmem segment.
 | 
			
		||||
 *
 | 
			
		||||
 * This interface is meant for internal libmetal use within system specific
 | 
			
		||||
 * shmem implementations.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]		name	Name of segment to open.
 | 
			
		||||
 * @param[in]		size	Size of segment.
 | 
			
		||||
 * @param[out]		io	I/O region handle, if successful.
 | 
			
		||||
 * @return	0 on success, or -errno on failure.
 | 
			
		||||
 */
 | 
			
		||||
int metal_shmem_open_generic(const char *name, size_t size,
 | 
			
		||||
			     struct metal_io_region **result);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_SHMEM__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	sleep.h
 | 
			
		||||
 * @brief	Sleep primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_SLEEP__H__
 | 
			
		||||
#define __METAL_SLEEP__H__
 | 
			
		||||
 | 
			
		||||
#include <metal/system/xizi/sleep.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup sleep Sleep Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief      delay in microseconds
 | 
			
		||||
 *             delay the next execution in the calling thread
 | 
			
		||||
 *             fo usec microseconds.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]  usec      microsecond intervals
 | 
			
		||||
 * @return     0 on success, non-zero for failures
 | 
			
		||||
 */
 | 
			
		||||
static inline int metal_sleep_usec(unsigned int usec)
 | 
			
		||||
{
 | 
			
		||||
	return __metal_sleep_usec(usec);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_SLEEP__H__ */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,68 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	spinlock.h
 | 
			
		||||
 * @brief	Spinlock primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_SPINLOCK__H__
 | 
			
		||||
#define __METAL_SPINLOCK__H__
 | 
			
		||||
 | 
			
		||||
#include <metal/atomic.h>
 | 
			
		||||
#include <metal/cpu.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup spinlock Spinlock Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
struct metal_spinlock {
 | 
			
		||||
    atomic_flag v;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Static metal spinlock initialization. */
 | 
			
		||||
#define METAL_SPINLOCK_INIT		{ATOMIC_FLAG_INIT}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Initialize a libmetal spinlock.
 | 
			
		||||
 * @param[in]	slock	Spinlock to initialize.
 | 
			
		||||
 */
 | 
			
		||||
static inline void metal_spinlock_init(struct metal_spinlock *slock)
 | 
			
		||||
{
 | 
			
		||||
	atomic_flag_clear(&slock->v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Acquire a spinlock.
 | 
			
		||||
 * @param[in]	slock   Spinlock to acquire.
 | 
			
		||||
 * @see metal_spinlock_release
 | 
			
		||||
 */
 | 
			
		||||
static inline void metal_spinlock_acquire(struct metal_spinlock *slock)
 | 
			
		||||
{
 | 
			
		||||
	while (atomic_flag_test_and_set(&slock->v)) {
 | 
			
		||||
		metal_cpu_yield();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Release a previously acquired spinlock.
 | 
			
		||||
 * @param[in]	slock	Spinlock to release.
 | 
			
		||||
 * @see metal_spinlock_acquire
 | 
			
		||||
 */
 | 
			
		||||
static inline void metal_spinlock_release(struct metal_spinlock *slock)
 | 
			
		||||
{
 | 
			
		||||
	atomic_flag_clear(&slock->v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_SPINLOCK__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,148 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	sys.h
 | 
			
		||||
 * @brief	System primitives for libmetal.
 | 
			
		||||
 * @brief	Top level include internal to libmetal library code.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_SYS__H__
 | 
			
		||||
#define __METAL_SYS__H__
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include <metal/log.h>
 | 
			
		||||
#include <metal/list.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup system Top Level Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
/** Physical address type. */
 | 
			
		||||
typedef unsigned long metal_phys_addr_t;
 | 
			
		||||
 | 
			
		||||
/** Interrupt request number. */
 | 
			
		||||
typedef int metal_irq_t;
 | 
			
		||||
 | 
			
		||||
/** Bad offset into shared memory or I/O region. */
 | 
			
		||||
#define METAL_BAD_OFFSET	((unsigned long)-1)
 | 
			
		||||
 | 
			
		||||
/** Bad physical address value. */
 | 
			
		||||
#define METAL_BAD_PHYS		((metal_phys_addr_t)-1)
 | 
			
		||||
 | 
			
		||||
/** Bad virtual address value. */
 | 
			
		||||
#define METAL_BAD_VA		((void *)-1)
 | 
			
		||||
 | 
			
		||||
/** Bad IRQ. */
 | 
			
		||||
#define METAL_BAD_IRQ		((metal_irq_t)-1)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Initialization configuration for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
struct metal_init_params {
 | 
			
		||||
 | 
			
		||||
	/** log message handler (defaults to stderr). */
 | 
			
		||||
	metal_log_handler		log_handler;
 | 
			
		||||
 | 
			
		||||
	/** default log message level (defaults to emergency). */
 | 
			
		||||
	enum metal_log_level		log_level;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * System independent runtime state for libmetal.  This is part of a system
 | 
			
		||||
 * specific singleton data structure (@see _metal).
 | 
			
		||||
 */
 | 
			
		||||
struct metal_common_state {
 | 
			
		||||
	/** Current log level. */
 | 
			
		||||
	enum metal_log_level		log_level;
 | 
			
		||||
 | 
			
		||||
	/** Current log handler (null for none). */
 | 
			
		||||
	metal_log_handler		log_handler;
 | 
			
		||||
 | 
			
		||||
	/** List of registered buses. */
 | 
			
		||||
	struct metal_list		bus_list;
 | 
			
		||||
 | 
			
		||||
	/** Generic statically defined shared memory segments. */
 | 
			
		||||
	struct metal_list		generic_shmem_list;
 | 
			
		||||
 | 
			
		||||
	/** Generic statically defined devices. */
 | 
			
		||||
	struct metal_list		generic_device_list;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct metal_state;
 | 
			
		||||
 | 
			
		||||
#include <metal/system/xizi/sys.h>
 | 
			
		||||
 | 
			
		||||
#ifndef METAL_INIT_DEFAULTS
 | 
			
		||||
#define METAL_INIT_DEFAULTS				\
 | 
			
		||||
{							\
 | 
			
		||||
	.log_handler	= metal_default_log_handler,	\
 | 
			
		||||
	.log_level	= METAL_LOG_INFO,		\
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** System specific runtime data. */
 | 
			
		||||
extern struct metal_state _metal;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Initialize libmetal.
 | 
			
		||||
 *
 | 
			
		||||
 * Initialize the libmetal library.
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]	params	Initialization params (@see metal_init_params).
 | 
			
		||||
 *
 | 
			
		||||
 * @return	0 on success, or -errno on failure.
 | 
			
		||||
 *
 | 
			
		||||
 * @see metal_finish
 | 
			
		||||
 */
 | 
			
		||||
extern int metal_init(const struct metal_init_params *params);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	Shutdown libmetal.
 | 
			
		||||
 *
 | 
			
		||||
 * Shutdown the libmetal library, and release all reserved resources.
 | 
			
		||||
 *
 | 
			
		||||
 * @see metal_init
 | 
			
		||||
 */
 | 
			
		||||
extern void metal_finish(void);
 | 
			
		||||
 | 
			
		||||
#ifdef METAL_INTERNAL
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	libmetal system initialization.
 | 
			
		||||
 *
 | 
			
		||||
 * This function initializes libmetal on Linux or Generic platforms.  This
 | 
			
		||||
 * involves obtaining necessary pieces of system information (sysfs mount path,
 | 
			
		||||
 * page size, etc.).
 | 
			
		||||
 *
 | 
			
		||||
 * @param[in]	params	Initialization parameters (@see metal_init_params).
 | 
			
		||||
 * @return	0 on success, or -errno on failure.
 | 
			
		||||
 */
 | 
			
		||||
extern int metal_sys_init(const struct metal_init_params *params);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief	libmetal system shutdown.
 | 
			
		||||
 *
 | 
			
		||||
 * This function shuts down and releases resources held by libmetal Linux or
 | 
			
		||||
 * Generic platform layers.
 | 
			
		||||
 *
 | 
			
		||||
 * @see metal_sys_init
 | 
			
		||||
 */
 | 
			
		||||
extern void metal_sys_finish(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_SYS__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/alloc.c
 | 
			
		||||
 * @brief	FreeRTOS libmetal memory allocattion definitions.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_ALLOC__H__
 | 
			
		||||
#error "Include metal/alloc.h instead of metal/xizi/alloc.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_FREERTOS_ALLOC__H__
 | 
			
		||||
#define __METAL_FREERTOS_ALLOC__H__
 | 
			
		||||
 | 
			
		||||
#include <xizi.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static inline void *metal_allocate_memory(unsigned int size)
 | 
			
		||||
{
 | 
			
		||||
	return (x_malloc(size));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void metal_free_memory(void *ptr)
 | 
			
		||||
{
 | 
			
		||||
	x_free(ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_FREERTOS_ALLOC__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2018, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	assert.h
 | 
			
		||||
 * @brief	FreeRTOS assertion support.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef __METAL_ASSERT__H__
 | 
			
		||||
#error "Include metal/assert.h instead of metal/xizi/assert.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_FREERTOS_ASSERT__H__
 | 
			
		||||
#define __METAL_FREERTOS_ASSERT__H__
 | 
			
		||||
 | 
			
		||||
#ifdef double_assert
 | 
			
		||||
#error recursive2
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define double_assert
 | 
			
		||||
 | 
			
		||||
//#include </opt/arm/gcc-arm-8.2-2018.11-x86_64-arm-eabi/arm-eabi/include/assert.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#undef double_assert
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Assertion macro for FreeRTOS applications.
 | 
			
		||||
 * @param cond Condition to evaluate.
 | 
			
		||||
 */
 | 
			
		||||
#define metal_sys_assert(cond) assert(cond)
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_FREERTOS_ASSERT__H__ */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2018, Linaro Limited. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/cache.h
 | 
			
		||||
 * @brief	FreeRTOS cache operation primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_CACHE__H__
 | 
			
		||||
#error "Include metal/cache.h instead of metal/xizi/cache.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_FREERTOS_CACHE__H__
 | 
			
		||||
#define __METAL_FREERTOS_CACHE__H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern void metal_machine_cache_flush(void *addr, unsigned int len);
 | 
			
		||||
extern void metal_machine_cache_invalidate(void *addr, unsigned int len);
 | 
			
		||||
 | 
			
		||||
static inline void __metal_cache_flush(void *addr, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
	metal_machine_cache_flush(addr, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __metal_cache_invalidate(void *addr, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
	metal_machine_cache_invalidate(addr, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_FREERTOS_CACHE__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,64 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	generic/condition.h
 | 
			
		||||
 * @brief	Generic condition variable primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_CONDITION__H__
 | 
			
		||||
#error "Include metal/condition.h instead of metal/xizi/condition.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_FREERTOS_CONDITION__H__
 | 
			
		||||
#define __METAL_FREERTOS_CONDITION__H__
 | 
			
		||||
 | 
			
		||||
#include <metal/atomic.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct metal_condition {
 | 
			
		||||
	metal_mutex_t *m; /**< mutex.
 | 
			
		||||
	                       The condition variable is attached to
 | 
			
		||||
	                       this mutex when it is waiting.
 | 
			
		||||
	                       It is also used to check correctness
 | 
			
		||||
	                       in case there are multiple waiters. */
 | 
			
		||||
 | 
			
		||||
	atomic_int v; /**< condition variable value. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Static metal condition variable initialization. */
 | 
			
		||||
#define METAL_CONDITION_INIT		{ NULL, ATOMIC_VAR_INIT(0) }
 | 
			
		||||
 | 
			
		||||
static inline void metal_condition_init(struct metal_condition *cv)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO: Implement condition variable for FreeRTOS */
 | 
			
		||||
	(void)cv;
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int metal_condition_signal(struct metal_condition *cv)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO: Implement condition variable for FreeRTOS */
 | 
			
		||||
	(void)cv;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int metal_condition_broadcast(struct metal_condition *cv)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO: Implement condition variable for FreeRTOS */
 | 
			
		||||
	(void)cv;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_FREERTOS_CONDITION__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/io.h
 | 
			
		||||
 * @brief	FreeRTOS specific io definitions.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_IO__H__
 | 
			
		||||
#error "Include metal/io.h instead of metal/xizi/io.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_FREEROTS_IO__H__
 | 
			
		||||
#define __METAL_FREEROTS_IO__H__
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef METAL_INTERNAL
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief memory mapping for an I/O region
 | 
			
		||||
 */
 | 
			
		||||
void metal_sys_io_mem_map(struct metal_io_region *io);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief memory mapping
 | 
			
		||||
 */
 | 
			
		||||
void *metal_machine_io_mem_map(void *va, metal_phys_addr_t pa,
 | 
			
		||||
			       size_t size, unsigned int flags);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_FREEROTS_IO__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/irq.c
 | 
			
		||||
 * @brief	FreeRTOS libmetal irq definitions.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_IRQ__H__
 | 
			
		||||
#error "Include metal/irq.h instead of metal/xizi/irq.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_FREERTOS_IRQ__H__
 | 
			
		||||
#define __METAL_FREERTOS_IRQ__H__
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_FREERTOS_IRQ__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2018, Linaro Limited. and Contributors. All rights reserved.
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
 *    this list of conditions and the following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
 *    this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
 *    and/or other materials provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 * 3. Neither the name of Linaro nor the names of its contributors may be used
 | 
			
		||||
 *    to endorse or promote products derived from this software without
 | 
			
		||||
 *    specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | 
			
		||||
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
			
		||||
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
			
		||||
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/log.h
 | 
			
		||||
 * @brief	FreeRTOS libmetal log handler definition.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_METAL_LOG__H__
 | 
			
		||||
#error "Include metal/log.h instead of metal/xizi/log.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_FREERTOS_LOG__H__
 | 
			
		||||
#define __METAL_FREERTOS_LOG__H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_FREERTOS_LOG__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,77 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/mutex.h
 | 
			
		||||
 * @brief	FreeRTOS mutex primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_MUTEX__H__
 | 
			
		||||
#error "Include metal/mutex.h instead of metal/xizi/mutex.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_FREERTOS_MUTEX__H__
 | 
			
		||||
#define __METAL_FREERTOS_MUTEX__H__
 | 
			
		||||
 | 
			
		||||
#include <metal/atomic.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	atomic_int v;
 | 
			
		||||
} metal_mutex_t;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * METAL_MUTEX_INIT - used for initializing an mutex elmenet in a static struct
 | 
			
		||||
 * or global
 | 
			
		||||
 */
 | 
			
		||||
#define METAL_MUTEX_INIT(m)		{ ATOMIC_VAR_INIT(0) }
 | 
			
		||||
/*
 | 
			
		||||
 * METAL_MUTEX_DEFINE - used for defining and initializing a global or
 | 
			
		||||
 * static singleton mutex
 | 
			
		||||
 */
 | 
			
		||||
#define METAL_MUTEX_DEFINE(m) metal_mutex_t m = METAL_MUTEX_INIT(m)
 | 
			
		||||
 | 
			
		||||
static inline void __metal_mutex_init(metal_mutex_t *mutex)
 | 
			
		||||
{
 | 
			
		||||
	atomic_store(&mutex->v, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __metal_mutex_deinit(metal_mutex_t *mutex)
 | 
			
		||||
{
 | 
			
		||||
	(void)mutex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int __metal_mutex_try_acquire(metal_mutex_t *mutex)
 | 
			
		||||
{
 | 
			
		||||
	return 1 - atomic_flag_test_and_set(&mutex->v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __metal_mutex_acquire(metal_mutex_t *mutex)
 | 
			
		||||
{
 | 
			
		||||
	while (atomic_flag_test_and_set(&mutex->v)) {
 | 
			
		||||
		;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void __metal_mutex_release(metal_mutex_t *mutex)
 | 
			
		||||
{
 | 
			
		||||
	atomic_flag_clear(&mutex->v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int __metal_mutex_is_acquired(metal_mutex_t *mutex)
 | 
			
		||||
{
 | 
			
		||||
	return atomic_load(&mutex->v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_FREERTOS_MUTEX__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,70 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2020, eForce.Co.Ltd
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
 *    this list of conditions and the following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
 *    this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
 *    and/or other materials provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 * 3. Neither the name of Xilinx nor the names of its contributors may be used
 | 
			
		||||
 *    to endorse or promote products derived from this software without
 | 
			
		||||
 *    specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | 
			
		||||
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
			
		||||
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
			
		||||
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/rzv2/sys.h
 | 
			
		||||
 * @brief	FreeRTOS Renesas RZ/V2 system primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_FREERTOS_SYS__H__
 | 
			
		||||
#error "Include metal/sys.h instead of metal/xizi/rzv2/sys.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "bsp_api.h"
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_FREERTOS_RZV2_SYS__H__
 | 
			
		||||
#define __METAL_FREERTOS_RZV2_SYS__H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define NO_ATOMIC_64_SUPPORT
 | 
			
		||||
 | 
			
		||||
#if !defined(MAX_IRQS)
 | 
			
		||||
#define MAX_IRQS	((int)479U)          /**< maximum number of irqs */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static inline void sys_irq_enable(unsigned int vector)
 | 
			
		||||
{
 | 
			
		||||
        (void)R_BSP_IrqEnable(vector);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void sys_irq_disable(unsigned int vector)
 | 
			
		||||
{
 | 
			
		||||
        (void)R_BSP_IrqDisable(vector);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_FREERTOS_RZV2_SYS__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2018, Linaro Limited. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/sleep.h
 | 
			
		||||
 * @brief	FreeRTOS sleep primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_SLEEP__H__
 | 
			
		||||
#error "Include metal/sleep.h instead of metal/xizi/sleep.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_FREERTOS_SLEEP__H__
 | 
			
		||||
#define __METAL_FREERTOS_SLEEP__H__
 | 
			
		||||
 | 
			
		||||
#include <xizi.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static inline int __metal_sleep_usec(unsigned int usec)
 | 
			
		||||
{
 | 
			
		||||
	DelayKTask(usec);
 | 
			
		||||
	// const TickType_t xDelay = usec / portTICK_PERIOD_MS;
 | 
			
		||||
	// vTaskDelay(xDelay);
 | 
			
		||||
	// return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_FREERTOS_SLEEP__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2017-2020, eForce Co Ltd. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/sys.h
 | 
			
		||||
 * @brief	FreeRTOS system primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_SYS__H__
 | 
			
		||||
#error "Include metal/sys.h instead of metal/xizi/sys.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_FREERTOS_SYS__H__
 | 
			
		||||
#define __METAL_FREERTOS_SYS__H__
 | 
			
		||||
 | 
			
		||||
#include <metal/errno.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "./rzv2/sys.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef METAL_MAX_DEVICE_REGIONS
 | 
			
		||||
#define METAL_MAX_DEVICE_REGIONS 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** Structure for FreeRTOS libmetal runtime state. */
 | 
			
		||||
struct metal_state {
 | 
			
		||||
 | 
			
		||||
	/** Common (system independent) data. */
 | 
			
		||||
	struct metal_common_state common;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef METAL_INTERNAL
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief restore interrupts to state before disable_global_interrupt()
 | 
			
		||||
 */
 | 
			
		||||
void sys_irq_restore_enable(unsigned int flags);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief disable all interrupts
 | 
			
		||||
 */
 | 
			
		||||
unsigned int sys_irq_save_disable(void);
 | 
			
		||||
 | 
			
		||||
#endif /* METAL_INTERNAL */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_FREERTOS_SYS__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	time.h
 | 
			
		||||
 * @brief	Time primitives for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_TIME__H__
 | 
			
		||||
#define __METAL_TIME__H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup time TIME Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <metal/sys.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief      get timestamp
 | 
			
		||||
 *             This function returns the timestampe as unsigned long long
 | 
			
		||||
 *             value.
 | 
			
		||||
 *
 | 
			
		||||
 * @return     timestamp
 | 
			
		||||
 */
 | 
			
		||||
unsigned long long metal_get_timestamp(void);
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_TIME__H__ */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,152 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	utilities.h
 | 
			
		||||
 * @brief	Utility routines for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_UTILITIES__H__
 | 
			
		||||
#define __METAL_UTILITIES__H__
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <metal/assert.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup utilities Simple Utilities
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
/** Marker for unused function arguments/variables. */
 | 
			
		||||
#define metal_unused(x)	do { (x) = (x); } while (0)
 | 
			
		||||
 | 
			
		||||
/** Figure out number of elements in an array. */
 | 
			
		||||
#define metal_dim(x)	(sizeof(x) / sizeof(x[0]))
 | 
			
		||||
 | 
			
		||||
/** Minimum of two numbers (warning: multiple evaluation!).  */
 | 
			
		||||
#define metal_min(x, y)	((x) < (y) ? (x) : (y))
 | 
			
		||||
 | 
			
		||||
/** Maximum of two numbers (warning: multiple evaluation!).  */
 | 
			
		||||
#define metal_max(x, y)	((x) > (y) ? (x) : (y))
 | 
			
		||||
 | 
			
		||||
/** Sign of a number [-1, 0, or 1] (warning: multiple evaluation!).  */
 | 
			
		||||
#define metal_sign(x)	((x) < 0 ? -1 : ((x) > 0 ? 1 : 0))
 | 
			
		||||
 | 
			
		||||
/** Align 'size' down to a multiple of 'align' (must be a power of two). */
 | 
			
		||||
#define metal_align_down(size, align)			\
 | 
			
		||||
	((size) & ~((align) - 1))
 | 
			
		||||
 | 
			
		||||
/** Align 'size' up to a multiple of 'align' (must be a power of two). */
 | 
			
		||||
#define metal_align_up(size, align)			\
 | 
			
		||||
	metal_align_down((size) + (align) - 1, align)
 | 
			
		||||
 | 
			
		||||
/** Divide (and round down). */
 | 
			
		||||
#define metal_div_round_down(num, den)			\
 | 
			
		||||
	((num) / (den))
 | 
			
		||||
 | 
			
		||||
/** Divide (and round up). */
 | 
			
		||||
#define metal_div_round_up(num, den)			\
 | 
			
		||||
	metal_div_round_down((num) + (den) - 1, (den))
 | 
			
		||||
 | 
			
		||||
/** Align 'ptr' down to a multiple of 'align' (must be a power of two). */
 | 
			
		||||
#define metal_ptr_align_down(ptr, align)		\
 | 
			
		||||
	(void *)(metal_align_down((uintptr_t)(ptr), (uintptr_t)(align)))
 | 
			
		||||
 | 
			
		||||
/** Align 'ptr' up to a multiple of 'align' (must be a power of two). */
 | 
			
		||||
#define metal_ptr_align_up(ptr, align)			\
 | 
			
		||||
	(void *)(metal_align_up((uintptr_t)(ptr), (uintptr_t)(align)))
 | 
			
		||||
 | 
			
		||||
/** Compute offset of a field within a structure. */
 | 
			
		||||
#define metal_offset_of(structure, member)		\
 | 
			
		||||
	((uintptr_t) &(((structure *) 0)->member))
 | 
			
		||||
 | 
			
		||||
/** Compute pointer to a structure given a pointer to one of its fields. */
 | 
			
		||||
#define metal_container_of(ptr, structure, member)	\
 | 
			
		||||
	(void *)((uintptr_t)(ptr) - metal_offset_of(structure, member))
 | 
			
		||||
 | 
			
		||||
#define METAL_BITS_PER_ULONG	(8 * sizeof(unsigned long))
 | 
			
		||||
 | 
			
		||||
#define metal_bit(bit)		(1UL << (bit))
 | 
			
		||||
 | 
			
		||||
#define metal_bitmap_longs(x)	metal_div_round_up((x), METAL_BITS_PER_ULONG)
 | 
			
		||||
 | 
			
		||||
static inline void metal_bitmap_set_bit(unsigned long *bitmap, int bit)
 | 
			
		||||
{
 | 
			
		||||
	bitmap[bit / METAL_BITS_PER_ULONG] |=
 | 
			
		||||
		metal_bit(bit & (METAL_BITS_PER_ULONG - 1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int metal_bitmap_is_bit_set(unsigned long *bitmap, int bit)
 | 
			
		||||
{
 | 
			
		||||
	return ((bitmap[bit / METAL_BITS_PER_ULONG] &
 | 
			
		||||
		metal_bit(bit & (METAL_BITS_PER_ULONG - 1))) == 0) ? 0 : 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void metal_bitmap_clear_bit(unsigned long *bitmap, int bit)
 | 
			
		||||
{
 | 
			
		||||
	bitmap[bit / METAL_BITS_PER_ULONG] &=
 | 
			
		||||
		~metal_bit(bit & (METAL_BITS_PER_ULONG - 1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int metal_bitmap_is_bit_clear(unsigned long *bitmap, int bit)
 | 
			
		||||
{
 | 
			
		||||
	return !metal_bitmap_is_bit_set(bitmap, bit);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline unsigned int
 | 
			
		||||
metal_bitmap_next_set_bit(unsigned long *bitmap, unsigned int start,
 | 
			
		||||
			  unsigned int max)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int bit;
 | 
			
		||||
	for (bit = start;
 | 
			
		||||
	     bit < max && !metal_bitmap_is_bit_set(bitmap, bit);
 | 
			
		||||
	     bit ++)
 | 
			
		||||
		;
 | 
			
		||||
	return bit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define metal_bitmap_for_each_set_bit(bitmap, bit, max)			\
 | 
			
		||||
	for ((bit) = metal_bitmap_next_set_bit((bitmap), 0, (max));	\
 | 
			
		||||
	     (bit) < (max);						\
 | 
			
		||||
	     (bit) = metal_bitmap_next_set_bit((bitmap), (bit + 1), (max)))
 | 
			
		||||
 | 
			
		||||
static inline unsigned int
 | 
			
		||||
metal_bitmap_next_clear_bit(unsigned long *bitmap, unsigned int start,
 | 
			
		||||
			    unsigned int max)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int bit;
 | 
			
		||||
	for (bit = start;
 | 
			
		||||
	     bit < max && !metal_bitmap_is_bit_clear(bitmap, bit);
 | 
			
		||||
	     bit ++)
 | 
			
		||||
		;
 | 
			
		||||
	return bit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define metal_bitmap_for_each_clear_bit(bitmap, bit, max)		\
 | 
			
		||||
	for ((bit) = metal_bitmap_next_clear_bit((bitmap), 0, (max));	\
 | 
			
		||||
	     (bit) < (max);						\
 | 
			
		||||
	     (bit) = metal_bitmap_next_clear_bit((bitmap), (bit + 1), (max)))
 | 
			
		||||
 | 
			
		||||
static inline unsigned long metal_log2(unsigned long in)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long result;
 | 
			
		||||
 | 
			
		||||
	metal_assert((in & (in - 1)) == 0);
 | 
			
		||||
 | 
			
		||||
	for (result = 0; (1UL << result) < in; result ++)
 | 
			
		||||
		;
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_UTILITIES__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	version.h
 | 
			
		||||
 * @brief	Library version information for libmetal.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __METAL_VERSION__H__
 | 
			
		||||
#define __METAL_VERSION__H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \defgroup versions Library Version Interfaces
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  @brief	Library major version number.
 | 
			
		||||
 *
 | 
			
		||||
 *  Return the major version number of the library linked into the application.
 | 
			
		||||
 *  This is required to match the value of METAL_VER_MAJOR, which is the major
 | 
			
		||||
 *  version of the library that the application was compiled against.
 | 
			
		||||
 *
 | 
			
		||||
 *  @return	Library major version number.
 | 
			
		||||
 *  @see	METAL_VER_MAJOR
 | 
			
		||||
 */
 | 
			
		||||
extern int metal_ver_major(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  @brief	Library minor version number.
 | 
			
		||||
 *
 | 
			
		||||
 *  Return the minor version number of the library linked into the application.
 | 
			
		||||
 *  This could differ from the value of METAL_VER_MINOR, which is the minor
 | 
			
		||||
 *  version of the library that the application was compiled against.
 | 
			
		||||
 *
 | 
			
		||||
 *  @return	Library minor version number.
 | 
			
		||||
 *  @see	METAL_VER_MINOR
 | 
			
		||||
 */
 | 
			
		||||
extern int metal_ver_minor(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  @brief	Library patch level.
 | 
			
		||||
 *
 | 
			
		||||
 *  Return the patch level of the library linked into the application.  This
 | 
			
		||||
 *  could differ from the value of METAL_VER_PATCH, which is the patch level of
 | 
			
		||||
 *  the library that the application was compiled against.
 | 
			
		||||
 *
 | 
			
		||||
 *  @return	Library patch level.
 | 
			
		||||
 *  @see	METAL_VER_PATCH
 | 
			
		||||
 */
 | 
			
		||||
extern int metal_ver_patch(void);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  @brief	Library version string.
 | 
			
		||||
 *
 | 
			
		||||
 *  Return the version string of the library linked into the application.  This
 | 
			
		||||
 *  could differ from the value of METAL_VER, which is the version string of
 | 
			
		||||
 *  the library that the application was compiled against.
 | 
			
		||||
 *
 | 
			
		||||
 *  @return	Library version string.
 | 
			
		||||
 *  @see	METAL_VER
 | 
			
		||||
 */
 | 
			
		||||
extern const char *metal_ver(void);
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __METAL_VERSION__H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
SRC_DIR := system/xizi
 | 
			
		||||
 | 
			
		||||
SRC_FILES := $(wildcard *.c)
 | 
			
		||||
 | 
			
		||||
include $(KERNEL_ROOT)/compiler.mk
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,169 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2020, eForce.Co.Ltd
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <metal/errno.h>
 | 
			
		||||
//#include <errno.h>
 | 
			
		||||
#include <metal/assert.h>
 | 
			
		||||
#include <metal/device.h>
 | 
			
		||||
#include <metal/list.h>
 | 
			
		||||
#include <metal/log.h>
 | 
			
		||||
#include <metal/sys.h>
 | 
			
		||||
#include <metal/utilities.h>
 | 
			
		||||
#include <metal/dma.h>
 | 
			
		||||
#include <metal/cache.h>
 | 
			
		||||
 | 
			
		||||
int metal_bus_register(struct metal_bus *bus)
 | 
			
		||||
{
 | 
			
		||||
	if (!bus || !bus->name || !strlen(bus->name))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (metal_bus_find(bus->name, NULL) == 0)
 | 
			
		||||
		return -EEXIST;
 | 
			
		||||
	metal_list_init(&bus->devices);
 | 
			
		||||
	metal_list_add_tail(&_metal.common.bus_list, &bus->node);
 | 
			
		||||
	metal_log(METAL_LOG_DEBUG, "registered %s bus\n", bus->name);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int metal_bus_unregister(struct metal_bus *bus)
 | 
			
		||||
{
 | 
			
		||||
	metal_list_del(&bus->node);
 | 
			
		||||
	if (bus->ops.bus_close)
 | 
			
		||||
		bus->ops.bus_close(bus);
 | 
			
		||||
	metal_log(METAL_LOG_DEBUG, "unregistered %s bus\n", bus->name);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int metal_bus_find(const char *name, struct metal_bus **result)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_list *node;
 | 
			
		||||
	struct metal_bus *bus;
 | 
			
		||||
 | 
			
		||||
	metal_list_for_each(&_metal.common.bus_list, node) {
 | 
			
		||||
		bus = metal_container_of(node, struct metal_bus, node);
 | 
			
		||||
		if (strcmp(bus->name, name) != 0)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (result)
 | 
			
		||||
			*result = bus;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	return -ENOENT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int metal_device_open(const char *bus_name, const char *dev_name,
 | 
			
		||||
		      struct metal_device **device)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_bus *bus;
 | 
			
		||||
	int error;
 | 
			
		||||
 | 
			
		||||
	if (!bus_name || !strlen(bus_name) ||
 | 
			
		||||
	    !dev_name || !strlen(dev_name) ||
 | 
			
		||||
	    !device)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	error = metal_bus_find(bus_name, &bus);
 | 
			
		||||
	if (error)
 | 
			
		||||
		return error;
 | 
			
		||||
 | 
			
		||||
	if (!bus->ops.dev_open)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	error = (*bus->ops.dev_open)(bus, dev_name, device);
 | 
			
		||||
	if (error)
 | 
			
		||||
		return error;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void metal_device_close(struct metal_device *device)
 | 
			
		||||
{
 | 
			
		||||
	metal_assert(device && device->bus);
 | 
			
		||||
	if (device->bus->ops.dev_close)
 | 
			
		||||
		device->bus->ops.dev_close(device->bus, device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int metal_register_generic_device(struct metal_device *device)
 | 
			
		||||
{
 | 
			
		||||
	if (!device->name || !strlen(device->name) ||
 | 
			
		||||
	    device->num_regions > METAL_MAX_DEVICE_REGIONS)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	device->bus = &metal_generic_bus;
 | 
			
		||||
	metal_list_add_tail(&_metal.common.generic_device_list,
 | 
			
		||||
			    &device->node);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int metal_generic_dev_open(struct metal_bus *bus, const char *dev_name,
 | 
			
		||||
			   struct metal_device **device)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_list *node;
 | 
			
		||||
	struct metal_device *dev;
 | 
			
		||||
 | 
			
		||||
	(void)bus;
 | 
			
		||||
 | 
			
		||||
	metal_list_for_each(&_metal.common.generic_device_list, node) {
 | 
			
		||||
		dev = metal_container_of(node, struct metal_device, node);
 | 
			
		||||
		if (strcmp(dev->name, dev_name) != 0)
 | 
			
		||||
			continue;
 | 
			
		||||
		*device = dev;
 | 
			
		||||
		return metal_generic_dev_sys_open(dev);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -ENODEV;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int metal_generic_dev_dma_map(struct metal_bus *bus,
 | 
			
		||||
			     struct metal_device *device,
 | 
			
		||||
			     uint32_t dir,
 | 
			
		||||
			     struct metal_sg *sg_in,
 | 
			
		||||
			     int nents_in,
 | 
			
		||||
			     struct metal_sg *sg_out)
 | 
			
		||||
{
 | 
			
		||||
	(void)bus;
 | 
			
		||||
	(void)device;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (sg_out != sg_in)
 | 
			
		||||
		memcpy(sg_out, sg_in, nents_in*(sizeof(struct metal_sg)));
 | 
			
		||||
	for (i = 0; i < nents_in; i++) {
 | 
			
		||||
		if (dir == METAL_DMA_DEV_W) {
 | 
			
		||||
			metal_cache_flush(sg_out[i].virt, sg_out[i].len);
 | 
			
		||||
		}
 | 
			
		||||
		metal_cache_invalidate(sg_out[i].virt, sg_out[i].len);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nents_in;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void metal_generic_dev_dma_unmap(struct metal_bus *bus,
 | 
			
		||||
				 struct metal_device *device,
 | 
			
		||||
				 uint32_t dir,
 | 
			
		||||
				 struct metal_sg *sg,
 | 
			
		||||
				 int nents)
 | 
			
		||||
{
 | 
			
		||||
	(void)bus;
 | 
			
		||||
	(void)device;
 | 
			
		||||
	(void)dir;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < nents; i++) {
 | 
			
		||||
		metal_cache_invalidate(sg[i].virt, sg[i].len);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct metal_bus metal_weak metal_generic_bus = {
 | 
			
		||||
	.name = "generic",
 | 
			
		||||
	.ops  = {
 | 
			
		||||
		.bus_close = NULL,
 | 
			
		||||
		.dev_open  = metal_generic_dev_open,
 | 
			
		||||
		.dev_close = NULL,
 | 
			
		||||
		.dev_irq_ack = NULL,
 | 
			
		||||
		.dev_dma_map = metal_generic_dev_dma_map,
 | 
			
		||||
		.dev_dma_unmap = metal_generic_dev_dma_unmap,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,60 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2020, eForce.Co.Ltd
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <metal/errno.h>
 | 
			
		||||
//#include <errno.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <metal/device.h>
 | 
			
		||||
#include <metal/log.h>
 | 
			
		||||
#include <metal/dma.h>
 | 
			
		||||
#include <metal/atomic.h>
 | 
			
		||||
 | 
			
		||||
int metal_dma_map(struct metal_device *dev,
 | 
			
		||||
		  uint32_t dir,
 | 
			
		||||
		  struct metal_sg *sg_in,
 | 
			
		||||
		  int nents_in,
 | 
			
		||||
		  struct metal_sg *sg_out)
 | 
			
		||||
{
 | 
			
		||||
	int nents_out;
 | 
			
		||||
 | 
			
		||||
	if (!dev || !sg_in || !sg_out)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (!dev->bus->ops.dev_dma_map)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	/* memory barrier */
 | 
			
		||||
	if (dir == METAL_DMA_DEV_R)
 | 
			
		||||
		/* If it is device read, apply memory write fence. */
 | 
			
		||||
		atomic_thread_fence(memory_order_release);
 | 
			
		||||
	else
 | 
			
		||||
		/* If it is device write or device r/w,
 | 
			
		||||
		   apply memory r/w fence. */
 | 
			
		||||
		atomic_thread_fence(memory_order_acq_rel);
 | 
			
		||||
	nents_out = dev->bus->ops.dev_dma_map(dev->bus,
 | 
			
		||||
			dev, dir, sg_in, nents_in, sg_out);
 | 
			
		||||
	return nents_out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void metal_dma_unmap(struct metal_device *dev,
 | 
			
		||||
		  uint32_t dir,
 | 
			
		||||
		  struct metal_sg *sg,
 | 
			
		||||
		  int nents)
 | 
			
		||||
{
 | 
			
		||||
	/* memory barrier */
 | 
			
		||||
	if (dir == METAL_DMA_DEV_R)
 | 
			
		||||
		/* If it is device read, apply memory write fence. */
 | 
			
		||||
		atomic_thread_fence(memory_order_release);
 | 
			
		||||
	else
 | 
			
		||||
		/* If it is device write or device r/w,
 | 
			
		||||
		   apply memory r/w fence. */
 | 
			
		||||
		atomic_thread_fence(memory_order_acq_rel);
 | 
			
		||||
 | 
			
		||||
	if (!dev || !dev->bus->ops.dev_dma_unmap || !sg)
 | 
			
		||||
		return;
 | 
			
		||||
	dev->bus->ops.dev_dma_unmap(dev->bus,
 | 
			
		||||
			dev, dir, sg, nents);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <metal/sys.h>
 | 
			
		||||
 | 
			
		||||
int metal_init(const struct metal_init_params *params)
 | 
			
		||||
{
 | 
			
		||||
	int error = 0;
 | 
			
		||||
 | 
			
		||||
	memset(&_metal, 0, sizeof(_metal));
 | 
			
		||||
 | 
			
		||||
	_metal.common.log_handler   = params->log_handler;
 | 
			
		||||
	_metal.common.log_level     = params->log_level;
 | 
			
		||||
 | 
			
		||||
	metal_list_init(&_metal.common.bus_list);
 | 
			
		||||
	metal_list_init(&_metal.common.generic_shmem_list);
 | 
			
		||||
	metal_list_init(&_metal.common.generic_device_list);
 | 
			
		||||
 | 
			
		||||
	error = metal_sys_init(params);
 | 
			
		||||
	if (error)
 | 
			
		||||
		return error;
 | 
			
		||||
 | 
			
		||||
	return error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void metal_finish(void)
 | 
			
		||||
{
 | 
			
		||||
	metal_sys_finish();
 | 
			
		||||
	memset(&_metal, 0, sizeof(_metal));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,141 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2020, eForce.Co.Ltd
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <metal/errno.h>
 | 
			
		||||
//#include <errno.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <metal/io.h>
 | 
			
		||||
#include <metal/sys.h>
 | 
			
		||||
 | 
			
		||||
void metal_io_init(struct metal_io_region *io, void *virt,
 | 
			
		||||
	      const metal_phys_addr_t *physmap, size_t size,
 | 
			
		||||
	      unsigned page_shift, unsigned int mem_flags,
 | 
			
		||||
	      const struct metal_io_ops *ops)
 | 
			
		||||
{
 | 
			
		||||
	const struct metal_io_ops nops = {NULL, NULL, NULL, NULL, NULL, NULL};
 | 
			
		||||
 | 
			
		||||
	io->virt = virt;
 | 
			
		||||
	io->physmap = physmap;
 | 
			
		||||
	io->size = size;
 | 
			
		||||
	io->page_shift = page_shift;
 | 
			
		||||
	if (page_shift >= sizeof(io->page_mask) * CHAR_BIT)
 | 
			
		||||
		/* avoid overflow */
 | 
			
		||||
		io->page_mask = -1UL;
 | 
			
		||||
	else
 | 
			
		||||
		io->page_mask = (1UL << page_shift) - 1UL;
 | 
			
		||||
	io->mem_flags = mem_flags;
 | 
			
		||||
	io->ops = ops ? *ops : nops;
 | 
			
		||||
	metal_sys_io_mem_map(io);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int metal_io_block_read(struct metal_io_region *io, unsigned long offset,
 | 
			
		||||
	       void *restrict dst, int len)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char *ptr = metal_io_virt(io, offset);
 | 
			
		||||
	unsigned char *dest = dst;
 | 
			
		||||
	int retlen;
 | 
			
		||||
 | 
			
		||||
	if (offset > io->size)
 | 
			
		||||
		return -ERANGE;
 | 
			
		||||
	if ((offset + len) > io->size)
 | 
			
		||||
		len = io->size - offset;
 | 
			
		||||
	retlen = len;
 | 
			
		||||
	if (io->ops.block_read) {
 | 
			
		||||
		retlen = (*io->ops.block_read)(
 | 
			
		||||
			io, offset, dst, memory_order_seq_cst, len);
 | 
			
		||||
	} else {
 | 
			
		||||
		atomic_thread_fence(memory_order_seq_cst);
 | 
			
		||||
		while ( len && (
 | 
			
		||||
			((uintptr_t)dest % sizeof(int)) ||
 | 
			
		||||
			((uintptr_t)ptr % sizeof(int)))) {
 | 
			
		||||
			*(unsigned char *)dest =
 | 
			
		||||
				*(const unsigned char *)ptr;
 | 
			
		||||
			dest++;
 | 
			
		||||
			ptr++;
 | 
			
		||||
			len--;
 | 
			
		||||
		}
 | 
			
		||||
		for (; len >= (int)sizeof(int); dest += sizeof(int),
 | 
			
		||||
					ptr += sizeof(int),
 | 
			
		||||
					len -= sizeof(int))
 | 
			
		||||
			*(unsigned int *)dest = *(const unsigned int *)ptr;
 | 
			
		||||
		for (; len != 0; dest++, ptr++, len--)
 | 
			
		||||
			*(unsigned char *)dest =
 | 
			
		||||
				*(const unsigned char *)ptr;
 | 
			
		||||
	}
 | 
			
		||||
	return retlen;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int metal_io_block_write(struct metal_io_region *io, unsigned long offset,
 | 
			
		||||
	       const void *restrict src, int len)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char *ptr = metal_io_virt(io, offset);
 | 
			
		||||
	const unsigned char *source = src;
 | 
			
		||||
	int retlen;
 | 
			
		||||
 | 
			
		||||
	if (offset > io->size)
 | 
			
		||||
		return -ERANGE;
 | 
			
		||||
	if ((offset + len) > io->size)
 | 
			
		||||
		len = io->size - offset;
 | 
			
		||||
	retlen = len;
 | 
			
		||||
	if (io->ops.block_write) {
 | 
			
		||||
		retlen = (*io->ops.block_write)(
 | 
			
		||||
			io, offset, src, memory_order_seq_cst, len);
 | 
			
		||||
	} else {
 | 
			
		||||
		while ( len && (
 | 
			
		||||
			((uintptr_t)ptr % sizeof(int)) ||
 | 
			
		||||
			((uintptr_t)source % sizeof(int)))) {
 | 
			
		||||
			*(unsigned char *)ptr =
 | 
			
		||||
				*(const unsigned char *)source;
 | 
			
		||||
			ptr++;
 | 
			
		||||
			source++;
 | 
			
		||||
			len--;
 | 
			
		||||
		}
 | 
			
		||||
		for (; len >= (int)sizeof(int); ptr += sizeof(int),
 | 
			
		||||
					source += sizeof(int),
 | 
			
		||||
					len -= sizeof(int))
 | 
			
		||||
			*(unsigned int *)ptr = *(const unsigned int *)source;
 | 
			
		||||
		for (; len != 0; ptr++, source++, len--)
 | 
			
		||||
			*(unsigned char *)ptr =
 | 
			
		||||
				*(const unsigned char *)source;
 | 
			
		||||
		atomic_thread_fence(memory_order_seq_cst);
 | 
			
		||||
	}
 | 
			
		||||
	return retlen;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int metal_io_block_set(struct metal_io_region *io, unsigned long offset,
 | 
			
		||||
	       unsigned char value, int len)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char *ptr = metal_io_virt(io, offset);
 | 
			
		||||
	int retlen = len;
 | 
			
		||||
 | 
			
		||||
	if (offset > io->size)
 | 
			
		||||
		return -ERANGE;
 | 
			
		||||
	if ((offset + len) > io->size)
 | 
			
		||||
		len = io->size - offset;
 | 
			
		||||
	retlen = len;
 | 
			
		||||
	if (io->ops.block_set) {
 | 
			
		||||
		(*io->ops.block_set)(
 | 
			
		||||
			io, offset, value, memory_order_seq_cst, len);
 | 
			
		||||
	} else {
 | 
			
		||||
		unsigned int cint = value;
 | 
			
		||||
		unsigned int i;
 | 
			
		||||
 | 
			
		||||
		for (i = 1; i < sizeof(int); i++)
 | 
			
		||||
			cint |= ((unsigned int)value << (8 * i));
 | 
			
		||||
 | 
			
		||||
		for (; len && ((uintptr_t)ptr % sizeof(int)); ptr++, len--)
 | 
			
		||||
			*(unsigned char *)ptr = (unsigned char) value;
 | 
			
		||||
		for (; len >= (int)sizeof(int); ptr += sizeof(int),
 | 
			
		||||
						len -= sizeof(int))
 | 
			
		||||
			*(unsigned int *)ptr = cint;
 | 
			
		||||
		for (; len != 0; ptr++, len--)
 | 
			
		||||
			*(unsigned char *)ptr = (unsigned char) value;
 | 
			
		||||
		atomic_thread_fence(memory_order_seq_cst);
 | 
			
		||||
	}
 | 
			
		||||
	return retlen;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#include <metal/log.h>
 | 
			
		||||
#include <metal/sys.h>
 | 
			
		||||
 | 
			
		||||
void metal_default_log_handler(enum metal_log_level level,
 | 
			
		||||
			       const char *format, ...)
 | 
			
		||||
{
 | 
			
		||||
#ifdef DEFAULT_LOGGER_ON
 | 
			
		||||
	char msg[1024];
 | 
			
		||||
	va_list args;
 | 
			
		||||
	static const char *level_strs[] = {
 | 
			
		||||
		"metal: emergency: ",
 | 
			
		||||
		"metal: alert:     ",
 | 
			
		||||
		"metal: critical:  ",
 | 
			
		||||
		"metal: error:     ",
 | 
			
		||||
		"metal: warning:   ",
 | 
			
		||||
		"metal: notice:    ",
 | 
			
		||||
		"metal: info:      ",
 | 
			
		||||
		"metal: debug:     ",
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	va_start(args, format);
 | 
			
		||||
	vsnprintf(msg, sizeof(msg), format, args);
 | 
			
		||||
	va_end(args);
 | 
			
		||||
 | 
			
		||||
	if (level <= METAL_LOG_EMERGENCY || level > METAL_LOG_DEBUG)
 | 
			
		||||
		level = METAL_LOG_EMERGENCY;
 | 
			
		||||
 | 
			
		||||
	fprintf(stderr, "%s%s", level_strs[level], msg);
 | 
			
		||||
#else
 | 
			
		||||
	(void)level;
 | 
			
		||||
	(void)format;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void metal_set_log_handler(metal_log_handler handler)
 | 
			
		||||
{
 | 
			
		||||
	_metal.common.log_handler = handler;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
metal_log_handler metal_get_log_handler(void)
 | 
			
		||||
{
 | 
			
		||||
	return _metal.common.log_handler;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void metal_set_log_level(enum metal_log_level level)
 | 
			
		||||
{
 | 
			
		||||
	_metal.common.log_level = level;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum metal_log_level metal_get_log_level(void)
 | 
			
		||||
{
 | 
			
		||||
	return _metal.common.log_level;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2020, eForce.Co.Ltd
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	generic/shmem.c
 | 
			
		||||
 * @brief	Generic libmetal shared memory handling.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <metal/errno.h>
 | 
			
		||||
//#include <errno.h>
 | 
			
		||||
#include <metal/assert.h>
 | 
			
		||||
#include <metal/shmem.h>
 | 
			
		||||
#include <metal/sys.h>
 | 
			
		||||
#include <metal/utilities.h>
 | 
			
		||||
 | 
			
		||||
int metal_shmem_register_generic(struct metal_generic_shmem *shmem)
 | 
			
		||||
{
 | 
			
		||||
	/* Make sure that we can be found. */
 | 
			
		||||
	metal_assert(shmem->name && strlen(shmem->name) != 0);
 | 
			
		||||
 | 
			
		||||
	/* Statically registered shmem regions cannot have a destructor. */
 | 
			
		||||
	metal_assert(!shmem->io.ops.close);
 | 
			
		||||
 | 
			
		||||
	metal_list_add_tail(&_metal.common.generic_shmem_list,
 | 
			
		||||
			    &shmem->node);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int metal_shmem_open_generic(const char *name, size_t size,
 | 
			
		||||
			     struct metal_io_region **result)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_generic_shmem *shmem;
 | 
			
		||||
	struct metal_list *node;
 | 
			
		||||
 | 
			
		||||
	metal_list_for_each(&_metal.common.generic_shmem_list, node) {
 | 
			
		||||
		shmem = metal_container_of(node, struct metal_generic_shmem, node);
 | 
			
		||||
		if (strcmp(shmem->name, name) != 0)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (size > metal_io_region_size(&shmem->io))
 | 
			
		||||
			continue;
 | 
			
		||||
		*result = &shmem->io;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -ENOENT;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
SRC_DIR := rzv2
 | 
			
		||||
 | 
			
		||||
SRC_FILES := $(wildcard *.c)
 | 
			
		||||
 | 
			
		||||
include $(KERNEL_ROOT)/compiler.mk
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
 *    this list of conditions and the following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
 *    this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
 *    and/or other materials provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 * 3. Neither the name of Xilinx nor the names of its contributors may be used
 | 
			
		||||
 *    to endorse or promote products derived from this software without
 | 
			
		||||
 *    specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | 
			
		||||
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
			
		||||
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
			
		||||
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	generic/condition.c
 | 
			
		||||
 * @brief	Generic libmetal condition variable handling.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "metal/condition.h"
 | 
			
		||||
 | 
			
		||||
int metal_condition_wait(struct metal_condition *cv,
 | 
			
		||||
			 metal_mutex_t *m)
 | 
			
		||||
{
 | 
			
		||||
	/* TODO: Implement condition variable for FreeRTOS */
 | 
			
		||||
	(void)cv;
 | 
			
		||||
	(void)m;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2018, eForce Co,Ltd. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/device.c
 | 
			
		||||
 * @brief	Generic libmetal device operations.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <metal/device.h>
 | 
			
		||||
#include <metal/io.h>
 | 
			
		||||
#include <metal/sys.h>
 | 
			
		||||
#include <metal/utilities.h>
 | 
			
		||||
 | 
			
		||||
int metal_generic_dev_sys_open(struct metal_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_io_region *io;
 | 
			
		||||
	unsigned i;
 | 
			
		||||
 | 
			
		||||
	/* map I/O memory regions */
 | 
			
		||||
	for (i = 0; i < dev->num_regions; i++) {
 | 
			
		||||
		io = &dev->regions[i];
 | 
			
		||||
		if (!io->size)
 | 
			
		||||
			break;
 | 
			
		||||
		metal_sys_io_mem_map(io);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/init.c
 | 
			
		||||
 * @brief	FreeRTOS libmetal initialization.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <metal/sys.h>
 | 
			
		||||
#include <metal/utilities.h>
 | 
			
		||||
#include <metal/device.h>
 | 
			
		||||
 | 
			
		||||
struct metal_state _metal;
 | 
			
		||||
 | 
			
		||||
int metal_sys_init(const struct metal_init_params *params)
 | 
			
		||||
{
 | 
			
		||||
	metal_unused(params);
 | 
			
		||||
	metal_bus_register(&metal_generic_bus);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void metal_sys_finish(void)
 | 
			
		||||
{
 | 
			
		||||
	metal_bus_unregister(&metal_generic_bus);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2017, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/io.c
 | 
			
		||||
 * @brief	FreeRTOS libmetal io operations
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <metal/io.h>
 | 
			
		||||
 | 
			
		||||
void metal_sys_io_mem_map(struct metal_io_region *io)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long p;
 | 
			
		||||
	size_t psize;
 | 
			
		||||
	void *va;
 | 
			
		||||
 | 
			
		||||
	va = io->virt;
 | 
			
		||||
	psize = io->size;
 | 
			
		||||
	if (psize) {
 | 
			
		||||
		if (psize >> io->page_shift)
 | 
			
		||||
			psize = (size_t)1 << io->page_shift;
 | 
			
		||||
		for (p = 0; p <= (io->size >> io->page_shift); p++) {
 | 
			
		||||
			metal_machine_io_mem_map(va, io->physmap[p],
 | 
			
		||||
						 psize, io->mem_flags);
 | 
			
		||||
			va += psize;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,279 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016 - 2017, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/irq.c
 | 
			
		||||
 * @brief	FreeRTOS libmetal irq definitions.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <metal/irq.h>
 | 
			
		||||
#include <metal/sys.h>
 | 
			
		||||
#include <metal/log.h>
 | 
			
		||||
#include <metal/mutex.h>
 | 
			
		||||
#include <metal/list.h>
 | 
			
		||||
#include <metal/utilities.h>
 | 
			
		||||
#include <metal/alloc.h>
 | 
			
		||||
 | 
			
		||||
/** IRQ handlers descriptor structure */
 | 
			
		||||
struct metal_irq_hddesc {
 | 
			
		||||
	metal_irq_handler hd;     /**< irq handler */
 | 
			
		||||
	void *drv_id;             /**< id to identify the driver
 | 
			
		||||
	                               of the irq handler */
 | 
			
		||||
	struct metal_device *dev; /**< device identifier */
 | 
			
		||||
	struct metal_list node;   /**< node on irq handlers list */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** IRQ descriptor structure */
 | 
			
		||||
struct metal_irq_desc {
 | 
			
		||||
	int irq;                  /**< interrupt number */
 | 
			
		||||
	struct metal_list hdls;   /**< interrupt handlers */
 | 
			
		||||
	struct metal_list node;   /**< node on irqs list */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** IRQ state structure */
 | 
			
		||||
struct metal_irqs_state {
 | 
			
		||||
	struct metal_list irqs;    /**< interrupt descriptors */
 | 
			
		||||
	metal_mutex_t irq_lock;    /**< access lock */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct metal_irqs_state _irqs = {
 | 
			
		||||
	.irqs = METAL_INIT_LIST(_irqs.irqs),
 | 
			
		||||
	.irq_lock = METAL_MUTEX_INIT(_irqs.irq_lock),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int metal_irq_register(int irq,
 | 
			
		||||
                       metal_irq_handler hd,
 | 
			
		||||
                       struct metal_device *dev,
 | 
			
		||||
                       void *drv_id)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_irq_desc *irq_p = NULL;
 | 
			
		||||
	struct metal_irq_hddesc *hdl_p;
 | 
			
		||||
	struct metal_list *node;
 | 
			
		||||
	unsigned int irq_flags_save;
 | 
			
		||||
 | 
			
		||||
	if (irq < 0) {
 | 
			
		||||
		metal_log(METAL_LOG_ERROR,
 | 
			
		||||
			  "%s: irq %d need to be a positive number\n",
 | 
			
		||||
		          __func__, irq);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((drv_id == NULL) || (hd == NULL)) {
 | 
			
		||||
		metal_log(METAL_LOG_ERROR, "%s: irq %d need drv_id and hd.\n",
 | 
			
		||||
		          __func__, irq);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Search for irq in list */
 | 
			
		||||
	metal_mutex_acquire(&_irqs.irq_lock);
 | 
			
		||||
	metal_list_for_each(&_irqs.irqs, node) {
 | 
			
		||||
		irq_p = metal_container_of(node, struct metal_irq_desc, node);
 | 
			
		||||
 | 
			
		||||
		if (irq_p->irq == irq) {
 | 
			
		||||
			struct metal_list *h_node;
 | 
			
		||||
 | 
			
		||||
			/* Check if drv_id already exist */
 | 
			
		||||
			metal_list_for_each(&irq_p->hdls, h_node) {
 | 
			
		||||
				hdl_p = metal_container_of(h_node,
 | 
			
		||||
							   struct metal_irq_hddesc,
 | 
			
		||||
							   node);
 | 
			
		||||
 | 
			
		||||
				/* if drv_id already exist reject */
 | 
			
		||||
				if ((hdl_p->drv_id == drv_id) &&
 | 
			
		||||
					((dev == NULL) || (hdl_p->dev == dev))) {
 | 
			
		||||
					metal_log(METAL_LOG_ERROR,
 | 
			
		||||
						  "%s: irq %d already registered."
 | 
			
		||||
							"Will not register again.\n",
 | 
			
		||||
							__func__, irq);
 | 
			
		||||
					metal_mutex_release(&_irqs.irq_lock);
 | 
			
		||||
					return -EINVAL;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			/* irq found and drv_id not used, get out of metal_list_for_each */
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Either need to add handler to an existing list or to a new one */
 | 
			
		||||
	hdl_p = metal_allocate_memory(sizeof(struct metal_irq_hddesc));
 | 
			
		||||
	if (hdl_p == NULL) {
 | 
			
		||||
		metal_log(METAL_LOG_ERROR,
 | 
			
		||||
		          "%s: irq %d cannot allocate mem for drv_id %d.\n",
 | 
			
		||||
		          __func__, irq, drv_id);
 | 
			
		||||
		metal_mutex_release(&_irqs.irq_lock);
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	hdl_p->hd = hd;
 | 
			
		||||
	hdl_p->drv_id = drv_id;
 | 
			
		||||
	hdl_p->dev = dev;
 | 
			
		||||
 | 
			
		||||
	/* interrupt already registered, add handler to existing list*/
 | 
			
		||||
	if ((irq_p != NULL) && (irq_p->irq == irq)) {
 | 
			
		||||
		irq_flags_save = metal_irq_save_disable();
 | 
			
		||||
		metal_list_add_tail(&irq_p->hdls, &hdl_p->node);
 | 
			
		||||
		metal_irq_restore_enable(irq_flags_save);
 | 
			
		||||
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG, "%s: success, irq %d add drv_id %p \n",
 | 
			
		||||
		          __func__, irq, drv_id);
 | 
			
		||||
		metal_mutex_release(&_irqs.irq_lock);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* interrupt was not already registered, add */
 | 
			
		||||
	irq_p = metal_allocate_memory(sizeof(struct metal_irq_desc));
 | 
			
		||||
	if (irq_p == NULL) {
 | 
			
		||||
		metal_log(METAL_LOG_ERROR, "%s: irq %d cannot allocate mem.\n",
 | 
			
		||||
		          __func__, irq);
 | 
			
		||||
		metal_mutex_release(&_irqs.irq_lock);
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	irq_p->irq = irq;
 | 
			
		||||
	metal_list_init(&irq_p->hdls);
 | 
			
		||||
	metal_list_add_tail(&irq_p->hdls, &hdl_p->node);
 | 
			
		||||
 | 
			
		||||
	irq_flags_save = metal_irq_save_disable();
 | 
			
		||||
	metal_list_add_tail(&_irqs.irqs, &irq_p->node);
 | 
			
		||||
	metal_irq_restore_enable(irq_flags_save);
 | 
			
		||||
 | 
			
		||||
	metal_log(METAL_LOG_DEBUG, "%s: success, added irq %d\n", __func__, irq);
 | 
			
		||||
	metal_mutex_release(&_irqs.irq_lock);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* helper function for metal_irq_unregister() */
 | 
			
		||||
static void metal_irq_delete_node(struct metal_list *node, void *p_to_free)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int irq_flags_save;
 | 
			
		||||
 | 
			
		||||
	irq_flags_save=metal_irq_save_disable();
 | 
			
		||||
	metal_list_del(node);
 | 
			
		||||
	metal_irq_restore_enable(irq_flags_save);
 | 
			
		||||
	metal_free_memory(p_to_free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int metal_irq_unregister(int irq,
 | 
			
		||||
                         metal_irq_handler hd,
 | 
			
		||||
                         struct metal_device *dev,
 | 
			
		||||
                         void *drv_id)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_irq_desc *irq_p;
 | 
			
		||||
	struct metal_list *node;
 | 
			
		||||
 | 
			
		||||
	if (irq < 0) {
 | 
			
		||||
		metal_log(METAL_LOG_ERROR, "%s: irq %d need to be a positive number\n",
 | 
			
		||||
		          __func__, irq);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Search for irq in list */
 | 
			
		||||
	metal_mutex_acquire(&_irqs.irq_lock);
 | 
			
		||||
	metal_list_for_each(&_irqs.irqs, node) {
 | 
			
		||||
 | 
			
		||||
		irq_p = metal_container_of(node, struct metal_irq_desc, node);
 | 
			
		||||
 | 
			
		||||
		if (irq_p->irq == irq) {
 | 
			
		||||
			struct metal_list *h_node, *h_prenode;
 | 
			
		||||
			struct metal_irq_hddesc *hdl_p;
 | 
			
		||||
			unsigned int delete_count = 0;
 | 
			
		||||
 | 
			
		||||
			metal_log(METAL_LOG_DEBUG, "%s: found irq %d\n",
 | 
			
		||||
				  __func__, irq);
 | 
			
		||||
 | 
			
		||||
			/* Search through handlers */
 | 
			
		||||
			metal_list_for_each(&irq_p->hdls, h_node) {
 | 
			
		||||
				hdl_p = metal_container_of(h_node,
 | 
			
		||||
							   struct metal_irq_hddesc,
 | 
			
		||||
							   node);
 | 
			
		||||
 | 
			
		||||
				if (((hd == NULL) || (hdl_p->hd == hd)) &&
 | 
			
		||||
				    ((drv_id == NULL) || (hdl_p->drv_id == drv_id)) &&
 | 
			
		||||
				    ((dev    == NULL) || (hdl_p->dev == dev))) {
 | 
			
		||||
					metal_log(METAL_LOG_DEBUG,
 | 
			
		||||
					          "%s: unregister hd=%p drv_id=%p dev=%p\n",
 | 
			
		||||
						  __func__, hdl_p->hd, hdl_p->drv_id, hdl_p->dev);
 | 
			
		||||
					h_prenode = h_node->prev;
 | 
			
		||||
					metal_irq_delete_node(h_node, hdl_p);
 | 
			
		||||
					delete_count++;
 | 
			
		||||
					h_node = h_prenode;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* we did not find any handler to delete */
 | 
			
		||||
			if (!delete_count) {
 | 
			
		||||
				metal_log(METAL_LOG_DEBUG, "%s: No matching entry\n",
 | 
			
		||||
				          __func__);
 | 
			
		||||
				metal_mutex_release(&_irqs.irq_lock);
 | 
			
		||||
				return -ENOENT;
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* if interrupt handlers list is empty, unregister interrupt */
 | 
			
		||||
			if (metal_list_is_empty(&irq_p->hdls)) {
 | 
			
		||||
				metal_log(METAL_LOG_DEBUG,
 | 
			
		||||
				          "%s: handlers list empty, unregister interrupt\n",
 | 
			
		||||
					  __func__);
 | 
			
		||||
				metal_irq_delete_node(node, irq_p);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			metal_log(METAL_LOG_DEBUG, "%s: success\n", __func__);
 | 
			
		||||
 | 
			
		||||
			metal_mutex_release(&_irqs.irq_lock);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	metal_log(METAL_LOG_DEBUG, "%s: No matching IRQ entry\n", __func__);
 | 
			
		||||
 | 
			
		||||
	metal_mutex_release(&_irqs.irq_lock);
 | 
			
		||||
	return -ENOENT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int metal_irq_save_disable(void)
 | 
			
		||||
{
 | 
			
		||||
	return sys_irq_save_disable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void metal_irq_restore_enable(unsigned int flags)
 | 
			
		||||
{
 | 
			
		||||
	sys_irq_restore_enable(flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void metal_irq_enable(unsigned int vector)
 | 
			
		||||
{
 | 
			
		||||
	sys_irq_enable(vector);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void metal_irq_disable(unsigned int vector)
 | 
			
		||||
{
 | 
			
		||||
	sys_irq_disable(vector);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief default handler
 | 
			
		||||
 */
 | 
			
		||||
void metal_irq_isr(unsigned int vector)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_list *node;
 | 
			
		||||
	struct metal_irq_desc *irq_p;
 | 
			
		||||
 | 
			
		||||
	metal_list_for_each(&_irqs.irqs, node) {
 | 
			
		||||
		irq_p = metal_container_of(node, struct metal_irq_desc, node);
 | 
			
		||||
 | 
			
		||||
		if ((unsigned int)irq_p->irq == vector) {
 | 
			
		||||
			struct metal_list *h_node;
 | 
			
		||||
			struct metal_irq_hddesc *hdl_p;
 | 
			
		||||
 | 
			
		||||
			metal_list_for_each(&irq_p->hdls, h_node) {
 | 
			
		||||
				hdl_p = metal_container_of(h_node,
 | 
			
		||||
							   struct metal_irq_hddesc,
 | 
			
		||||
							   node);
 | 
			
		||||
 | 
			
		||||
				(hdl_p->hd)(vector, hdl_p->drv_id);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
SRC_DIR := 
 | 
			
		||||
 | 
			
		||||
SRC_FILES := $(wildcard *.c)
 | 
			
		||||
 | 
			
		||||
include $(KERNEL_ROOT)/compiler.mk
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,94 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2014, Mentor Graphics Corporation
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2017, eForce Co Ltd. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
 *    this list of conditions and the following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
 *    this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
 *    and/or other materials provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 * 3. Neither the name of Xilinx nor the names of its contributors may be used
 | 
			
		||||
 *    to endorse or promote products derived from this software without
 | 
			
		||||
 *    specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | 
			
		||||
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
			
		||||
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
			
		||||
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	rzv2/sys.c
 | 
			
		||||
 * @brief	machine specific system primitives implementation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include "metal/io.h"
 | 
			
		||||
#include "metal/sys.h"
 | 
			
		||||
#include "bsp_api.h"
 | 
			
		||||
#include <xizi.h>
 | 
			
		||||
 | 
			
		||||
void sys_irq_restore_enable(unsigned int flags)
 | 
			
		||||
{
 | 
			
		||||
#if 0
 | 
			
		||||
	(void)IRQ_SetPriorityMask(flags);
 | 
			
		||||
#else
 | 
			
		||||
    ENABLE_INTERRUPT(flags);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int sys_irq_save_disable(void)
 | 
			
		||||
{
 | 
			
		||||
#if 0
 | 
			
		||||
    int32_t imask;
 | 
			
		||||
    imask= IRQ_GetPriorityMask();
 | 
			
		||||
 | 
			
		||||
	if (imask != 0) {
 | 
			
		||||
	    (void)IRQ_SetPriorityMask(0);
 | 
			
		||||
	}
 | 
			
		||||
	return imask;
 | 
			
		||||
#else
 | 
			
		||||
    // return ulSetInterruptMask();
 | 
			
		||||
    return DISABLE_INTERRUPT();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void metal_machine_cache_flush(void *addr, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
    //SCB_InvalidateDCache_by_Addr(addr, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void metal_machine_cache_invalidate(void *addr, unsigned int len)
 | 
			
		||||
{
 | 
			
		||||
    //SCB_CleanDCache_by_Addr(addr, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief poll function until some event happens
 | 
			
		||||
 */
 | 
			
		||||
void __attribute__((weak)) metal_generic_default_poll(void)
 | 
			
		||||
{
 | 
			
		||||
     __asm__ volatile("wfi");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *metal_machine_io_mem_map(void *va, metal_phys_addr_t pa,
 | 
			
		||||
				      size_t size, unsigned int flags)
 | 
			
		||||
{
 | 
			
		||||
    (void)pa;
 | 
			
		||||
    (void)size;
 | 
			
		||||
    (void)flags;
 | 
			
		||||
    return va;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/shmem.c
 | 
			
		||||
 * @brief	FreeRTOS libmetal shared memory handling.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <metal/shmem.h>
 | 
			
		||||
 | 
			
		||||
int metal_shmem_open(const char *name, size_t size,
 | 
			
		||||
		     struct metal_io_region **io)
 | 
			
		||||
{
 | 
			
		||||
	return metal_shmem_open_generic(name, size, io);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2016, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * @file	freertos/time.c
 | 
			
		||||
 * @brief	freertos libmetal time handling.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// #include <FreeRTOS.h>
 | 
			
		||||
// #include <task.h>
 | 
			
		||||
#include <xizi.h>
 | 
			
		||||
#include <metal/time.h>
 | 
			
		||||
 | 
			
		||||
unsigned long long metal_get_timestamp(void)
 | 
			
		||||
{
 | 
			
		||||
	return (unsigned long long)CurrentTicksGain();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <metal/config.h>
 | 
			
		||||
 | 
			
		||||
int metal_ver_major(void)
 | 
			
		||||
{
 | 
			
		||||
	return METAL_VER_MAJOR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int metal_ver_minor(void)
 | 
			
		||||
{
 | 
			
		||||
       return METAL_VER_MINOR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int metal_ver_patch(void)
 | 
			
		||||
{
 | 
			
		||||
       return METAL_VER_PATCH;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *metal_ver(void)
 | 
			
		||||
{
 | 
			
		||||
       return METAL_VER;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,69 @@
 | 
			
		|||
Software License Agreement (BSD 3-Clause License)
 | 
			
		||||
========================================
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2014, Mentor Graphics Corporation. All rights reserved.
 | 
			
		||||
Copyright (c) 2015 - 2016 Xilinx, Inc. All rights reserved.
 | 
			
		||||
Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
1. Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
   this list of conditions and the following disclaimer.
 | 
			
		||||
 | 
			
		||||
2. Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
   this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
   and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
3. Neither the name of <the copyright holder> nor the names of its contributors
 | 
			
		||||
   may be used to endorse or promote products derived from this software
 | 
			
		||||
   without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | 
			
		||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
			
		||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
			
		||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
BSD 2-Clause License
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
Copyright (c) <year> <owner>. All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
1. Redistributions of source code must retain the above copyright notice, this
 | 
			
		||||
   list of conditions and the following disclaimer.
 | 
			
		||||
 | 
			
		||||
2. Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
   this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
   and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 | 
			
		||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
			
		||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
			
		||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
Notes
 | 
			
		||||
=========================================
 | 
			
		||||
Use the following tag instead of the full license text in the individual files:
 | 
			
		||||
 | 
			
		||||
    SPDX-License-Identifier:    BSD-3-Clause
 | 
			
		||||
    SPDX-License-Identifier:    BSD-2-Clause
 | 
			
		||||
 | 
			
		||||
This enables machine processing of license information based on the SPDX
 | 
			
		||||
License Identifiers that are here available: http://spdx.org/licenses/
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
# OpenAMP Maintainers
 | 
			
		||||
 | 
			
		||||
OpenAMP project is maintained by the OpenAMP open source community. Everyone
 | 
			
		||||
is encouraged to submit issues and changes to improve OpenAMP.
 | 
			
		||||
 | 
			
		||||
The intention of this file is to provide a set of names that developers can
 | 
			
		||||
consult when they have a question about OpenAMP and to provide a a set of
 | 
			
		||||
names to be CC'd when submitting a patch.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Project Administration
 | 
			
		||||
Wendy Liang <wendy.liang@xilinx.com>
 | 
			
		||||
 | 
			
		||||
### All patches CC here
 | 
			
		||||
open-amp@googlegroups.com
 | 
			
		||||
 | 
			
		||||
## Machines
 | 
			
		||||
### Xilinx Platform - Zynq-7000
 | 
			
		||||
Wendy Liang <wendy.liang@xilinx.com>
 | 
			
		||||
 | 
			
		||||
### Xilinx Platform - Zynq UltraScale+ MPSoC
 | 
			
		||||
Wendy Liang <wendy.liang@xilinx.com>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,242 @@
 | 
			
		|||
# open-amp
 | 
			
		||||
This repository is the home for the Open Asymmetric Multi Processing (OpenAMP)
 | 
			
		||||
framework project. The OpenAMP framework provides software components that
 | 
			
		||||
enable development of software applications for Asymmetric Multiprocessing
 | 
			
		||||
(AMP) systems. The framework provides the following key capabilities.
 | 
			
		||||
 | 
			
		||||
1. Provides Life Cycle Management, and Inter Processor Communication
 | 
			
		||||
   capabilities for management of remote compute resources and their associated
 | 
			
		||||
   software contexts.
 | 
			
		||||
2. Provides a stand alone library usable with RTOS and Baremetal software
 | 
			
		||||
   environments
 | 
			
		||||
3. Compatibility with upstream Linux remoteproc and rpmsg components
 | 
			
		||||
4. Following AMP configurations supported
 | 
			
		||||
	a. Linux master/Generic(Baremetal) remote
 | 
			
		||||
	b. Generic(Baremetal) master/Linux remote
 | 
			
		||||
5. Proxy infrastructure and supplied demos showcase ability of proxy on master
 | 
			
		||||
   to handle printf, scanf, open, close, read, write calls from Bare metal
 | 
			
		||||
   based remote contexts.
 | 
			
		||||
 | 
			
		||||
## OpenAMP Source Structure
 | 
			
		||||
```
 | 
			
		||||
|- lib/
 | 
			
		||||
|  |- common/     # common helper functions
 | 
			
		||||
|  |- virtio/     # virtio implementation
 | 
			
		||||
|  |- rpmsg/      # rpmsg implementation
 | 
			
		||||
|  |- remoteproc/ # remoteproc implementation
 | 
			
		||||
|  |  |- drivers  # remoteproc drivers
 | 
			
		||||
|  |- proxy/      # implement one processor access device on the
 | 
			
		||||
|  |              # other processor with file operations
 | 
			
		||||
|- apps/        # demonstration/testing applications
 | 
			
		||||
|  |- machine/  # common files for machine can be shared by applications
 | 
			
		||||
|               # It is up to each app to decide whether to use these files.
 | 
			
		||||
|  |- system/   # common files for system can be shared by applications
 | 
			
		||||
|               # It is up to each app to decide whether to use these files.
 | 
			
		||||
|- obsolete     # It is used to build libs which may also required when
 | 
			
		||||
|               # building the apps. It will be removed in future since
 | 
			
		||||
|               # user can specify which libs to use when compiling the apps.
 | 
			
		||||
|- cmake        # CMake files
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
OpenAMP library libopen_amp is composed of the following directories in `lib/`:
 | 
			
		||||
*   `common/`
 | 
			
		||||
*   `virtio/`
 | 
			
		||||
*   `rpmsg/`
 | 
			
		||||
*   `remoteproc/`
 | 
			
		||||
*   `proxy/`
 | 
			
		||||
 | 
			
		||||
OpenAMP system/machine support has been moved to libmetal, the system/machine
 | 
			
		||||
layer in the `apps/` directory is for system application initialization, and
 | 
			
		||||
resource table definition.
 | 
			
		||||
 | 
			
		||||
### libmetal APIs used in OpenAMP
 | 
			
		||||
Here are the libmetal APIs used by OpenAMP, if you want to port OpenAMP for your
 | 
			
		||||
system, you will need to implement the following libmetal APIs in the libmetal's
 | 
			
		||||
`lib/system/<SYS>` directory:
 | 
			
		||||
* alloc, for memory allocation and memory free
 | 
			
		||||
* cache, for flushing cache and invalidating cache
 | 
			
		||||
* io, for memory mapping. OpenAMP required memory mapping in order to access
 | 
			
		||||
  vrings and carved out memory.
 | 
			
		||||
* irq, for IRQ handler registration, IRQ disable/enable and global IRQ handling.
 | 
			
		||||
* mutex
 | 
			
		||||
* shmem (For RTOS, you can usually use the implementation from
 | 
			
		||||
  `lib/system/generic/`)
 | 
			
		||||
* sleep, at the moment, OpenAMP only requires microseconds sleep as when OpenAMP
 | 
			
		||||
  fails to get a buffer to send messages, it will call this function to sleep and
 | 
			
		||||
  then try again.
 | 
			
		||||
* time, for timestamp
 | 
			
		||||
* init, for libmetal initialization.
 | 
			
		||||
* atomic
 | 
			
		||||
 | 
			
		||||
Please refer to `lib/system/generic` when you port libmetal for your system.
 | 
			
		||||
 | 
			
		||||
If you a different compiler to GNU gcc, please refer to `lib/compiler/gcc/` to
 | 
			
		||||
port libmetal for your compiler. At the moment, OpenAMP needs the atomic
 | 
			
		||||
operations defined in `lib/compiler/gcc/atomic.h`.
 | 
			
		||||
 | 
			
		||||
## OpenAMP Compilation
 | 
			
		||||
OpenAMP uses CMake for library and demonstration application compilation.
 | 
			
		||||
OpenAMP requires libmetal library. For now, you will need to download and
 | 
			
		||||
compile libmetal library separately before you compiling OpenAMP library.
 | 
			
		||||
In future, we will try to make libmetal as a submodule to OpenAMP to make this
 | 
			
		||||
flow easier.
 | 
			
		||||
 | 
			
		||||
### Example to compile OpenAMP for Zephyr
 | 
			
		||||
You can compile OpenAMP library for Zephyr.
 | 
			
		||||
As OpenAMP uses libmetal, please refer to libmetal README to build libmetal
 | 
			
		||||
for Zephyr before building OpenAMP library for Zephyr.
 | 
			
		||||
As Zephyr uses CMake, we build OpenAMP library as a target of Zephyr CMake
 | 
			
		||||
project. Here is how to build libmetal for Zephyr:
 | 
			
		||||
```
 | 
			
		||||
    $ export ZEPHRY_GCC_VARIANT=zephyr
 | 
			
		||||
    $ export ZEPHRY_SDK_INSTALL_DIR=<where Zephyr SDK is installed>
 | 
			
		||||
    $ source <git_clone_zephyr_project_source_root>/zephyr-env.sh
 | 
			
		||||
 | 
			
		||||
    $ cmake <OpenAMP_source_root> \
 | 
			
		||||
      -DWITH_ZEPHYR=on -DBOARD=qemu_cortex_m3 \
 | 
			
		||||
      -DCMAKE_INCLUDE_PATH="<libmetal_zephyr_build_dir>/lib/include" \
 | 
			
		||||
      -DCMAKE_LIBRARY_PATH="<libmetal_zephyr_build_dir>/lib" \
 | 
			
		||||
    $ make VERBOSE=1 all
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Example to compile OpenAMP for communication between Linux processes:
 | 
			
		||||
* Install libsysfs devel and libhugetlbfs devel packages on your Linux host.
 | 
			
		||||
* build libmetal library on your host as follows:
 | 
			
		||||
 | 
			
		||||
    ```
 | 
			
		||||
        $ mkdir -p build-libmetal
 | 
			
		||||
        $ cd build-libmetal
 | 
			
		||||
        $ cmake <libmetal_source>
 | 
			
		||||
        $ make VERBOSE=1 DESTDIR=<libmetal_install> install
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
* build OpenAMP library on your host as follows:
 | 
			
		||||
 | 
			
		||||
        $ mkdir -p build-openamp
 | 
			
		||||
        $ cd build-openamp
 | 
			
		||||
        $ cmake <openamp_source> -DCMAKE_INCLUDE_PATH=<libmetal_built_include_dir> \
 | 
			
		||||
              -DCMAKE_LIBRARY_PATH=<libmetal_built_lib_dir> [-DWITH_APPS=ON]
 | 
			
		||||
        $ make VERBOSE=1 DESTDIR=$(pwd) install
 | 
			
		||||
 | 
			
		||||
The OpenAMP library will be generated to `build/usr/local/lib` directory,
 | 
			
		||||
headers will be generated to `build/usr/local/include` directory, and the
 | 
			
		||||
applications executable will be generated to `build/usr/local/bin`
 | 
			
		||||
directory.
 | 
			
		||||
 | 
			
		||||
* cmake option `-DWITH_APPS=ON` is to build the demonstration applications.
 | 
			
		||||
* If you have used `-DWITH_APPS=ON` to build the demos, you can try them on
 | 
			
		||||
  your Linux host as follows:
 | 
			
		||||
 | 
			
		||||
    ```
 | 
			
		||||
    # Start echo test server to wait for message to echo
 | 
			
		||||
    $ sudo LD_LIBRARY_PATH=<openamp_built>/usr/local/lib:<libmetal_built>/usr/local/lib \
 | 
			
		||||
       build/usr/local/bin/rpmsg-echo-shared
 | 
			
		||||
    # Run echo test to send message to echo test server
 | 
			
		||||
    $ sudo LD_LIBRARY_PATH=<openamp_built>/usr/local/lib:<libmetal_built>/usr/local/lib \
 | 
			
		||||
       build/usr/local/bin/rpmsg-echo-ping-shared 1
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
###  Example to compile Zynq UltraScale+ MPSoC R5 generic(baremetal) remote:
 | 
			
		||||
* build libmetal library on your host as follows:
 | 
			
		||||
  * Create your on cmake toolchain file to compile libmetal for your generic
 | 
			
		||||
    (baremetal) platform. Here is the example of the toolchain file:
 | 
			
		||||
 | 
			
		||||
    ```
 | 
			
		||||
        set (CMAKE_SYSTEM_PROCESSOR "arm"              CACHE STRING "")
 | 
			
		||||
        set (MACHINE "zynqmp_r5" CACHE STRING "")
 | 
			
		||||
 | 
			
		||||
        set (CROSS_PREFIX           "armr5-none-eabi-" CACHE STRING "")
 | 
			
		||||
        set (CMAKE_C_FLAGS          "-mfloat-abi=soft -mcpu=cortex-r5 -Wall -Werror -Wextra \
 | 
			
		||||
           -flto -Os -I/ws/xsdk/r5_0_bsp/psu_cortexr5_0/include" CACHE STRING "")
 | 
			
		||||
 | 
			
		||||
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto")
 | 
			
		||||
        SET(CMAKE_AR  "gcc-ar" CACHE STRING "")
 | 
			
		||||
        SET(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>")
 | 
			
		||||
        SET(CMAKE_C_ARCHIVE_FINISH   true)
 | 
			
		||||
 | 
			
		||||
        include (cross-generic-gcc)
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
  * Compile libmetal library:
 | 
			
		||||
 | 
			
		||||
    ```
 | 
			
		||||
        $ mkdir -p build-libmetal
 | 
			
		||||
        $ cd build-libmetal
 | 
			
		||||
        $ cmake <libmetal_source> -DCMAKE_TOOLCHAIN_FILE=<toolchain_file>
 | 
			
		||||
        $ make VERBOSE=1 DESTDIR=<libmetal_install> install
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
* build OpenAMP library on your host as follows:
 | 
			
		||||
  * Create your on cmake toolchain file to compile openamp for your generic
 | 
			
		||||
    (baremetal) platform. Here is the example of the toolchain file:
 | 
			
		||||
    ```
 | 
			
		||||
        set (CMAKE_SYSTEM_PROCESSOR "arm" CACHE STRING "")
 | 
			
		||||
        set (MACHINE                "zynqmp_r5" CACHE STRING "")
 | 
			
		||||
        set (CROSS_PREFIX           "armr5-none-eabi-" CACHE STRING "")
 | 
			
		||||
        set (CMAKE_C_FLAGS          "-mfloat-abi=soft -mcpu=cortex-r5 -Os -flto \
 | 
			
		||||
          -I/ws/libmetal-r5-generic/usr/local/include \
 | 
			
		||||
          -I/ws/xsdk/r5_0_bsp/psu_cortexr5_0/include" CACHE STRING "")
 | 
			
		||||
        set (CMAKE_ASM_FLAGS        "-mfloat-abi=soft -mcpu=cortex-r5" CACHE STRING "")
 | 
			
		||||
        set (PLATFORM_LIB_DEPS      "-lxil -lc -lm" CACHE STRING "")
 | 
			
		||||
        SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto")
 | 
			
		||||
        SET(CMAKE_AR  "gcc-ar" CACHE STRING "")
 | 
			
		||||
        SET(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>")
 | 
			
		||||
        SET(CMAKE_C_ARCHIVE_FINISH   true)
 | 
			
		||||
        set (CMAKE_FIND_ROOT_PATH /ws/libmetal-r5-generic/usr/local/lib \
 | 
			
		||||
            /ws/xsdk/r5_bsp/psu_cortexr5_0/lib )
 | 
			
		||||
 | 
			
		||||
        include (cross_generic_gcc)
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
  * We use cmake `find_path` and `find_library` to check if libmetal includes
 | 
			
		||||
    and libmetal library is in the includes and library search paths. However,
 | 
			
		||||
    for non-linux system, it doesn't work with `CMAKE_INCLUDE_PATH` and
 | 
			
		||||
    `CMAKE_LIBRARY_PATH` variables, and thus, we need to specify those paths
 | 
			
		||||
    in the toolchain file with `CMAKE_C_FLAGS` and `CMAKE_FIND_ROOT_PATH`.
 | 
			
		||||
* Compile the OpenAMP library:
 | 
			
		||||
 | 
			
		||||
    ```
 | 
			
		||||
    $ mkdir -p build-openamp
 | 
			
		||||
    $ cd build-openamp
 | 
			
		||||
    $ cmake <openamp_source> -DCMAKE_TOOLCHAIN_FILE=<toolchain_file>
 | 
			
		||||
    $ make VERBOSE=1 DESTDIR=$(pwd) install
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
The OpenAMP library will be generated to `build/usr/local/lib` directory,
 | 
			
		||||
headers will be generated to `build/usr/local/include` directory, and the
 | 
			
		||||
applications executable will be generated to `build/usr/local/bin`
 | 
			
		||||
directory.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Example to compile OpenAMP Linux Userspace for Zynq UltraScale+ MPSoC
 | 
			
		||||
We can use yocto to build the OpenAMP Linux userspace library and application.
 | 
			
		||||
open-amp and libmetal recipes are in this yocto layer:
 | 
			
		||||
https://github.com/OpenAMP/meta-openamp
 | 
			
		||||
* Add the `meta-openamp` layer to your layers in your yocto build project's `bblayers.conf` file.
 | 
			
		||||
* Add `libmetal` and `open-amp` to your packages list. E.g. add `libmetal` and `open-amp` to the
 | 
			
		||||
  `IMAGE_INSTALL_append` in the `local.conf` file.
 | 
			
		||||
* You can also add OpenAMP demos Linux applications packages to your yocto packages list. OpenAMP
 | 
			
		||||
  demo examples recipes are also in `meta-openamp`:
 | 
			
		||||
  https://github.com/OpenAMP/meta-openamp/tree/master/recipes-openamp/openamp-examples
 | 
			
		||||
 | 
			
		||||
In order to user OpenAMP(RPMsg) in Linux userspace, you will need to have put the IPI device,
 | 
			
		||||
  vring memory and shared buffer memory to your Linux kernel device tree. The device tree example
 | 
			
		||||
  can be found here:
 | 
			
		||||
  https://github.com/OpenAMP/open-amp/blob/master/apps/machine/zynqmp/openamp-linux-userspace.dtsi
 | 
			
		||||
 | 
			
		||||
## Supported System and Machines
 | 
			
		||||
For now, it supports:
 | 
			
		||||
* Zynq generic slave
 | 
			
		||||
* Zynq UltraScale+ MPSoC R5 generic slave
 | 
			
		||||
* Linux host OpenAMP between Linux userspace processes
 | 
			
		||||
* Linux userspace OpenAMP RPMsg master
 | 
			
		||||
* Linux userspace OpenAMP RPMsg slave
 | 
			
		||||
 | 
			
		||||
## Known Limitations:
 | 
			
		||||
1. In case of OpenAMP on Linux userspace for inter processors communication,
 | 
			
		||||
   it only supports static vrings and shared buffers.
 | 
			
		||||
2. `sudo` is required to run the OpenAMP demos between Linux processes, as
 | 
			
		||||
   it doesn't work on some systems if you are normal users.
 | 
			
		||||
 | 
			
		||||
For using the framework please refer to the wiki of the OpenAMP repo.
 | 
			
		||||
Subscribe to the open-amp mailing list at https://groups.google.com/group/open-amp.
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,71 @@
 | 
			
		|||
#ifndef _COMPILER_H_
 | 
			
		||||
#define _COMPILER_H_
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2014, Mentor Graphics Corporation
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**************************************************************************
 | 
			
		||||
 * FILE NAME
 | 
			
		||||
 *
 | 
			
		||||
 *       compiler.h
 | 
			
		||||
 *
 | 
			
		||||
 * DESCRIPTION
 | 
			
		||||
 *
 | 
			
		||||
 *       This file defines compiler-specific macros.
 | 
			
		||||
 *
 | 
			
		||||
 ***************************************************************************/
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* IAR ARM build tools */
 | 
			
		||||
#if defined(__ICCARM__)
 | 
			
		||||
 | 
			
		||||
#ifndef OPENAMP_PACKED_BEGIN
 | 
			
		||||
#define OPENAMP_PACKED_BEGIN __packed
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef OPENAMP_PACKED_END
 | 
			
		||||
#define OPENAMP_PACKED_END
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* GNUC */
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
 | 
			
		||||
#ifndef OPENAMP_PACKED_BEGIN
 | 
			
		||||
#define OPENAMP_PACKED_BEGIN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef OPENAMP_PACKED_END
 | 
			
		||||
#define OPENAMP_PACKED_END __attribute__((__packed__))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ARM GCC */
 | 
			
		||||
#elif defined(__CC_ARM)
 | 
			
		||||
 | 
			
		||||
#ifndef OPENAMP_PACKED_BEGIN
 | 
			
		||||
#define OPENAMP_PACKED_BEGIN _Pragma("pack(1U)")
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef OPENAMP_PACKED_END
 | 
			
		||||
#define OPENAMP_PACKED_END _Pragma("pack()")
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
/*
 | 
			
		||||
 * There is no default definition here to avoid wrong structures packing in case
 | 
			
		||||
 * of not supported compiler
 | 
			
		||||
 */
 | 
			
		||||
#error Please implement the structure packing macros for your compiler here!
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* _COMPILER_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,428 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2014, Mentor Graphics Corporation
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef ELF_LOADER_H_
 | 
			
		||||
#define ELF_LOADER_H_
 | 
			
		||||
 | 
			
		||||
#include <openamp/remoteproc.h>
 | 
			
		||||
#include <openamp/remoteproc_loader.h>
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* ELF32 base types - 32-bit. */
 | 
			
		||||
typedef uint32_t Elf32_Addr;
 | 
			
		||||
typedef uint16_t Elf32_Half;
 | 
			
		||||
typedef uint32_t Elf32_Off;
 | 
			
		||||
typedef int32_t Elf32_Sword;
 | 
			
		||||
typedef uint32_t Elf32_Word;
 | 
			
		||||
 | 
			
		||||
/* ELF64 base types - 64-bit. */
 | 
			
		||||
typedef uint64_t Elf64_Addr;
 | 
			
		||||
typedef uint16_t Elf64_Half;
 | 
			
		||||
typedef uint64_t Elf64_Off;
 | 
			
		||||
typedef int32_t Elf64_Sword;
 | 
			
		||||
typedef uint32_t Elf64_Word;
 | 
			
		||||
typedef uint64_t Elf64_Xword;
 | 
			
		||||
typedef int64_t Elf64_Sxword;
 | 
			
		||||
 | 
			
		||||
/* Size of ELF identifier field in the ELF file header. */
 | 
			
		||||
#define     EI_NIDENT       16
 | 
			
		||||
 | 
			
		||||
/* ELF32 file header */
 | 
			
		||||
typedef struct {
 | 
			
		||||
	unsigned char e_ident[EI_NIDENT];
 | 
			
		||||
	Elf32_Half e_type;
 | 
			
		||||
	Elf32_Half e_machine;
 | 
			
		||||
	Elf32_Word e_version;
 | 
			
		||||
	Elf32_Addr e_entry;
 | 
			
		||||
	Elf32_Off e_phoff;
 | 
			
		||||
	Elf32_Off e_shoff;
 | 
			
		||||
	Elf32_Word e_flags;
 | 
			
		||||
	Elf32_Half e_ehsize;
 | 
			
		||||
	Elf32_Half e_phentsize;
 | 
			
		||||
	Elf32_Half e_phnum;
 | 
			
		||||
	Elf32_Half e_shentsize;
 | 
			
		||||
	Elf32_Half e_shnum;
 | 
			
		||||
	Elf32_Half e_shstrndx;
 | 
			
		||||
} Elf32_Ehdr;
 | 
			
		||||
 | 
			
		||||
/* ELF64 file header */
 | 
			
		||||
typedef struct {
 | 
			
		||||
	unsigned char e_ident[EI_NIDENT];
 | 
			
		||||
	Elf64_Half e_type;
 | 
			
		||||
	Elf64_Half e_machine;
 | 
			
		||||
	Elf64_Word e_version;
 | 
			
		||||
	Elf64_Addr e_entry;
 | 
			
		||||
	Elf64_Off e_phoff;
 | 
			
		||||
	Elf64_Off e_shoff;
 | 
			
		||||
	Elf64_Word e_flags;
 | 
			
		||||
	Elf64_Half e_ehsize;
 | 
			
		||||
	Elf64_Half e_phentsize;
 | 
			
		||||
	Elf64_Half e_phnum;
 | 
			
		||||
	Elf64_Half e_shentsize;
 | 
			
		||||
	Elf64_Half e_shnum;
 | 
			
		||||
	Elf64_Half e_shstrndx;
 | 
			
		||||
} Elf64_Ehdr;
 | 
			
		||||
 | 
			
		||||
/* e_ident */
 | 
			
		||||
#define     ET_NONE         0
 | 
			
		||||
#define     ET_REL          1	/* Re-locatable file         */
 | 
			
		||||
#define     ET_EXEC         2	/* Executable file           */
 | 
			
		||||
#define     ET_DYN          3	/* Shared object file        */
 | 
			
		||||
#define     ET_CORE         4	/* Core file                 */
 | 
			
		||||
#define     ET_LOOS         0xfe00	/* Operating system-specific */
 | 
			
		||||
#define     ET_HIOS         0xfeff	/* Operating system-specific */
 | 
			
		||||
#define     ET_LOPROC       0xff00	/* remote_proc-specific        */
 | 
			
		||||
#define     ET_HIPROC       0xffff	/* remote_proc-specific        */
 | 
			
		||||
 | 
			
		||||
/* e_machine */
 | 
			
		||||
#define     EM_ARM          40	/* ARM/Thumb Architecture    */
 | 
			
		||||
 | 
			
		||||
/* e_version */
 | 
			
		||||
#define     EV_CURRENT      1	/* Current version           */
 | 
			
		||||
 | 
			
		||||
/* e_ident[] Identification Indexes */
 | 
			
		||||
#define     EI_MAG0         0	/* File identification       */
 | 
			
		||||
#define     EI_MAG1         1	/* File identification       */
 | 
			
		||||
#define     EI_MAG2         2	/* File identification       */
 | 
			
		||||
#define     EI_MAG3         3	/* File identification       */
 | 
			
		||||
#define     EI_CLASS        4	/* File class                */
 | 
			
		||||
#define     EI_DATA         5	/* Data encoding             */
 | 
			
		||||
#define     EI_VERSION      6	/* File version              */
 | 
			
		||||
#define     EI_OSABI        7	/* Operating system/ABI identification */
 | 
			
		||||
#define     EI_ABIVERSION   8	/* ABI version               */
 | 
			
		||||
#define     EI_PAD          9	/* Start of padding bytes    */
 | 
			
		||||
#define     EI_NIDENT       16	/* Size of e_ident[]         */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * EI_MAG0 to EI_MAG3 - A file's first 4 bytes hold amagic number, identifying
 | 
			
		||||
 * the file as an ELF object file
 | 
			
		||||
 */
 | 
			
		||||
#define     ELFMAG0         0x7f /* e_ident[EI_MAG0]          */
 | 
			
		||||
#define     ELFMAG1         'E'	/* e_ident[EI_MAG1]          */
 | 
			
		||||
#define     ELFMAG2         'L'	/* e_ident[EI_MAG2]          */
 | 
			
		||||
#define     ELFMAG3         'F'	/* e_ident[EI_MAG3]          */
 | 
			
		||||
#define     ELFMAG          "\177ELF"
 | 
			
		||||
#define     SELFMAG         4
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * EI_CLASS - The next byte, e_ident[EI_CLASS], identifies the file's class, or
 | 
			
		||||
 * capacity.
 | 
			
		||||
 */
 | 
			
		||||
#define     ELFCLASSNONE    0	/* Invalid class             */
 | 
			
		||||
#define     ELFCLASS32      1	/* 32-bit objects            */
 | 
			
		||||
#define     ELFCLASS64      2	/* 64-bit objects            */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * EI_DATA - Byte e_ident[EI_DATA] specifies the data encoding of the
 | 
			
		||||
 * remote_proc-specific data in the object file. The following encodings are
 | 
			
		||||
 * currently defined.
 | 
			
		||||
 */
 | 
			
		||||
#define     ELFDATANONE     0	/* Invalid data encoding     */
 | 
			
		||||
#define     ELFDATA2LSB     1	/* See Data encodings, below */
 | 
			
		||||
#define     ELFDATA2MSB     2	/* See Data encodings, below */
 | 
			
		||||
 | 
			
		||||
/* EI_OSABI - We do not define an OS specific ABI */
 | 
			
		||||
#define     ELFOSABI_NONE   0
 | 
			
		||||
 | 
			
		||||
/* ELF32 program header */
 | 
			
		||||
typedef struct elf32_phdr{
 | 
			
		||||
	Elf32_Word p_type;
 | 
			
		||||
	Elf32_Off p_offset;
 | 
			
		||||
	Elf32_Addr p_vaddr;
 | 
			
		||||
	Elf32_Addr p_paddr;
 | 
			
		||||
	Elf32_Word p_filesz;
 | 
			
		||||
	Elf32_Word p_memsz;
 | 
			
		||||
	Elf32_Word p_flags;
 | 
			
		||||
	Elf32_Word p_align;
 | 
			
		||||
} Elf32_Phdr;
 | 
			
		||||
 | 
			
		||||
/* ELF64 program header */
 | 
			
		||||
typedef struct elf64_phdr {
 | 
			
		||||
	Elf64_Word p_type;
 | 
			
		||||
	Elf64_Word p_flags;
 | 
			
		||||
	Elf64_Off p_offset;
 | 
			
		||||
	Elf64_Addr p_vaddr;
 | 
			
		||||
	Elf64_Addr p_paddr;
 | 
			
		||||
	Elf64_Xword p_filesz;
 | 
			
		||||
	Elf64_Xword p_memsz;
 | 
			
		||||
	Elf64_Xword p_align;
 | 
			
		||||
} Elf64_Phdr;
 | 
			
		||||
 | 
			
		||||
/* segment types */
 | 
			
		||||
#define PT_NULL    0
 | 
			
		||||
#define PT_LOAD    1
 | 
			
		||||
#define PT_DYNAMIC 2
 | 
			
		||||
#define PT_INTERP  3
 | 
			
		||||
#define PT_NOTE    4
 | 
			
		||||
#define PT_SHLIB   5
 | 
			
		||||
#define PT_PHDR    6
 | 
			
		||||
#define PT_TLS     7               /* Thread local storage segment */
 | 
			
		||||
#define PT_LOOS    0x60000000      /* OS-specific */
 | 
			
		||||
#define PT_HIOS    0x6fffffff      /* OS-specific */
 | 
			
		||||
#define PT_LOPROC  0x70000000
 | 
			
		||||
#define PT_HIPROC  0x7fffffff
 | 
			
		||||
 | 
			
		||||
/* ELF32 section header. */
 | 
			
		||||
typedef struct {
 | 
			
		||||
	Elf32_Word sh_name;
 | 
			
		||||
	Elf32_Word sh_type;
 | 
			
		||||
	Elf32_Word sh_flags;
 | 
			
		||||
	Elf32_Addr sh_addr;
 | 
			
		||||
	Elf32_Off sh_offset;
 | 
			
		||||
	Elf32_Word sh_size;
 | 
			
		||||
	Elf32_Word sh_link;
 | 
			
		||||
	Elf32_Word sh_info;
 | 
			
		||||
	Elf32_Word sh_addralign;
 | 
			
		||||
	Elf32_Word sh_entsize;
 | 
			
		||||
} Elf32_Shdr;
 | 
			
		||||
 | 
			
		||||
/* ELF64 section header. */
 | 
			
		||||
typedef struct {
 | 
			
		||||
	Elf64_Word sh_name;
 | 
			
		||||
	Elf64_Word sh_type;
 | 
			
		||||
	Elf64_Xword sh_flags;
 | 
			
		||||
	Elf64_Addr sh_addr;
 | 
			
		||||
	Elf64_Off sh_offset;
 | 
			
		||||
	Elf64_Xword sh_size;
 | 
			
		||||
	Elf64_Word sh_link;
 | 
			
		||||
	Elf64_Word sh_info;
 | 
			
		||||
	Elf64_Xword sh_addralign;
 | 
			
		||||
	Elf64_Xword sh_entsize;
 | 
			
		||||
} Elf64_Shdr;
 | 
			
		||||
 | 
			
		||||
/* sh_type */
 | 
			
		||||
#define     SHT_NULL                0
 | 
			
		||||
#define     SHT_PROGBITS            1
 | 
			
		||||
#define     SHT_SYMTAB              2
 | 
			
		||||
#define     SHT_STRTAB              3
 | 
			
		||||
#define     SHT_RELA                4
 | 
			
		||||
#define     SHT_HASH                5
 | 
			
		||||
#define     SHT_DYNAMIC             6
 | 
			
		||||
#define     SHT_NOTE                7
 | 
			
		||||
#define     SHT_NOBITS              8
 | 
			
		||||
#define     SHT_REL                 9
 | 
			
		||||
#define     SHT_SHLIB               10
 | 
			
		||||
#define     SHT_DYNSYM              11
 | 
			
		||||
#define     SHT_INIT_ARRAY          14
 | 
			
		||||
#define     SHT_FINI_ARRAY          15
 | 
			
		||||
#define     SHT_PREINIT_ARRAY       16
 | 
			
		||||
#define     SHT_GROUP               17
 | 
			
		||||
#define     SHT_SYMTAB_SHNDX        18
 | 
			
		||||
#define     SHT_LOOS                0x60000000
 | 
			
		||||
#define     SHT_HIOS                0x6fffffff
 | 
			
		||||
#define     SHT_LOPROC              0x70000000
 | 
			
		||||
#define     SHT_HIPROC              0x7fffffff
 | 
			
		||||
#define     SHT_LOUSER              0x80000000
 | 
			
		||||
#define     SHT_HIUSER              0xffffffff
 | 
			
		||||
 | 
			
		||||
/* sh_flags */
 | 
			
		||||
#define     SHF_WRITE       0x1
 | 
			
		||||
#define     SHF_ALLOC       0x2
 | 
			
		||||
#define     SHF_EXECINSTR   0x4
 | 
			
		||||
#define     SHF_MASKPROC    0xf0000000
 | 
			
		||||
 | 
			
		||||
/* Relocation entry (without addend) */
 | 
			
		||||
typedef struct {
 | 
			
		||||
	Elf32_Addr r_offset;
 | 
			
		||||
	Elf32_Word r_info;
 | 
			
		||||
 | 
			
		||||
} Elf32_Rel;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	Elf64_Addr r_offset;
 | 
			
		||||
	Elf64_Xword r_info;
 | 
			
		||||
 | 
			
		||||
} Elf64_Rel;
 | 
			
		||||
 | 
			
		||||
/* Relocation entry with addend */
 | 
			
		||||
typedef struct {
 | 
			
		||||
	Elf32_Addr r_offset;
 | 
			
		||||
	Elf32_Word r_info;
 | 
			
		||||
	Elf32_Sword r_addend;
 | 
			
		||||
 | 
			
		||||
} Elf32_Rela;
 | 
			
		||||
 | 
			
		||||
typedef struct elf64_rela {
 | 
			
		||||
	Elf64_Addr r_offset;
 | 
			
		||||
	Elf64_Xword r_info;
 | 
			
		||||
	Elf64_Sxword r_addend;
 | 
			
		||||
} Elf64_Rela;
 | 
			
		||||
 | 
			
		||||
/* Macros to extract information from 'r_info' field of relocation entries */
 | 
			
		||||
#define ELF32_R_SYM(i)  ((i) >> 8)
 | 
			
		||||
#define ELF32_R_TYPE(i) ((unsigned char)(i))
 | 
			
		||||
#define ELF64_R_SYM(i)  ((i) >> 32)
 | 
			
		||||
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
 | 
			
		||||
 | 
			
		||||
/* Symbol table entry */
 | 
			
		||||
typedef struct {
 | 
			
		||||
	Elf32_Word st_name;
 | 
			
		||||
	Elf32_Addr st_value;
 | 
			
		||||
	Elf32_Word st_size;
 | 
			
		||||
	unsigned char st_info;
 | 
			
		||||
	unsigned char st_other;
 | 
			
		||||
	Elf32_Half st_shndx;
 | 
			
		||||
 | 
			
		||||
} Elf32_Sym;
 | 
			
		||||
 | 
			
		||||
typedef struct elf64_sym {
 | 
			
		||||
	Elf64_Word st_name;
 | 
			
		||||
	unsigned char	st_info;
 | 
			
		||||
	unsigned char	st_other;
 | 
			
		||||
	Elf64_Half st_shndx;
 | 
			
		||||
	Elf64_Addr st_value;
 | 
			
		||||
	Elf64_Xword st_size;
 | 
			
		||||
} Elf64_Sym;
 | 
			
		||||
 | 
			
		||||
/* ARM specific dynamic relocation codes */
 | 
			
		||||
#define     R_ARM_GLOB_DAT	21	/* 0x15 */
 | 
			
		||||
#define     R_ARM_JUMP_SLOT	22	/* 0x16 */
 | 
			
		||||
#define     R_ARM_RELATIVE	23	/* 0x17 */
 | 
			
		||||
#define     R_ARM_ABS32		2	/* 0x02 */
 | 
			
		||||
 | 
			
		||||
/* ELF decoding information */
 | 
			
		||||
struct elf32_info {
 | 
			
		||||
	Elf32_Ehdr ehdr;
 | 
			
		||||
	unsigned int load_state;
 | 
			
		||||
	Elf32_Phdr *phdrs;
 | 
			
		||||
	Elf32_Shdr *shdrs;
 | 
			
		||||
	void *shstrtab;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct elf64_info {
 | 
			
		||||
	Elf64_Ehdr ehdr;
 | 
			
		||||
	unsigned int load_state;
 | 
			
		||||
	Elf64_Phdr *phdrs;
 | 
			
		||||
	Elf64_Shdr *shdrs;
 | 
			
		||||
	void *shstrtab;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define ELF_STATE_INIT              0x0UL
 | 
			
		||||
#define ELF_STATE_WAIT_FOR_PHDRS    0x100UL
 | 
			
		||||
#define ELF_STATE_WAIT_FOR_SHDRS    0x200UL
 | 
			
		||||
#define ELF_STATE_WAIT_FOR_SHSTRTAB 0x400UL
 | 
			
		||||
#define ELF_STATE_HDRS_COMPLETE     0x800UL
 | 
			
		||||
#define ELF_STATE_MASK              0xFF00UL
 | 
			
		||||
#define ELF_NEXT_SEGMENT_MASK       0x00FFUL
 | 
			
		||||
 | 
			
		||||
extern struct loader_ops elf_ops;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * elf_identify - check if it is an ELF file
 | 
			
		||||
 *
 | 
			
		||||
 * It will check if the input image header is an ELF header.
 | 
			
		||||
 *
 | 
			
		||||
 * @img_data: firmware private data which will be passed to user defined loader
 | 
			
		||||
 *            operations
 | 
			
		||||
 * @len: firmware header length
 | 
			
		||||
 *
 | 
			
		||||
 * return 0 for success or negative value for failure.
 | 
			
		||||
 */
 | 
			
		||||
int elf_identify(const void *img_data, size_t len);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * elf_load_header - Load ELF headers
 | 
			
		||||
 *
 | 
			
		||||
 * It will get the ELF header, the program header, and the section header.
 | 
			
		||||
 *
 | 
			
		||||
 * @img_data: image data
 | 
			
		||||
 * @offset: input image data offset to the start of image file
 | 
			
		||||
 * @len: input image data length
 | 
			
		||||
 * @img_info: pointer to store image information data
 | 
			
		||||
 * @last_load_state: last state return by this function
 | 
			
		||||
 * @noffset: pointer to next offset required by loading ELF header
 | 
			
		||||
 * @nlen: pointer to next data length required by loading ELF header
 | 
			
		||||
 *
 | 
			
		||||
 * return ELF loading header state, or negative value for failure
 | 
			
		||||
 */
 | 
			
		||||
int elf_load_header(const void *img_data, size_t offset, size_t len,
 | 
			
		||||
		    void **img_info, int last_load_state,
 | 
			
		||||
		    size_t *noffset, size_t *nlen);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * elf_load - load ELF data
 | 
			
		||||
 *
 | 
			
		||||
 * It will parse the ELF image and return the target device address,
 | 
			
		||||
 * offset to the start of the ELF image of the data to load and the
 | 
			
		||||
 * length of the data to load.
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc: pointer to remoteproc instance
 | 
			
		||||
 * @img_data: image data which will passed to the function.
 | 
			
		||||
 *            it can be NULL, if image data doesn't need to be handled
 | 
			
		||||
 *            by the load function. E.g. binary data which was
 | 
			
		||||
 *            loaded to the target memory.
 | 
			
		||||
 * @offset: last loaded image data offset to the start of image file
 | 
			
		||||
 * @len: last loaded image data length
 | 
			
		||||
 * @img_info: pointer to store image information data
 | 
			
		||||
 * @last_load_state: the returned state of the last function call.
 | 
			
		||||
 * @da: target device address, if the data to load is not for target memory
 | 
			
		||||
 *      the da will be set to ANY.
 | 
			
		||||
 * @noffset: pointer to next offset required by loading ELF header
 | 
			
		||||
 * @nlen: pointer to next data length required by loading ELF header
 | 
			
		||||
 * @padding: value to pad it is possible that a size of a segment in memory
 | 
			
		||||
 *           is larger than what it is in the ELF image. e.g. a segment
 | 
			
		||||
 *           can have stack section .bss. It doesn't need to copy image file
 | 
			
		||||
 *           space, in this case, it will be packed with 0.
 | 
			
		||||
 * @nmemsize: pointer to next data target memory size. The size of a segment
 | 
			
		||||
 *            in the target memory can be larger than the its size in the
 | 
			
		||||
 *            image file.
 | 
			
		||||
 *
 | 
			
		||||
 * return 0 for success, otherwise negative value for failure
 | 
			
		||||
 */
 | 
			
		||||
int elf_load(struct remoteproc *rproc, const void *img_data,
 | 
			
		||||
	     size_t offset, size_t len,
 | 
			
		||||
	     void **img_info, int last_load_state,
 | 
			
		||||
	     metal_phys_addr_t *da,
 | 
			
		||||
	     size_t *noffset, size_t *nlen,
 | 
			
		||||
	     unsigned char *padding, size_t *nmemsize);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * elf_release - Release ELF image information
 | 
			
		||||
 *
 | 
			
		||||
 * It will release ELF image information data.
 | 
			
		||||
 *
 | 
			
		||||
 * @img_info: pointer to ELF image information
 | 
			
		||||
 */
 | 
			
		||||
void elf_release(void *img_info);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * elf_get_entry - Get entry point
 | 
			
		||||
 *
 | 
			
		||||
 * It will return entry point specified in the ELF file.
 | 
			
		||||
 *
 | 
			
		||||
 * @img_info: pointer to ELF image information
 | 
			
		||||
 *
 | 
			
		||||
 * return entry address
 | 
			
		||||
 */
 | 
			
		||||
metal_phys_addr_t elf_get_entry(void *img_info);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * elf_locate_rsc_table - locate the resource table information
 | 
			
		||||
 *
 | 
			
		||||
 * It will return the length of the resource table, and the device address of
 | 
			
		||||
 * the resource table.
 | 
			
		||||
 *
 | 
			
		||||
 * @img_info: pointer to ELF image information
 | 
			
		||||
 * @da: pointer to the device address
 | 
			
		||||
 * @offset: pointer to the offset to in the ELF image of the resource
 | 
			
		||||
 *          table section.
 | 
			
		||||
 * @size: pointer to the size of the resource table section.
 | 
			
		||||
 *
 | 
			
		||||
 * return 0 if successfully locate the resource table, negative value for
 | 
			
		||||
 * failure.
 | 
			
		||||
 */
 | 
			
		||||
int elf_locate_rsc_table(void *img_info, metal_phys_addr_t *da,
 | 
			
		||||
			 size_t *offset, size_t *size);
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* ELF_LOADER_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2014, Mentor Graphics Corporation
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef OPEN_AMP_H_
 | 
			
		||||
#define OPEN_AMP_H_
 | 
			
		||||
 | 
			
		||||
#include <openamp/rpmsg.h>
 | 
			
		||||
#include <openamp/rpmsg_virtio.h>
 | 
			
		||||
#include <openamp/remoteproc.h>
 | 
			
		||||
#include <openamp/remoteproc_virtio.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif				/* OPEN_AMP_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,871 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Remoteproc Framework
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright(c) 2018 Xilinx Ltd.
 | 
			
		||||
 * Copyright(c) 2011 Texas Instruments, Inc.
 | 
			
		||||
 * Copyright(c) 2011 Google, Inc.
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef REMOTEPROC_H
 | 
			
		||||
#define REMOTEPROC_H
 | 
			
		||||
 | 
			
		||||
#include <metal/io.h>
 | 
			
		||||
#include <metal/mutex.h>
 | 
			
		||||
#include <openamp/compiler.h>
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define RSC_NOTIFY_ID_ANY 0xFFFFFFFFUL
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct resource_table - firmware resource table header
 | 
			
		||||
 * @ver: version number
 | 
			
		||||
 * @num: number of resource entries
 | 
			
		||||
 * @reserved: reserved (must be zero)
 | 
			
		||||
 * @offset: array of offsets pointing at the various resource entries
 | 
			
		||||
 *
 | 
			
		||||
 * A resource table is essentially a list of system resources required
 | 
			
		||||
 * by the remote remote_proc. It may also include configuration entries.
 | 
			
		||||
 * If needed, the remote remote_proc firmware should contain this table
 | 
			
		||||
 * as a dedicated ".resource_table" ELF section.
 | 
			
		||||
 *
 | 
			
		||||
 * Some resources entries are mere announcements, where the host is informed
 | 
			
		||||
 * of specific remoteproc configuration. Other entries require the host to
 | 
			
		||||
 * do something (e.g. allocate a system resource). Sometimes a negotiation
 | 
			
		||||
 * is expected, where the firmware requests a resource, and once allocated,
 | 
			
		||||
 * the host should provide back its details (e.g. address of an allocated
 | 
			
		||||
 * memory region).
 | 
			
		||||
 *
 | 
			
		||||
 * The header of the resource table, as expressed by this structure,
 | 
			
		||||
 * contains a version number (should we need to change this format in the
 | 
			
		||||
 * future), the number of available resource entries, and their offsets
 | 
			
		||||
 * in the table.
 | 
			
		||||
 *
 | 
			
		||||
 * Immediately following this header are the resource entries themselves,
 | 
			
		||||
 * each of which begins with a resource entry header (as described below).
 | 
			
		||||
 */
 | 
			
		||||
OPENAMP_PACKED_BEGIN
 | 
			
		||||
struct resource_table {
 | 
			
		||||
	uint32_t ver;
 | 
			
		||||
	uint32_t num;
 | 
			
		||||
	uint32_t reserved[2];
 | 
			
		||||
	uint32_t offset[0];
 | 
			
		||||
} OPENAMP_PACKED_END;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct fw_rsc_hdr - firmware resource entry header
 | 
			
		||||
 * @type: resource type
 | 
			
		||||
 * @data: resource data
 | 
			
		||||
 *
 | 
			
		||||
 * Every resource entry begins with a 'struct fw_rsc_hdr' header providing
 | 
			
		||||
 * its @type. The content of the entry itself will immediately follow
 | 
			
		||||
 * this header, and it should be parsed according to the resource type.
 | 
			
		||||
 */
 | 
			
		||||
OPENAMP_PACKED_BEGIN
 | 
			
		||||
struct fw_rsc_hdr {
 | 
			
		||||
	uint32_t type;
 | 
			
		||||
	uint8_t data[0];
 | 
			
		||||
} OPENAMP_PACKED_END;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum fw_resource_type - types of resource entries
 | 
			
		||||
 *
 | 
			
		||||
 * @RSC_CARVEOUT:   request for allocation of a physically contiguous
 | 
			
		||||
 *          memory region.
 | 
			
		||||
 * @RSC_DEVMEM:     request to iommu_map a memory-based peripheral.
 | 
			
		||||
 * @RSC_TRACE:      announces the availability of a trace buffer into which
 | 
			
		||||
 *          the remote remote_proc will be writing logs.
 | 
			
		||||
 * @RSC_VDEV:       declare support for a virtio device, and serve as its
 | 
			
		||||
 *          virtio header.
 | 
			
		||||
 * @RSC_VENDOR_START: start of the vendor specific resource types range
 | 
			
		||||
 * @RSC_VENDOR_END  : end of the vendor specific resource types range
 | 
			
		||||
 * @RSC_LAST:       just keep this one at the end
 | 
			
		||||
 *
 | 
			
		||||
 * For more details regarding a specific resource type, please see its
 | 
			
		||||
 * dedicated structure below.
 | 
			
		||||
 *
 | 
			
		||||
 * Please note that these values are used as indices to the rproc_handle_rsc
 | 
			
		||||
 * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to
 | 
			
		||||
 * check the validity of an index before the lookup table is accessed, so
 | 
			
		||||
 * please update it as needed.
 | 
			
		||||
 */
 | 
			
		||||
enum fw_resource_type {
 | 
			
		||||
	RSC_CARVEOUT = 0,
 | 
			
		||||
	RSC_DEVMEM = 1,
 | 
			
		||||
	RSC_TRACE = 2,
 | 
			
		||||
	RSC_VDEV = 3,
 | 
			
		||||
	RSC_RPROC_MEM = 4,
 | 
			
		||||
	RSC_FW_CHKSUM = 5,
 | 
			
		||||
	RSC_LAST = 6,
 | 
			
		||||
	RSC_VENDOR_START = 128,
 | 
			
		||||
	RSC_VENDOR_END = 512,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define FW_RSC_ADDR_ANY (0xFFFFFFFFFFFFFFFF)
 | 
			
		||||
#define FW_RSC_U32_ADDR_ANY (0xFFFFFFFF)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct fw_rsc_carveout - physically contiguous memory request
 | 
			
		||||
 * @da: device address
 | 
			
		||||
 * @pa: physical address
 | 
			
		||||
 * @len: length (in bytes)
 | 
			
		||||
 * @flags: iommu protection flags
 | 
			
		||||
 * @reserved: reserved (must be zero)
 | 
			
		||||
 * @name: human-readable name of the requested memory region
 | 
			
		||||
 *
 | 
			
		||||
 * This resource entry requests the host to allocate a physically contiguous
 | 
			
		||||
 * memory region.
 | 
			
		||||
 *
 | 
			
		||||
 * These request entries should precede other firmware resource entries,
 | 
			
		||||
 * as other entries might request placing other data objects inside
 | 
			
		||||
 * these memory regions (e.g. data/code segments, trace resource entries, ...).
 | 
			
		||||
 *
 | 
			
		||||
 * Allocating memory this way helps utilizing the reserved physical memory
 | 
			
		||||
 * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries
 | 
			
		||||
 * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB
 | 
			
		||||
 * pressure is important; it may have a substantial impact on performance.
 | 
			
		||||
 *
 | 
			
		||||
 * If the firmware is compiled with static addresses, then @da should specify
 | 
			
		||||
 * the expected device address of this memory region. If @da is set to
 | 
			
		||||
 * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then
 | 
			
		||||
 * overwrite @da with the dynamically allocated address.
 | 
			
		||||
 *
 | 
			
		||||
 * We will always use @da to negotiate the device addresses, even if it
 | 
			
		||||
 * isn't using an iommu. In that case, though, it will obviously contain
 | 
			
		||||
 * physical addresses.
 | 
			
		||||
 *
 | 
			
		||||
 * Some remote remote_procs needs to know the allocated physical address
 | 
			
		||||
 * even if they do use an iommu. This is needed, e.g., if they control
 | 
			
		||||
 * hardware accelerators which access the physical memory directly (this
 | 
			
		||||
 * is the case with OMAP4 for instance). In that case, the host will
 | 
			
		||||
 * overwrite @pa with the dynamically allocated physical address.
 | 
			
		||||
 * Generally we don't want to expose physical addresses if we don't have to
 | 
			
		||||
 * (remote remote_procs are generally _not_ trusted), so we might want to
 | 
			
		||||
 * change this to happen _only_ when explicitly required by the hardware.
 | 
			
		||||
 *
 | 
			
		||||
 * @flags is used to provide IOMMU protection flags, and @name should
 | 
			
		||||
 * (optionally) contain a human readable name of this carveout region
 | 
			
		||||
 * (mainly for debugging purposes).
 | 
			
		||||
 */
 | 
			
		||||
OPENAMP_PACKED_BEGIN
 | 
			
		||||
struct fw_rsc_carveout {
 | 
			
		||||
	uint32_t type;
 | 
			
		||||
	uint32_t da;
 | 
			
		||||
	uint32_t pa;
 | 
			
		||||
	uint32_t len;
 | 
			
		||||
	uint32_t flags;
 | 
			
		||||
	uint32_t reserved;
 | 
			
		||||
	uint8_t name[32];
 | 
			
		||||
} OPENAMP_PACKED_END;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct fw_rsc_devmem - iommu mapping request
 | 
			
		||||
 * @da: device address
 | 
			
		||||
 * @pa: physical address
 | 
			
		||||
 * @len: length (in bytes)
 | 
			
		||||
 * @flags: iommu protection flags
 | 
			
		||||
 * @reserved: reserved (must be zero)
 | 
			
		||||
 * @name: human-readable name of the requested region to be mapped
 | 
			
		||||
 *
 | 
			
		||||
 * This resource entry requests the host to iommu map a physically contiguous
 | 
			
		||||
 * memory region. This is needed in case the remote remote_proc requires
 | 
			
		||||
 * access to certain memory-based peripherals; _never_ use it to access
 | 
			
		||||
 * regular memory.
 | 
			
		||||
 *
 | 
			
		||||
 * This is obviously only needed if the remote remote_proc is accessing memory
 | 
			
		||||
 * via an iommu.
 | 
			
		||||
 *
 | 
			
		||||
 * @da should specify the required device address, @pa should specify
 | 
			
		||||
 * the physical address we want to map, @len should specify the size of
 | 
			
		||||
 * the mapping and @flags is the IOMMU protection flags. As always, @name may
 | 
			
		||||
 * (optionally) contain a human readable name of this mapping (mainly for
 | 
			
		||||
 * debugging purposes).
 | 
			
		||||
 *
 | 
			
		||||
 * Note: at this point we just "trust" those devmem entries to contain valid
 | 
			
		||||
 * physical addresses, but this isn't safe and will be changed: eventually we
 | 
			
		||||
 * want remoteproc implementations to provide us ranges of physical addresses
 | 
			
		||||
 * the firmware is allowed to request, and not allow firmwares to request
 | 
			
		||||
 * access to physical addresses that are outside those ranges.
 | 
			
		||||
 */
 | 
			
		||||
OPENAMP_PACKED_BEGIN
 | 
			
		||||
struct fw_rsc_devmem {
 | 
			
		||||
	uint32_t type;
 | 
			
		||||
	uint32_t da;
 | 
			
		||||
	uint32_t pa;
 | 
			
		||||
	uint32_t len;
 | 
			
		||||
	uint32_t flags;
 | 
			
		||||
	uint32_t reserved;
 | 
			
		||||
	uint8_t name[32];
 | 
			
		||||
} OPENAMP_PACKED_END;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct fw_rsc_trace - trace buffer declaration
 | 
			
		||||
 * @da: device address
 | 
			
		||||
 * @len: length (in bytes)
 | 
			
		||||
 * @reserved: reserved (must be zero)
 | 
			
		||||
 * @name: human-readable name of the trace buffer
 | 
			
		||||
 *
 | 
			
		||||
 * This resource entry provides the host information about a trace buffer
 | 
			
		||||
 * into which the remote remote_proc will write log messages.
 | 
			
		||||
 *
 | 
			
		||||
 * @da specifies the device address of the buffer, @len specifies
 | 
			
		||||
 * its size, and @name may contain a human readable name of the trace buffer.
 | 
			
		||||
 *
 | 
			
		||||
 * After booting the remote remote_proc, the trace buffers are exposed to the
 | 
			
		||||
 * user via debugfs entries (called trace0, trace1, etc..).
 | 
			
		||||
 */
 | 
			
		||||
OPENAMP_PACKED_BEGIN
 | 
			
		||||
struct fw_rsc_trace {
 | 
			
		||||
	uint32_t type;
 | 
			
		||||
	uint32_t da;
 | 
			
		||||
	uint32_t len;
 | 
			
		||||
	uint32_t reserved;
 | 
			
		||||
	uint8_t name[32];
 | 
			
		||||
} OPENAMP_PACKED_END;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct fw_rsc_vdev_vring - vring descriptor entry
 | 
			
		||||
 * @da: device address
 | 
			
		||||
 * @align: the alignment between the consumer and producer parts of the vring
 | 
			
		||||
 * @num: num of buffers supported by this vring (must be power of two)
 | 
			
		||||
 * @notifyid is a unique rproc-wide notify index for this vring. This notify
 | 
			
		||||
 * index is used when kicking a remote remote_proc, to let it know that this
 | 
			
		||||
 * vring is triggered.
 | 
			
		||||
 * @reserved: reserved (must be zero)
 | 
			
		||||
 *
 | 
			
		||||
 * This descriptor is not a resource entry by itself; it is part of the
 | 
			
		||||
 * vdev resource type (see below).
 | 
			
		||||
 *
 | 
			
		||||
 * Note that @da should either contain the device address where
 | 
			
		||||
 * the remote remote_proc is expecting the vring, or indicate that
 | 
			
		||||
 * dynamically allocation of the vring's device address is supported.
 | 
			
		||||
 */
 | 
			
		||||
OPENAMP_PACKED_BEGIN
 | 
			
		||||
struct fw_rsc_vdev_vring {
 | 
			
		||||
	uint32_t da;
 | 
			
		||||
	uint32_t align;
 | 
			
		||||
	uint32_t num;
 | 
			
		||||
	uint32_t notifyid;
 | 
			
		||||
	uint32_t reserved;
 | 
			
		||||
} OPENAMP_PACKED_END;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct fw_rsc_vdev - virtio device header
 | 
			
		||||
 * @id: virtio device id (as in virtio_ids.h)
 | 
			
		||||
 * @notifyid is a unique rproc-wide notify index for this vdev. This notify
 | 
			
		||||
 * index is used when kicking a remote remote_proc, to let it know that the
 | 
			
		||||
 * status/features of this vdev have changes.
 | 
			
		||||
 * @dfeatures specifies the virtio device features supported by the firmware
 | 
			
		||||
 * @gfeatures is a place holder used by the host to write back the
 | 
			
		||||
 * negotiated features that are supported by both sides.
 | 
			
		||||
 * @config_len is the size of the virtio config space of this vdev. The config
 | 
			
		||||
 * space lies in the resource table immediate after this vdev header.
 | 
			
		||||
 * @status is a place holder where the host will indicate its virtio progress.
 | 
			
		||||
 * @num_of_vrings indicates how many vrings are described in this vdev header
 | 
			
		||||
 * @reserved: reserved (must be zero)
 | 
			
		||||
 * @vring is an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'.
 | 
			
		||||
 *
 | 
			
		||||
 * This resource is a virtio device header: it provides information about
 | 
			
		||||
 * the vdev, and is then used by the host and its peer remote remote_procs
 | 
			
		||||
 * to negotiate and share certain virtio properties.
 | 
			
		||||
 *
 | 
			
		||||
 * By providing this resource entry, the firmware essentially asks remoteproc
 | 
			
		||||
 * to statically allocate a vdev upon registration of the rproc (dynamic vdev
 | 
			
		||||
 * allocation is not yet supported).
 | 
			
		||||
 *
 | 
			
		||||
 * Note: unlike virtualization systems, the term 'host' here means
 | 
			
		||||
 * the Linux side which is running remoteproc to control the remote
 | 
			
		||||
 * remote_procs. We use the name 'gfeatures' to comply with virtio's terms,
 | 
			
		||||
 * though there isn't really any virtualized guest OS here: it's the host
 | 
			
		||||
 * which is responsible for negotiating the final features.
 | 
			
		||||
 * Yeah, it's a bit confusing.
 | 
			
		||||
 *
 | 
			
		||||
 * Note: immediately following this structure is the virtio config space for
 | 
			
		||||
 * this vdev (which is specific to the vdev; for more info, read the virtio
 | 
			
		||||
 * spec). the size of the config space is specified by @config_len.
 | 
			
		||||
 */
 | 
			
		||||
OPENAMP_PACKED_BEGIN
 | 
			
		||||
struct fw_rsc_vdev {
 | 
			
		||||
	uint32_t type;
 | 
			
		||||
	uint32_t id;
 | 
			
		||||
	uint32_t notifyid;
 | 
			
		||||
	uint32_t dfeatures;
 | 
			
		||||
	uint32_t gfeatures;
 | 
			
		||||
	uint32_t config_len;
 | 
			
		||||
	uint8_t status;
 | 
			
		||||
	uint8_t num_of_vrings;
 | 
			
		||||
	uint8_t reserved[2];
 | 
			
		||||
	struct fw_rsc_vdev_vring vring[0];
 | 
			
		||||
} OPENAMP_PACKED_END;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct fw_rsc_vendor - remote processor vendor specific resource
 | 
			
		||||
 * @len: length of the resource
 | 
			
		||||
 *
 | 
			
		||||
 * This resource entry tells the host the vendor specific resource
 | 
			
		||||
 * required by the remote.
 | 
			
		||||
 *
 | 
			
		||||
 * These request entries should precede other shared resource entries
 | 
			
		||||
 * such as vdevs, vrings.
 | 
			
		||||
 */
 | 
			
		||||
OPENAMP_PACKED_BEGIN
 | 
			
		||||
struct fw_rsc_vendor {
 | 
			
		||||
	uint32_t type;
 | 
			
		||||
	uint32_t len;
 | 
			
		||||
} OPENAMP_PACKED_END;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct fw_rsc_rproc_mem - remote processor memory
 | 
			
		||||
 * @da: device address
 | 
			
		||||
 * @pa: physical address
 | 
			
		||||
 * @len: length (in bytes)
 | 
			
		||||
 * @reserved: reserved (must be zero)
 | 
			
		||||
 *
 | 
			
		||||
 * This resource entry tells the host to the remote processor
 | 
			
		||||
 * memory that the host can be used as shared memory.
 | 
			
		||||
 *
 | 
			
		||||
 * These request entries should precede other shared resource entries
 | 
			
		||||
 * such as vdevs, vrings.
 | 
			
		||||
 */
 | 
			
		||||
OPENAMP_PACKED_BEGIN
 | 
			
		||||
struct fw_rsc_rproc_mem {
 | 
			
		||||
	uint32_t type;
 | 
			
		||||
	uint32_t da;
 | 
			
		||||
	uint32_t pa;
 | 
			
		||||
	uint32_t len;
 | 
			
		||||
	uint32_t reserved;
 | 
			
		||||
} OPENAMP_PACKED_END;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * struct fw_rsc_fw_chksum - firmware checksum
 | 
			
		||||
 * @algo: algorithm to generate the cheksum
 | 
			
		||||
 * @chksum: checksum of the firmware loadable sections.
 | 
			
		||||
 *
 | 
			
		||||
 * This resource entry provides checksum for the firmware loadable sections.
 | 
			
		||||
 * It is used to check if the remote already runs with the expected firmware to
 | 
			
		||||
 * decide if it needs to start the remote if the remote is already running.
 | 
			
		||||
 */
 | 
			
		||||
OPENAMP_PACKED_BEGIN
 | 
			
		||||
struct fw_rsc_fw_chksum {
 | 
			
		||||
	uint32_t type;
 | 
			
		||||
	uint8_t algo[16];
 | 
			
		||||
	uint8_t chksum[64];
 | 
			
		||||
} OPENAMP_PACKED_END;
 | 
			
		||||
 | 
			
		||||
struct loader_ops;
 | 
			
		||||
struct image_store_ops;
 | 
			
		||||
struct remoteproc_ops;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct remoteproc_mem
 | 
			
		||||
 *
 | 
			
		||||
 * This structure presents the memory used by the remote processor
 | 
			
		||||
 *
 | 
			
		||||
 * @da: device memory
 | 
			
		||||
 * @pa: physical memory
 | 
			
		||||
 * @size: size of the memory
 | 
			
		||||
 * @io: pointer to the I/O region
 | 
			
		||||
 * @node: list node
 | 
			
		||||
 */
 | 
			
		||||
struct remoteproc_mem {
 | 
			
		||||
	metal_phys_addr_t da;
 | 
			
		||||
	metal_phys_addr_t pa;
 | 
			
		||||
	size_t size;
 | 
			
		||||
	char name[32];
 | 
			
		||||
	struct metal_io_region *io;
 | 
			
		||||
	struct metal_list node;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct remoteproc
 | 
			
		||||
 *
 | 
			
		||||
 * This structure is maintained by the remoteproc to represent the remote
 | 
			
		||||
 * processor instance. This structure acts as a prime parameter to use
 | 
			
		||||
 * the remoteproc APIs.
 | 
			
		||||
 *
 | 
			
		||||
 * @bootadd: boot address
 | 
			
		||||
 * @loader: executable loader
 | 
			
		||||
 * @lock: mutext lock
 | 
			
		||||
 * @ops: remoteproc operations
 | 
			
		||||
 * @rsc_table: pointer to resource table
 | 
			
		||||
 * @rsc_len: length of resource table
 | 
			
		||||
 * @rsc_io: metal I/O region of resource table
 | 
			
		||||
 * @mems: remoteproc memories
 | 
			
		||||
 * @vdevs: remoteproc virtio devices
 | 
			
		||||
 * @bitmap: bitmap for notify IDs for remoteproc subdevices
 | 
			
		||||
 * @state: remote processor state
 | 
			
		||||
 * @priv: private data
 | 
			
		||||
 */
 | 
			
		||||
struct remoteproc {
 | 
			
		||||
	metal_mutex_t lock;
 | 
			
		||||
	void *rsc_table;
 | 
			
		||||
	size_t rsc_len;
 | 
			
		||||
	struct metal_io_region *rsc_io;
 | 
			
		||||
	struct metal_list mems;
 | 
			
		||||
	struct metal_list vdevs;
 | 
			
		||||
	unsigned long bitmap;
 | 
			
		||||
	struct remoteproc_ops *ops;
 | 
			
		||||
	metal_phys_addr_t bootaddr;
 | 
			
		||||
	struct loader_ops *loader;
 | 
			
		||||
	unsigned int state;
 | 
			
		||||
	void *priv;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct remoteproc_ops
 | 
			
		||||
 *
 | 
			
		||||
 * remoteproc operations needs to be implemented by each remoteproc driver
 | 
			
		||||
 *
 | 
			
		||||
 * @init: initialize the remoteproc instance
 | 
			
		||||
 * @remove: remove the remoteproc instance
 | 
			
		||||
 * @mmap: memory mapped the mempory with physical address or destination
 | 
			
		||||
 *        address as input.
 | 
			
		||||
 * @handle_rsc: handle the vendor specific resource
 | 
			
		||||
 * @config: configure the remoteproc to make it ready to load and run
 | 
			
		||||
 *          executable
 | 
			
		||||
 * @start: kick the remoteproc to run application
 | 
			
		||||
 * @stop: stop the remoteproc from running application, the resource such as
 | 
			
		||||
 *        memory may not be off.
 | 
			
		||||
 * @shutdown: shutdown the remoteproc and release its resources.
 | 
			
		||||
 * @notify: notify the remote
 | 
			
		||||
 */
 | 
			
		||||
struct remoteproc_ops {
 | 
			
		||||
	struct remoteproc *(*init)(struct remoteproc *rproc,
 | 
			
		||||
				   struct remoteproc_ops *ops, void *arg);
 | 
			
		||||
	void (*remove)(struct remoteproc *rproc);
 | 
			
		||||
	void *(*mmap)(struct remoteproc *rproc,
 | 
			
		||||
		      metal_phys_addr_t *pa, metal_phys_addr_t *da,
 | 
			
		||||
		      size_t size, unsigned int attribute,
 | 
			
		||||
		      struct metal_io_region **io);
 | 
			
		||||
	int (*handle_rsc)(struct remoteproc *rproc, void *rsc, size_t len);
 | 
			
		||||
	int (*config)(struct remoteproc *rproc, void *data);
 | 
			
		||||
	int (*start)(struct remoteproc *rproc);
 | 
			
		||||
	int (*stop)(struct remoteproc *rproc);
 | 
			
		||||
	int (*shutdown)(struct remoteproc *rproc);
 | 
			
		||||
	int (*notify)(struct remoteproc *rproc, uint32_t id);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Remoteproc error codes */
 | 
			
		||||
#define RPROC_EBASE	0
 | 
			
		||||
#define RPROC_ENOMEM	(RPROC_EBASE + 1)
 | 
			
		||||
#define RPROC_EINVAL	(RPROC_EBASE + 2)
 | 
			
		||||
#define RPROC_ENODEV	(RPROC_EBASE + 3)
 | 
			
		||||
#define RPROC_EAGAIN	(RPROC_EBASE + 4)
 | 
			
		||||
#define RPROC_ERR_RSC_TAB_TRUNC (RPROC_EBASE + 5)
 | 
			
		||||
#define RPROC_ERR_RSC_TAB_VER   (RPROC_EBASE + 6)
 | 
			
		||||
#define RPROC_ERR_RSC_TAB_RSVD  (RPROC_EBASE + 7)
 | 
			
		||||
#define RPROC_ERR_RSC_TAB_VDEV_NRINGS (RPROC_EBASE + 9)
 | 
			
		||||
#define RPROC_ERR_RSC_TAB_NP          (RPROC_EBASE + 10)
 | 
			
		||||
#define RPROC_ERR_RSC_TAB_NS          (RPROC_EBASE + 11)
 | 
			
		||||
#define RPROC_ERR_LOADER_STATE (RPROC_EBASE + 12)
 | 
			
		||||
#define RPROC_EMAX	(RPROC_EBASE + 16)
 | 
			
		||||
#define RPROC_EPTR	(void *)(-1)
 | 
			
		||||
#define RPROC_EOF	(void *)(-1)
 | 
			
		||||
 | 
			
		||||
static inline long RPROC_PTR_ERR(const void *ptr)
 | 
			
		||||
{
 | 
			
		||||
	return (long)ptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int RPROC_IS_ERR(const void *ptr)
 | 
			
		||||
{
 | 
			
		||||
	if ((unsigned long)ptr >= (unsigned long)(-RPROC_EMAX))
 | 
			
		||||
		return 1;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void *RPROC_ERR_PTR(long error)
 | 
			
		||||
{
 | 
			
		||||
	return (void *)error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * enum rproc_state - remote processor states
 | 
			
		||||
 * @RPROC_OFFLINE:	remote is offline
 | 
			
		||||
 * @RPROC_READY:	remote is ready to start
 | 
			
		||||
 * @RPROC_RUNNING:	remote is up and running
 | 
			
		||||
 * @RPROC_SUSPENDED:	remote is suspended
 | 
			
		||||
 * @RPROC_ERROR:	remote has error; need to recover
 | 
			
		||||
 * @RPROC_STOPPED:	remote is stopped
 | 
			
		||||
 * @RPROC_LAST:		just keep this one at the end
 | 
			
		||||
 */
 | 
			
		||||
enum remoteproc_state {
 | 
			
		||||
	RPROC_OFFLINE		= 0,
 | 
			
		||||
	RPROC_CONFIGURED	= 1,
 | 
			
		||||
	RPROC_READY		= 2,
 | 
			
		||||
	RPROC_RUNNING		= 3,
 | 
			
		||||
	RPROC_SUSPENDED		= 4,
 | 
			
		||||
	RPROC_ERROR		= 5,
 | 
			
		||||
	RPROC_STOPPED		= 6,
 | 
			
		||||
	RPROC_LAST		= 7,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_init
 | 
			
		||||
 *
 | 
			
		||||
 * Initializes remoteproc resource.
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to remoteproc instance
 | 
			
		||||
 * @ops - pointer to remoteproc operations
 | 
			
		||||
 * @priv - pointer to private data
 | 
			
		||||
 *
 | 
			
		||||
 * @returns created remoteproc pointer
 | 
			
		||||
 */
 | 
			
		||||
struct remoteproc *remoteproc_init(struct remoteproc *rproc,
 | 
			
		||||
				   struct remoteproc_ops *ops, void *priv);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_remove
 | 
			
		||||
 *
 | 
			
		||||
 * Remove remoteproc resource
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to remoteproc instance
 | 
			
		||||
 *
 | 
			
		||||
 * returns 0 for success, negative value for failure
 | 
			
		||||
 */
 | 
			
		||||
int remoteproc_remove(struct remoteproc *rproc);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_init_mem
 | 
			
		||||
 *
 | 
			
		||||
 * Initialize remoteproc memory
 | 
			
		||||
 *
 | 
			
		||||
 * @mem - pointer to remoteproc memory
 | 
			
		||||
 * @char - memory name
 | 
			
		||||
 * @pa - physcial address
 | 
			
		||||
 * @da - device address
 | 
			
		||||
 * @size - memory size
 | 
			
		||||
 * @io - pointer to the I/O region
 | 
			
		||||
 */
 | 
			
		||||
static inline void
 | 
			
		||||
remoteproc_init_mem(struct remoteproc_mem *mem, const char *name,
 | 
			
		||||
		    metal_phys_addr_t pa, metal_phys_addr_t da,
 | 
			
		||||
		    size_t size, struct metal_io_region *io)
 | 
			
		||||
{
 | 
			
		||||
	if (!mem)
 | 
			
		||||
		return;
 | 
			
		||||
	if (name)
 | 
			
		||||
		strncpy(mem->name, name, sizeof(mem->name));
 | 
			
		||||
	else
 | 
			
		||||
		mem->name[0] = 0;
 | 
			
		||||
	mem->pa = pa;
 | 
			
		||||
	mem->da = da;
 | 
			
		||||
	mem->io = io;
 | 
			
		||||
	mem->size = size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_add_mem
 | 
			
		||||
 *
 | 
			
		||||
 * Add remoteproc memory
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to remoteproc
 | 
			
		||||
 * @mem - pointer to remoteproc memory
 | 
			
		||||
 */
 | 
			
		||||
static inline void
 | 
			
		||||
remoteproc_add_mem(struct remoteproc *rproc, struct remoteproc_mem *mem)
 | 
			
		||||
{
 | 
			
		||||
	if (!rproc || !mem)
 | 
			
		||||
		return;
 | 
			
		||||
	metal_list_add_tail(&rproc->mems, &mem->node);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_get_io_with_name
 | 
			
		||||
 *
 | 
			
		||||
 * get remoteproc memory I/O region with name
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to the remote processor
 | 
			
		||||
 * @name - name of the shared memory
 | 
			
		||||
 * @io - pointer to the pointer of the I/O region
 | 
			
		||||
 *
 | 
			
		||||
 * returns metal I/O region pointer, NULL for failure
 | 
			
		||||
 */
 | 
			
		||||
struct metal_io_region *
 | 
			
		||||
remoteproc_get_io_with_name(struct remoteproc *rproc,
 | 
			
		||||
			    const char *name);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_get_io_with_pa
 | 
			
		||||
 *
 | 
			
		||||
 * get remoteproc memory I/O region with physical address
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to the remote processor
 | 
			
		||||
 * @pa - physical address
 | 
			
		||||
 *
 | 
			
		||||
 * returns metal I/O region pointer, NULL for failure
 | 
			
		||||
 */
 | 
			
		||||
struct metal_io_region *
 | 
			
		||||
remoteproc_get_io_with_pa(struct remoteproc *rproc,
 | 
			
		||||
			  metal_phys_addr_t pa);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_get_io_with_da
 | 
			
		||||
 *
 | 
			
		||||
 * get remoteproc memory I/O region with device address
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to the remote processor
 | 
			
		||||
 * @da - device address
 | 
			
		||||
 * @offset - I/O region offset of the device address
 | 
			
		||||
 *
 | 
			
		||||
 * returns metal I/O region pointer, NULL for failure
 | 
			
		||||
 */
 | 
			
		||||
struct metal_io_region *
 | 
			
		||||
remoteproc_get_io_with_da(struct remoteproc *rproc,
 | 
			
		||||
			  metal_phys_addr_t da,
 | 
			
		||||
			  unsigned long *offset);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_get_io_with_va
 | 
			
		||||
 *
 | 
			
		||||
 * get remoteproc memory I/O region with virtual address
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to the remote processor
 | 
			
		||||
 * @va - virtual address
 | 
			
		||||
 *
 | 
			
		||||
 * returns metal I/O region pointer, NULL for failure
 | 
			
		||||
 */
 | 
			
		||||
struct metal_io_region *
 | 
			
		||||
remoteproc_get_io_with_va(struct remoteproc *rproc,
 | 
			
		||||
			  void *va);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_mmap
 | 
			
		||||
 *
 | 
			
		||||
 * remoteproc mmap memory
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to the remote processor
 | 
			
		||||
 * @pa - physical address pointer
 | 
			
		||||
 * @da - device address pointer
 | 
			
		||||
 * @size - size of the memory
 | 
			
		||||
 * @attribute - memory attribute
 | 
			
		||||
 * @io - pointer to the I/O region
 | 
			
		||||
 *
 | 
			
		||||
 * returns pointer to the memory
 | 
			
		||||
 */
 | 
			
		||||
void *remoteproc_mmap(struct remoteproc *rproc,
 | 
			
		||||
		      metal_phys_addr_t *pa, metal_phys_addr_t *da,
 | 
			
		||||
		      size_t size, unsigned int attribute,
 | 
			
		||||
		      struct metal_io_region **io);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_parse_rsc_table
 | 
			
		||||
 *
 | 
			
		||||
 * Parse resource table of remoteproc
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to remoteproc instance
 | 
			
		||||
 * @rsc_table - pointer to resource table
 | 
			
		||||
 * @rsc_size - resource table size
 | 
			
		||||
 *
 | 
			
		||||
 * returns 0 for success and negative value for errors
 | 
			
		||||
 */
 | 
			
		||||
int remoteproc_parse_rsc_table(struct remoteproc *rproc,
 | 
			
		||||
			       struct resource_table *rsc_table,
 | 
			
		||||
			       size_t rsc_size);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_set_rsc_table
 | 
			
		||||
 *
 | 
			
		||||
 * Parse and set resource table of remoteproc
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to remoteproc instance
 | 
			
		||||
 * @rsc_table - pointer to resource table
 | 
			
		||||
 * @rsc_size - resource table size
 | 
			
		||||
 *
 | 
			
		||||
 * returns 0 for success and negative value for errors
 | 
			
		||||
 */
 | 
			
		||||
int remoteproc_set_rsc_table(struct remoteproc *rproc,
 | 
			
		||||
			     struct resource_table *rsc_table,
 | 
			
		||||
			     size_t rsc_size);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_config
 | 
			
		||||
 *
 | 
			
		||||
 * This function configures the remote processor to get it
 | 
			
		||||
 * ready to load and run executable.
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to remoteproc instance to start
 | 
			
		||||
 * @data - configuration data
 | 
			
		||||
 *
 | 
			
		||||
 * returns 0 for success and negative value for errors
 | 
			
		||||
 */
 | 
			
		||||
int remoteproc_config(struct remoteproc *rproc, void *data);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_start
 | 
			
		||||
 *
 | 
			
		||||
 * This function starts the remote processor.
 | 
			
		||||
 * It assumes the firmware is already loaded,
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to remoteproc instance to start
 | 
			
		||||
 *
 | 
			
		||||
 * returns 0 for success and negative value for errors
 | 
			
		||||
 */
 | 
			
		||||
int remoteproc_start(struct remoteproc *rproc);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_stop
 | 
			
		||||
 *
 | 
			
		||||
 * This function stops the remote processor but it
 | 
			
		||||
 * will not release its resource.
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to remoteproc instance
 | 
			
		||||
 *
 | 
			
		||||
 * returns 0 for success and negative value for errors
 | 
			
		||||
 */
 | 
			
		||||
int remoteproc_stop(struct remoteproc *rproc);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_shutdown
 | 
			
		||||
 *
 | 
			
		||||
 * This function shutdown the remote processor and
 | 
			
		||||
 * release its resources.
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to remoteproc instance
 | 
			
		||||
 *
 | 
			
		||||
 * returns 0 for success and negative value for errors
 | 
			
		||||
 */
 | 
			
		||||
int remoteproc_shutdown(struct remoteproc *rproc);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_load
 | 
			
		||||
 *
 | 
			
		||||
 * load executable, it expects the user application defines how to
 | 
			
		||||
 * open the executable file and how to get data from the executable file
 | 
			
		||||
 * and how to load data to the target memory.
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc: pointer to the remoteproc instance
 | 
			
		||||
 * @path: optional path to the image file
 | 
			
		||||
 * @store: pointer to user defined image store argument
 | 
			
		||||
 * @store_ops: pointer to image store operations
 | 
			
		||||
 * @image_info: pointer to memory which stores image information used
 | 
			
		||||
 *              by remoteproc loader
 | 
			
		||||
 *
 | 
			
		||||
 * return 0 for success and negative value for failure
 | 
			
		||||
 */
 | 
			
		||||
int remoteproc_load(struct remoteproc *rproc, const char *path,
 | 
			
		||||
		    void *store, struct image_store_ops *store_ops,
 | 
			
		||||
		    void **img_info);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_load_noblock
 | 
			
		||||
 *
 | 
			
		||||
 * load executable, it expects the caller has loaded image data to local
 | 
			
		||||
 * memory and passed to the this function. If the function needs more
 | 
			
		||||
 * image data it will return the next expected image data offset and
 | 
			
		||||
 * the next expected image data length. If the function requires the
 | 
			
		||||
 * caller to download image data to the target memory, it will also
 | 
			
		||||
 * return the target physical address besides the offset and length.
 | 
			
		||||
 * This function can be used to load firmware in stream mode. In this
 | 
			
		||||
 * mode, you cannot do seek to the executable file. If the executable
 | 
			
		||||
 * is ELF, it cannot get the resource table section before it loads
 | 
			
		||||
 * the full ELF file. Furthermore, application usually don't store
 | 
			
		||||
 * the data which is loaded to local memory in streaming mode, and
 | 
			
		||||
 * thus, in this mode, it will load the binrary to the target memory
 | 
			
		||||
 * before it gets the resource table. And thus, when calling this funciton
 | 
			
		||||
 * don't put the target exectuable memory in the resource table, as
 | 
			
		||||
 * this function will parse the resource table after it loads the binary
 | 
			
		||||
 * to target memory.
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc: pointer to the remoteproc instance
 | 
			
		||||
 * @img_data: pointer to image data for remoteproc loader to parse
 | 
			
		||||
 * @offset: image data offset to the beginning of the image file
 | 
			
		||||
 * @len: image data length
 | 
			
		||||
 * @image_info: pointer to memory which stores image information used
 | 
			
		||||
 *              by remoteproc loader
 | 
			
		||||
 * @pa: pointer to the target memory physical address. If the next expected
 | 
			
		||||
 *      data doesn't need to load to the target memory, the function will
 | 
			
		||||
 *      set it to ANY.
 | 
			
		||||
 * @io: pointer to the target memory physical address. If the next expected
 | 
			
		||||
 *      data doesn't need to load to the target memory, the function will
 | 
			
		||||
 *      set it to ANY.
 | 
			
		||||
 * @noffset: pointer to the next image data offset to the beginning of
 | 
			
		||||
 *           the image file needs to load to local or to the target
 | 
			
		||||
 *           memory.
 | 
			
		||||
 * @nlen: pointer to the next image data length needs to load to local
 | 
			
		||||
 *        or to the target memory.
 | 
			
		||||
 * @nmlen: pointer to the memory size. It is only used when the next
 | 
			
		||||
 *         expected data is going to be loaded to the target memory. E.g.
 | 
			
		||||
 *         in ELF, it is possible that loadable segment in memory is
 | 
			
		||||
 *         larger that the segment data in the ELF file. In this case,
 | 
			
		||||
 *         application will need to pad the rest of the memory with
 | 
			
		||||
 *         padding.
 | 
			
		||||
 * @padding: pointer to the padding value. It is only used when the next
 | 
			
		||||
 *           expected data is going to be loaded to the target memory.
 | 
			
		||||
 *           and the target memory size is larger than the segment data in
 | 
			
		||||
 *           the executable file.
 | 
			
		||||
 *
 | 
			
		||||
 * return 0 for success and negative value for failure
 | 
			
		||||
 */
 | 
			
		||||
int remoteproc_load_noblock(struct remoteproc *rproc,
 | 
			
		||||
			    const void *img_data, size_t offset, size_t len,
 | 
			
		||||
			    void **img_info,
 | 
			
		||||
			    metal_phys_addr_t *pa, struct metal_io_region **io,
 | 
			
		||||
			    size_t *noffset, size_t *nlen,
 | 
			
		||||
			    size_t *nmlen, unsigned char *padding);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * remoteproc_allocate_id
 | 
			
		||||
 *
 | 
			
		||||
 * allocate notifyid for resource
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc - pointer to the remoteproc instance
 | 
			
		||||
 * @start - start of the id range
 | 
			
		||||
 * @end - end of the id range
 | 
			
		||||
 *
 | 
			
		||||
 * return allocated notify id
 | 
			
		||||
 */
 | 
			
		||||
unsigned int remoteproc_allocate_id(struct remoteproc *rproc,
 | 
			
		||||
				    unsigned int start,
 | 
			
		||||
				    unsigned int end);
 | 
			
		||||
 | 
			
		||||
/* remoteproc_create_virtio
 | 
			
		||||
 *
 | 
			
		||||
 * create virtio device, it returns pointer to the created virtio device.
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc: pointer to the remoteproc instance
 | 
			
		||||
 * @vdev_id: virtio device ID
 | 
			
		||||
 * @role: virtio device role
 | 
			
		||||
 * @rst_cb: virtio device reset callback
 | 
			
		||||
 *
 | 
			
		||||
 * return pointer to the created virtio device, NULL for failure.
 | 
			
		||||
 */
 | 
			
		||||
struct virtio_device *
 | 
			
		||||
remoteproc_create_virtio(struct remoteproc *rproc,
 | 
			
		||||
			 int vdev_id, unsigned int role,
 | 
			
		||||
			 void (*rst_cb)(struct virtio_device *vdev));
 | 
			
		||||
 | 
			
		||||
/* remoteproc_remove_virtio
 | 
			
		||||
 *
 | 
			
		||||
 * Remove virtio device
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc: pointer to the remoteproc instance
 | 
			
		||||
 * @vdev: pointer to the virtio device
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void remoteproc_remove_virtio(struct remoteproc *rproc,
 | 
			
		||||
			      struct virtio_device *vdev);
 | 
			
		||||
 | 
			
		||||
/* remoteproc_get_notification
 | 
			
		||||
 *
 | 
			
		||||
 * remoteproc is got notified, it will check its subdevices
 | 
			
		||||
 * for the notification
 | 
			
		||||
 *
 | 
			
		||||
 * @rproc -  pointer to the remoteproc instance
 | 
			
		||||
 * @notifyid - notificatin id
 | 
			
		||||
 *
 | 
			
		||||
 * return 0 for succeed, negative value for failure
 | 
			
		||||
 */
 | 
			
		||||
int remoteproc_get_notification(struct remoteproc *rproc,
 | 
			
		||||
				uint32_t notifyid);
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* REMOTEPROC_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,108 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2014, Mentor Graphics Corporation
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**************************************************************************
 | 
			
		||||
 * FILE NAME
 | 
			
		||||
 *
 | 
			
		||||
 *       remoteproc_loader.h
 | 
			
		||||
 *
 | 
			
		||||
 * COMPONENT
 | 
			
		||||
 *
 | 
			
		||||
 *         OpenAMP stack.
 | 
			
		||||
 *
 | 
			
		||||
 * DESCRIPTION
 | 
			
		||||
 *
 | 
			
		||||
 *       This file provides definitions for remoteproc loader
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 **************************************************************************/
 | 
			
		||||
#ifndef REMOTEPROC_LOADER_H_
 | 
			
		||||
#define REMOTEPROC_LOADER_H_
 | 
			
		||||
 | 
			
		||||
#include <metal/io.h>
 | 
			
		||||
#include <metal/list.h>
 | 
			
		||||
#include <metal/sys.h>
 | 
			
		||||
#include <openamp/remoteproc.h>
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Loader feature macros */
 | 
			
		||||
#define SUPPORT_SEEK 1UL
 | 
			
		||||
 | 
			
		||||
/* Remoteproc loader any address */
 | 
			
		||||
#define RPROC_LOAD_ANYADDR ((metal_phys_addr_t)-1)
 | 
			
		||||
 | 
			
		||||
/* Remoteproc loader Exectuable Image Parsing States */
 | 
			
		||||
/* Remoteproc loader parser intial state */
 | 
			
		||||
#define RPROC_LOADER_NOT_READY      0x0UL
 | 
			
		||||
/* Remoteproc loader ready to load, even it can be not finish parsing */
 | 
			
		||||
#define RPROC_LOADER_READY_TO_LOAD  0x10000UL
 | 
			
		||||
/* Remoteproc loader post data load */
 | 
			
		||||
#define RPROC_LOADER_POST_DATA_LOAD 0x20000UL
 | 
			
		||||
/* Remoteproc loader finished loading */
 | 
			
		||||
#define RPROC_LOADER_LOAD_COMPLETE  0x40000UL
 | 
			
		||||
/* Remoteproc loader state mask */
 | 
			
		||||
#define RPROC_LOADER_MASK           0x00FF0000UL
 | 
			
		||||
/* Remoteproc loader private mask */
 | 
			
		||||
#define RPROC_LOADER_PRIVATE_MASK   0x0000FFFFUL
 | 
			
		||||
/* Remoteproc loader reserved mask */
 | 
			
		||||
#define RPROC_LOADER_RESERVED_MASK  0x0F000000UL
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct image_store_ops - user defined image store operations
 | 
			
		||||
 * @open: user defined callback to open the "firmware" to prepare loading
 | 
			
		||||
 * @close: user defined callback to close the "firmware" to clean up
 | 
			
		||||
 *         after loading
 | 
			
		||||
 * @load: user defined callback to load the firmware contents to target
 | 
			
		||||
 *        memory or local memory
 | 
			
		||||
 * @features: loader supported features. e.g. seek
 | 
			
		||||
 */
 | 
			
		||||
struct image_store_ops {
 | 
			
		||||
	int (*open)(void *store, const char *path, const void **img_data);
 | 
			
		||||
	void (*close)(void *store);
 | 
			
		||||
	int (*load)(void *store, size_t offset, size_t size,
 | 
			
		||||
		    const void **data,
 | 
			
		||||
		    metal_phys_addr_t pa,
 | 
			
		||||
		    struct metal_io_region *io, char is_blocking);
 | 
			
		||||
	unsigned int features;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct loader_ops - loader oeprations
 | 
			
		||||
 * @load_header: define how to get the executable headers
 | 
			
		||||
 * @load_data: define how to load the target data
 | 
			
		||||
 * @locate_rsc_table: define how to get the resource table target address,
 | 
			
		||||
 *                    offset to the ELF image file and size of the resource
 | 
			
		||||
 *                    table.
 | 
			
		||||
 * @release: define how to release the loader
 | 
			
		||||
 * @get_entry: get entry address
 | 
			
		||||
 * @get_load_state: get load state from the image information
 | 
			
		||||
 */
 | 
			
		||||
struct loader_ops {
 | 
			
		||||
	int (*load_header)(const void *img_data, size_t offset, size_t len,
 | 
			
		||||
			   void **img_info, int last_state,
 | 
			
		||||
			   size_t *noffset, size_t *nlen);
 | 
			
		||||
	int (*load_data)(struct remoteproc *rproc,
 | 
			
		||||
			 const void *img_data, size_t offset, size_t len,
 | 
			
		||||
			 void **img_info, int last_load_state,
 | 
			
		||||
			 metal_phys_addr_t *da,
 | 
			
		||||
			 size_t *noffset, size_t *nlen,
 | 
			
		||||
			 unsigned char *padding, size_t *nmemsize);
 | 
			
		||||
	int (*locate_rsc_table)(void *img_info, metal_phys_addr_t *da,
 | 
			
		||||
				size_t *offset, size_t *size);
 | 
			
		||||
	void (*release)(void *img_info);
 | 
			
		||||
	metal_phys_addr_t (*get_entry)(void *img_info);
 | 
			
		||||
	int (*get_load_state)(void *img_info);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* REMOTEPROC_LOADER_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,150 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Remoteproc Virtio Framework
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright(c) 2018 Xilinx Ltd.
 | 
			
		||||
 * Copyright(c) 2011 Texas Instruments, Inc.
 | 
			
		||||
 * Copyright(c) 2011 Google, Inc.
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 *
 | 
			
		||||
 * * Redistributions of source code must retain the above copyright
 | 
			
		||||
 *   notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * * Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *   notice, this list of conditions and the following disclaimer in
 | 
			
		||||
 *   the documentation and/or other materials provided with the
 | 
			
		||||
 *   distribution.
 | 
			
		||||
 * * Neither the name Texas Instruments nor the names of its
 | 
			
		||||
 *   contributors may be used to endorse or promote products derived
 | 
			
		||||
 *   from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
			
		||||
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
			
		||||
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
			
		||||
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
			
		||||
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
			
		||||
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef REMOTEPROC_VIRTIO_H
 | 
			
		||||
#define REMOTEPROC_VIRTIO_H
 | 
			
		||||
 | 
			
		||||
#include <metal/io.h>
 | 
			
		||||
#include <metal/list.h>
 | 
			
		||||
#include <openamp/virtio.h>
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* define vdev notification funciton user should implement */
 | 
			
		||||
typedef int (*rpvdev_notify_func)(void *priv, uint32_t id);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct remoteproc_virtio
 | 
			
		||||
 * @priv pointer to private data
 | 
			
		||||
 * @notifyid notification id
 | 
			
		||||
 * @vdev_rsc address of vdev resource
 | 
			
		||||
 * @vdev_rsc_io metal I/O region of vdev_info, can be NULL
 | 
			
		||||
 * @notify notification function
 | 
			
		||||
 * @vdev virtio device
 | 
			
		||||
 * @node list node
 | 
			
		||||
 */
 | 
			
		||||
struct remoteproc_virtio {
 | 
			
		||||
	void *priv;
 | 
			
		||||
	uint32_t notify_id;
 | 
			
		||||
	void *vdev_rsc;
 | 
			
		||||
	struct metal_io_region *vdev_rsc_io;
 | 
			
		||||
	rpvdev_notify_func notify;
 | 
			
		||||
	struct virtio_device vdev;
 | 
			
		||||
	struct metal_list node;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rproc_virtio_create_vdev
 | 
			
		||||
 *
 | 
			
		||||
 * Create rproc virtio vdev
 | 
			
		||||
 *
 | 
			
		||||
 * @role: 0 - virtio master, 1 - virtio slave
 | 
			
		||||
 * @notifyid: virtio device notification id
 | 
			
		||||
 * @rsc: pointer to the virtio device resource
 | 
			
		||||
 * @rsc_io: pointer to the virtio device resource I/O region
 | 
			
		||||
 * @priv: pointer to the private data
 | 
			
		||||
 * @notify: vdev and virtqueue notification function
 | 
			
		||||
 * @rst_cb: reset virtio device callback
 | 
			
		||||
 *
 | 
			
		||||
 * return pointer to the created virtio device for success,
 | 
			
		||||
 * NULL for failure.
 | 
			
		||||
 */
 | 
			
		||||
struct virtio_device *
 | 
			
		||||
rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid,
 | 
			
		||||
			 void *rsc, struct metal_io_region *rsc_io,
 | 
			
		||||
			 void *priv,
 | 
			
		||||
			 rpvdev_notify_func notify,
 | 
			
		||||
			 virtio_dev_reset_cb rst_cb);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rproc_virtio_remove_vdev
 | 
			
		||||
 *
 | 
			
		||||
 * Create rproc virtio vdev
 | 
			
		||||
 *
 | 
			
		||||
 * @vdev - pointer to the virtio device
 | 
			
		||||
 */
 | 
			
		||||
void rproc_virtio_remove_vdev(struct virtio_device *vdev);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rproc_virtio_create_vring
 | 
			
		||||
 *
 | 
			
		||||
 * Create rproc virtio vring
 | 
			
		||||
 *
 | 
			
		||||
 * @vdev: pointer to the virtio device
 | 
			
		||||
 * @index: vring index in the virtio device
 | 
			
		||||
 * @notifyid: remoteproc vring notification id
 | 
			
		||||
 * @va: vring virtual address
 | 
			
		||||
 * @io: pointer to vring I/O region
 | 
			
		||||
 * @num_desc: number of descriptors
 | 
			
		||||
 * @align: vring alignment
 | 
			
		||||
 *
 | 
			
		||||
 * return 0 for success, negative value for failure.
 | 
			
		||||
 */
 | 
			
		||||
int rproc_virtio_init_vring(struct virtio_device *vdev, unsigned int index,
 | 
			
		||||
			    unsigned int notifyid, void *va,
 | 
			
		||||
			    struct metal_io_region *io,
 | 
			
		||||
			    unsigned int num_descs, unsigned int align);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rproc_virtio_notified
 | 
			
		||||
 *
 | 
			
		||||
 * remoteproc virtio is got notified
 | 
			
		||||
 *
 | 
			
		||||
 * @vdev - pointer to the virtio device
 | 
			
		||||
 * @notifyid - notify id
 | 
			
		||||
 *
 | 
			
		||||
 * return 0 for successful, negative value for failure
 | 
			
		||||
 */
 | 
			
		||||
int rproc_virtio_notified(struct virtio_device *vdev, uint32_t notifyid);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rproc_virtio_wait_remote_ready
 | 
			
		||||
 *
 | 
			
		||||
 * Blocking function, waiting for the remote core is ready to start
 | 
			
		||||
 * communications.
 | 
			
		||||
 *
 | 
			
		||||
 * @vdev - pointer to the virtio device
 | 
			
		||||
 *
 | 
			
		||||
 * return true when remote processor is ready.
 | 
			
		||||
 */
 | 
			
		||||
void rproc_virtio_wait_remote_ready(struct virtio_device *vdev);
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* REMOTEPROC_VIRTIO_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,357 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Remote processor messaging
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2011 Texas Instruments, Inc.
 | 
			
		||||
 * Copyright (C) 2011 Google, Inc.
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _RPMSG_H_
 | 
			
		||||
#define _RPMSG_H_
 | 
			
		||||
 | 
			
		||||
#include <openamp/compiler.h>
 | 
			
		||||
#include <metal/mutex.h>
 | 
			
		||||
#include <metal/list.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Configurable parameters */
 | 
			
		||||
#define RPMSG_NAME_SIZE		(32)
 | 
			
		||||
#define RPMSG_ADDR_BMP_SIZE	(4)
 | 
			
		||||
 | 
			
		||||
#define RPMSG_NS_EPT_ADDR	(0x35)
 | 
			
		||||
#define RPMSG_ADDR_ANY		0xFFFFFFFF
 | 
			
		||||
 | 
			
		||||
/* Error macros. */
 | 
			
		||||
#define RPMSG_SUCCESS		0
 | 
			
		||||
#define RPMSG_ERROR_BASE	-2000
 | 
			
		||||
#define RPMSG_ERR_NO_MEM	(RPMSG_ERROR_BASE - 1)
 | 
			
		||||
#define RPMSG_ERR_NO_BUFF	(RPMSG_ERROR_BASE - 2)
 | 
			
		||||
#define RPMSG_ERR_PARAM		(RPMSG_ERROR_BASE - 3)
 | 
			
		||||
#define RPMSG_ERR_DEV_STATE	(RPMSG_ERROR_BASE - 4)
 | 
			
		||||
#define RPMSG_ERR_BUFF_SIZE	(RPMSG_ERROR_BASE - 5)
 | 
			
		||||
#define RPMSG_ERR_INIT		(RPMSG_ERROR_BASE - 6)
 | 
			
		||||
#define RPMSG_ERR_ADDR		(RPMSG_ERROR_BASE - 7)
 | 
			
		||||
 | 
			
		||||
struct rpmsg_endpoint;
 | 
			
		||||
struct rpmsg_device;
 | 
			
		||||
 | 
			
		||||
typedef int (*rpmsg_ept_cb)(struct rpmsg_endpoint *ept, void *data,
 | 
			
		||||
			    size_t len, uint32_t src, void *priv);
 | 
			
		||||
typedef void (*rpmsg_ns_unbind_cb)(struct rpmsg_endpoint *ept);
 | 
			
		||||
typedef void (*rpmsg_ns_bind_cb)(struct rpmsg_device *rdev,
 | 
			
		||||
				 const char *name, uint32_t dest);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct rpmsg_endpoint - binds a local rpmsg address to its user
 | 
			
		||||
 * @name:name of the service supported
 | 
			
		||||
 * @rdev: pointer to the rpmsg device
 | 
			
		||||
 * @addr: local address of the endpoint
 | 
			
		||||
 * @dest_addr: address of the default remote endpoint binded.
 | 
			
		||||
 * @cb: user rx callback, return value of this callback is reserved
 | 
			
		||||
 *      for future use, for now, only allow RPMSG_SUCCESS as return value.
 | 
			
		||||
 * @ns_unbind_cb: end point service service unbind callback, called when remote
 | 
			
		||||
 *                ept is destroyed.
 | 
			
		||||
 * @node: end point node.
 | 
			
		||||
 * @addr: local rpmsg address
 | 
			
		||||
 * @priv: private data for the driver's use
 | 
			
		||||
 *
 | 
			
		||||
 * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as
 | 
			
		||||
 * it binds an rpmsg address with an rx callback handler.
 | 
			
		||||
 */
 | 
			
		||||
struct rpmsg_endpoint {
 | 
			
		||||
	char name[RPMSG_NAME_SIZE];
 | 
			
		||||
	struct rpmsg_device *rdev;
 | 
			
		||||
	uint32_t addr;
 | 
			
		||||
	uint32_t dest_addr;
 | 
			
		||||
	rpmsg_ept_cb cb;
 | 
			
		||||
	rpmsg_ns_unbind_cb ns_unbind_cb;
 | 
			
		||||
	struct metal_list node;
 | 
			
		||||
	void *priv;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct rpmsg_device_ops - RPMsg device operations
 | 
			
		||||
 * @send_offchannel_raw: send RPMsg data
 | 
			
		||||
 */
 | 
			
		||||
struct rpmsg_device_ops {
 | 
			
		||||
	int (*send_offchannel_raw)(struct rpmsg_device *rdev,
 | 
			
		||||
				   uint32_t src, uint32_t dst,
 | 
			
		||||
				   const void *data, int size, int wait);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct rpmsg_device - representation of a RPMsg device
 | 
			
		||||
 * @endpoints: list of endpoints
 | 
			
		||||
 * @ns_ept: name service endpoint
 | 
			
		||||
 * @bitmap: table endpoin address allocation.
 | 
			
		||||
 * @lock: mutex lock for rpmsg management
 | 
			
		||||
 * @ns_bind_cb: callback handler for name service announcement without local
 | 
			
		||||
 *              endpoints waiting to bind.
 | 
			
		||||
 * @ops: RPMsg device operations
 | 
			
		||||
 */
 | 
			
		||||
struct rpmsg_device {
 | 
			
		||||
	struct metal_list endpoints;
 | 
			
		||||
	struct rpmsg_endpoint ns_ept;
 | 
			
		||||
	unsigned long bitmap[RPMSG_ADDR_BMP_SIZE];
 | 
			
		||||
	metal_mutex_t lock;
 | 
			
		||||
	rpmsg_ns_bind_cb ns_bind_cb;
 | 
			
		||||
	struct rpmsg_device_ops ops;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_send_offchannel_raw() - send a message across to the remote processor,
 | 
			
		||||
 * specifying source and destination address.
 | 
			
		||||
 * @ept: the rpmsg endpoint
 | 
			
		||||
 * @data: payload of the message
 | 
			
		||||
 * @len: length of the payload
 | 
			
		||||
 *
 | 
			
		||||
 * This function sends @data of length @len to the remote @dst address from
 | 
			
		||||
 * the source @src address.
 | 
			
		||||
 * The message will be sent to the remote processor which the channel belongs
 | 
			
		||||
 * to.
 | 
			
		||||
 * In case there are no TX buffers available, the function will block until
 | 
			
		||||
 * one becomes available, or a timeout of 15 seconds elapses. When the latter
 | 
			
		||||
 * happens, -ERESTARTSYS is returned.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns number of bytes it has sent or negative error value on failure.
 | 
			
		||||
 */
 | 
			
		||||
int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src,
 | 
			
		||||
			      uint32_t dst, const void *data, int size,
 | 
			
		||||
			      int wait);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_send() - send a message across to the remote processor
 | 
			
		||||
 * @ept: the rpmsg endpoint
 | 
			
		||||
 * @data: payload of the message
 | 
			
		||||
 * @len: length of the payload
 | 
			
		||||
 *
 | 
			
		||||
 * This function sends @data of length @len based on the @ept.
 | 
			
		||||
 * The message will be sent to the remote processor which the channel belongs
 | 
			
		||||
 * to, using @ept's source and destination addresses.
 | 
			
		||||
 * In case there are no TX buffers available, the function will block until
 | 
			
		||||
 * one becomes available, or a timeout of 15 seconds elapses. When the latter
 | 
			
		||||
 * happens, -ERESTARTSYS is returned.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns number of bytes it has sent or negative error value on failure.
 | 
			
		||||
 */
 | 
			
		||||
static inline int rpmsg_send(struct rpmsg_endpoint *ept, const void *data,
 | 
			
		||||
			     int len)
 | 
			
		||||
{
 | 
			
		||||
	if (ept->dest_addr == RPMSG_ADDR_ANY)
 | 
			
		||||
		return RPMSG_ERR_ADDR;
 | 
			
		||||
	return rpmsg_send_offchannel_raw(ept, ept->addr, ept->dest_addr, data,
 | 
			
		||||
					 len, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_sendto() - send a message across to the remote processor, specify dst
 | 
			
		||||
 * @ept: the rpmsg endpoint
 | 
			
		||||
 * @data: payload of message
 | 
			
		||||
 * @len: length of payload
 | 
			
		||||
 * @dst: destination address
 | 
			
		||||
 *
 | 
			
		||||
 * This function sends @data of length @len to the remote @dst address.
 | 
			
		||||
 * The message will be sent to the remote processor which the @ept
 | 
			
		||||
 * channel belongs to, using @ept's source address.
 | 
			
		||||
 * In case there are no TX buffers available, the function will block until
 | 
			
		||||
 * one becomes available, or a timeout of 15 seconds elapses. When the latter
 | 
			
		||||
 * happens, -ERESTARTSYS is returned.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns number of bytes it has sent or negative error value on failure.
 | 
			
		||||
 */
 | 
			
		||||
static inline int rpmsg_sendto(struct rpmsg_endpoint *ept, const void *data,
 | 
			
		||||
			       int len, uint32_t dst)
 | 
			
		||||
{
 | 
			
		||||
	return rpmsg_send_offchannel_raw(ept, ept->addr, dst, data, len, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_send_offchannel() - send a message using explicit src/dst addresses
 | 
			
		||||
 * @ept: the rpmsg endpoint
 | 
			
		||||
 * @src: source address
 | 
			
		||||
 * @dst: destination address
 | 
			
		||||
 * @data: payload of message
 | 
			
		||||
 * @len: length of payload
 | 
			
		||||
 *
 | 
			
		||||
 * This function sends @data of length @len to the remote @dst address,
 | 
			
		||||
 * and uses @src as the source address.
 | 
			
		||||
 * The message will be sent to the remote processor which the @ept
 | 
			
		||||
 * channel belongs to.
 | 
			
		||||
 * In case there are no TX buffers available, the function will block until
 | 
			
		||||
 * one becomes available, or a timeout of 15 seconds elapses. When the latter
 | 
			
		||||
 * happens, -ERESTARTSYS is returned.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns number of bytes it has sent or negative error value on failure.
 | 
			
		||||
 */
 | 
			
		||||
static inline int rpmsg_send_offchannel(struct rpmsg_endpoint *ept,
 | 
			
		||||
					uint32_t src, uint32_t dst,
 | 
			
		||||
					const void *data, int len)
 | 
			
		||||
{
 | 
			
		||||
	return rpmsg_send_offchannel_raw(ept, src, dst, data, len, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_trysend() - send a message across to the remote processor
 | 
			
		||||
 * @ept: the rpmsg endpoint
 | 
			
		||||
 * @data: payload of message
 | 
			
		||||
 * @len: length of payload
 | 
			
		||||
 *
 | 
			
		||||
 * This function sends @data of length @len on the @ept channel.
 | 
			
		||||
 * The message will be sent to the remote processor which the @ept
 | 
			
		||||
 * channel belongs to, using @ept's source and destination addresses.
 | 
			
		||||
 * In case there are no TX buffers available, the function will immediately
 | 
			
		||||
 * return -ENOMEM without waiting until one becomes available.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns number of bytes it has sent or negative error value on failure.
 | 
			
		||||
 */
 | 
			
		||||
static inline int rpmsg_trysend(struct rpmsg_endpoint *ept, const void *data,
 | 
			
		||||
				int len)
 | 
			
		||||
{
 | 
			
		||||
	if (ept->dest_addr == RPMSG_ADDR_ANY)
 | 
			
		||||
		return RPMSG_ERR_ADDR;
 | 
			
		||||
	return rpmsg_send_offchannel_raw(ept, ept->addr, ept->dest_addr, data,
 | 
			
		||||
					 len, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_trysendto() - send a message across to the remote processor,
 | 
			
		||||
 * specify dst
 | 
			
		||||
 * @ept: the rpmsg endpoint
 | 
			
		||||
 * @data: payload of message
 | 
			
		||||
 * @len: length of payload
 | 
			
		||||
 * @dst: destination address
 | 
			
		||||
 *
 | 
			
		||||
 * This function sends @data of length @len to the remote @dst address.
 | 
			
		||||
 * The message will be sent to the remote processor which the @ept
 | 
			
		||||
 * channel belongs to, using @ept's source address.
 | 
			
		||||
 * In case there are no TX buffers available, the function will immediately
 | 
			
		||||
 * return -ENOMEM without waiting until one becomes available.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns number of bytes it has sent or negative error value on failure.
 | 
			
		||||
 */
 | 
			
		||||
static inline int rpmsg_trysendto(struct rpmsg_endpoint *ept, const void *data,
 | 
			
		||||
				  int len, uint32_t dst)
 | 
			
		||||
{
 | 
			
		||||
	return rpmsg_send_offchannel_raw(ept, ept->addr, dst, data, len, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_trysend_offchannel() - send a message using explicit src/dst addresses
 | 
			
		||||
 * @ept: the rpmsg endpoint
 | 
			
		||||
 * @src: source address
 | 
			
		||||
 * @dst: destination address
 | 
			
		||||
 * @data: payload of message
 | 
			
		||||
 * @len: length of payload
 | 
			
		||||
 *
 | 
			
		||||
 * This function sends @data of length @len to the remote @dst address,
 | 
			
		||||
 * and uses @src as the source address.
 | 
			
		||||
 * The message will be sent to the remote processor which the @ept
 | 
			
		||||
 * channel belongs to.
 | 
			
		||||
 * In case there are no TX buffers available, the function will immediately
 | 
			
		||||
 * return -ENOMEM without waiting until one becomes available.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns number of bytes it has sent or negative error value on failure.
 | 
			
		||||
 */
 | 
			
		||||
static inline int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept,
 | 
			
		||||
					   uint32_t src, uint32_t dst,
 | 
			
		||||
					   const void *data, int len)
 | 
			
		||||
{
 | 
			
		||||
	return rpmsg_send_offchannel_raw(ept, src, dst, data, len, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_init_ept - initialize rpmsg endpoint
 | 
			
		||||
 *
 | 
			
		||||
 * Initialize an RPMsg endpoint with a name, source address,
 | 
			
		||||
 * remoteproc address, endpoitn callback, and destroy endpoint callback.
 | 
			
		||||
 *
 | 
			
		||||
 * @ept: pointer to rpmsg endpoint
 | 
			
		||||
 * @name: service name associated to the endpoint
 | 
			
		||||
 * @src: local address of the endpoint
 | 
			
		||||
 * @dest: target address of the endpoint
 | 
			
		||||
 * @cb: endpoint callback
 | 
			
		||||
 * @ns_unbind_cb: end point service unbind callback, called when remote ept is
 | 
			
		||||
 *                destroyed.
 | 
			
		||||
 */
 | 
			
		||||
static inline void rpmsg_init_ept(struct rpmsg_endpoint *ept,
 | 
			
		||||
				  const char *name,
 | 
			
		||||
				  uint32_t src, uint32_t dest,
 | 
			
		||||
				  rpmsg_ept_cb cb,
 | 
			
		||||
				  rpmsg_ns_unbind_cb ns_unbind_cb)
 | 
			
		||||
{
 | 
			
		||||
	strncpy(ept->name, name, sizeof(ept->name));
 | 
			
		||||
	ept->addr = src;
 | 
			
		||||
	ept->dest_addr = dest;
 | 
			
		||||
	ept->cb = cb;
 | 
			
		||||
	ept->ns_unbind_cb = ns_unbind_cb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_create_ept - create rpmsg endpoint and register it to rpmsg device
 | 
			
		||||
 *
 | 
			
		||||
 * Create a RPMsg endpoint, initialize it with a name, source address,
 | 
			
		||||
 * remoteproc address, endpoitn callback, and destroy endpoint callback,
 | 
			
		||||
 * and register it to the RPMsg device.
 | 
			
		||||
 *
 | 
			
		||||
 * @ept: pointer to rpmsg endpoint
 | 
			
		||||
 * @name: service name associated to the endpoint
 | 
			
		||||
 * @src: local address of the endpoint
 | 
			
		||||
 * @dest: target address of the endpoint
 | 
			
		||||
 * @cb: endpoint callback
 | 
			
		||||
 * @ns_unbind_cb: end point service unbind callback, called when remote ept is
 | 
			
		||||
 *                destroyed.
 | 
			
		||||
 *
 | 
			
		||||
 * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as
 | 
			
		||||
 * it binds an rpmsg address with an rx callback handler.
 | 
			
		||||
 *
 | 
			
		||||
 * Rpmsg client should create an endpoint to discuss with remote. rpmsg client
 | 
			
		||||
 * provide at least a channel name, a callback for message notification and by
 | 
			
		||||
 * default endpoint source address should be set to RPMSG_ADDR_ANY.
 | 
			
		||||
 *
 | 
			
		||||
 * As an option Some rpmsg clients can specify an endpoint with a specific
 | 
			
		||||
 * source address.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev,
 | 
			
		||||
		     const char *name, uint32_t src, uint32_t dest,
 | 
			
		||||
		     rpmsg_ept_cb cb, rpmsg_ns_unbind_cb ns_unbind_cb);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_destroy_ept - destroy rpmsg endpoint and unregister it from rpmsg
 | 
			
		||||
 *                     device
 | 
			
		||||
 *
 | 
			
		||||
 * @ept: pointer to the rpmsg endpoint
 | 
			
		||||
 *
 | 
			
		||||
 * It unregisters the rpmsg endpoint from the rpmsg device and calls the
 | 
			
		||||
 * destroy endpoint callback if it is provided.
 | 
			
		||||
 */
 | 
			
		||||
void rpmsg_destroy_ept(struct rpmsg_endpoint *ept);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * is_rpmsg_ept_ready - check if the rpmsg endpoint ready to send
 | 
			
		||||
 *
 | 
			
		||||
 * @ept: pointer to rpmsg endpoint
 | 
			
		||||
 *
 | 
			
		||||
 * Returns 1 if the rpmsg endpoint has both local addr and destination
 | 
			
		||||
 * addr set, 0 otherwise
 | 
			
		||||
 */
 | 
			
		||||
static inline unsigned int is_rpmsg_ept_ready(struct rpmsg_endpoint *ept)
 | 
			
		||||
{
 | 
			
		||||
	return (ept->dest_addr != RPMSG_ADDR_ANY &&
 | 
			
		||||
		ept->addr != RPMSG_ADDR_ANY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif				/* _RPMSG_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,119 @@
 | 
			
		|||
#ifndef RPMSG_RETARGET_H
 | 
			
		||||
#define RPMSG_RETARGET_H
 | 
			
		||||
 | 
			
		||||
#include <metal/mutex.h>
 | 
			
		||||
#include <openamp/open_amp.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* File Operations System call definitions */
 | 
			
		||||
#define OPEN_SYSCALL_ID  0x1UL
 | 
			
		||||
#define CLOSE_SYSCALL_ID 0x2UL
 | 
			
		||||
#define WRITE_SYSCALL_ID 0x3UL
 | 
			
		||||
#define READ_SYSCALL_ID  0x4UL
 | 
			
		||||
#define ACK_STATUS_ID    0x5UL
 | 
			
		||||
 | 
			
		||||
#define TERM_SYSCALL_ID  0x6UL
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_PROXY_ENDPOINT  0xFFUL
 | 
			
		||||
 | 
			
		||||
struct rpmsg_rpc_data;
 | 
			
		||||
 | 
			
		||||
typedef int (*rpmsg_rpc_poll)(void *arg);
 | 
			
		||||
typedef void (*rpmsg_rpc_shutdown_cb)(struct rpmsg_rpc_data *rpc);
 | 
			
		||||
 | 
			
		||||
struct rpmsg_rpc_syscall_header {
 | 
			
		||||
	int32_t int_field1;
 | 
			
		||||
	int32_t int_field2;
 | 
			
		||||
	uint32_t data_len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rpmsg_rpc_syscall {
 | 
			
		||||
	uint32_t id;
 | 
			
		||||
	struct rpmsg_rpc_syscall_header args;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct rpmsg_rpc_data {
 | 
			
		||||
	struct rpmsg_endpoint ept;
 | 
			
		||||
	int ept_destroyed;
 | 
			
		||||
	atomic_flag nacked;
 | 
			
		||||
	void *respbuf;
 | 
			
		||||
	size_t respbuf_len;
 | 
			
		||||
	rpmsg_rpc_poll poll;
 | 
			
		||||
	void *poll_arg;
 | 
			
		||||
	rpmsg_rpc_shutdown_cb shutdown_cb;
 | 
			
		||||
	metal_mutex_t lock;
 | 
			
		||||
	struct metal_spinlock buflock;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_rpc_init - initialize RPMsg remote procedure call
 | 
			
		||||
 *
 | 
			
		||||
 * This function is to intialize the remote procedure call
 | 
			
		||||
 * global data. RPMsg RPC will send request to remote and
 | 
			
		||||
 * wait for callback.
 | 
			
		||||
 *
 | 
			
		||||
 * @rpc: pointer to the global remote procedure call data
 | 
			
		||||
 * @rdev: pointer to the rpmsg device
 | 
			
		||||
 * @ept_name: name of the endpoint used by RPC
 | 
			
		||||
 * @ept_addr: address of the endpoint used by RPC
 | 
			
		||||
 * @ept_raddr: remote address of the endpoint used by RPC
 | 
			
		||||
 * @poll_arg: pointer to poll function argument
 | 
			
		||||
 * @poll: poll function
 | 
			
		||||
 * @shutdown_cb: shutdown callback function
 | 
			
		||||
 *
 | 
			
		||||
 * return 0 for success, and negative value for failure.
 | 
			
		||||
 */
 | 
			
		||||
int rpmsg_rpc_init(struct rpmsg_rpc_data *rpc,
 | 
			
		||||
		   struct rpmsg_device *rdev,
 | 
			
		||||
		   const char *ept_name, uint32_t ept_addr,
 | 
			
		||||
		   uint32_t ept_raddr,
 | 
			
		||||
		   void *poll_arg, rpmsg_rpc_poll poll,
 | 
			
		||||
		   rpmsg_rpc_shutdown_cb shutdown_cb);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_rpc_release - release RPMsg remote procedure call
 | 
			
		||||
 *
 | 
			
		||||
 * This function is to release remoteproc procedure call
 | 
			
		||||
 * global data.
 | 
			
		||||
 *
 | 
			
		||||
 * @rpc: pointer to the globacl remote procedure call
 | 
			
		||||
 */
 | 
			
		||||
void rpmsg_rpc_release(struct rpmsg_rpc_data *rpc);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_rpc_send - Request RPMsg RPC call
 | 
			
		||||
 *
 | 
			
		||||
 * This function sends RPC request it will return with the length
 | 
			
		||||
 * of data and the response buffer.
 | 
			
		||||
 *
 | 
			
		||||
 * @rpc: pointer to remoteproc procedure call data struct
 | 
			
		||||
 * @req: pointer to request buffer
 | 
			
		||||
 * @len: length of the request data
 | 
			
		||||
 * @resp: pointer to where store the response buffer
 | 
			
		||||
 * @resp_len: length of the response buffer
 | 
			
		||||
 *
 | 
			
		||||
 * return length of the received response, negative value for failure.
 | 
			
		||||
 */
 | 
			
		||||
int rpmsg_rpc_send(struct rpmsg_rpc_data *rpc,
 | 
			
		||||
		   void *req, size_t len,
 | 
			
		||||
		   void *resp, size_t resp_len);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_set_default_rpc - set default RPMsg RPC data
 | 
			
		||||
 *
 | 
			
		||||
 * The default RPC data is used to redirect standard C file operations
 | 
			
		||||
 * to RPMsg channels.
 | 
			
		||||
 *
 | 
			
		||||
 * @rpc: pointer to remoteproc procedure call data struct
 | 
			
		||||
 */
 | 
			
		||||
void rpmsg_set_default_rpc(struct rpmsg_rpc_data *rpc);
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* RPMSG_RETARGET_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,190 @@
 | 
			
		|||
/*
 | 
			
		||||
 * rpmsg based on virtio
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2018 Linaro, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _RPMSG_VIRTIO_H_
 | 
			
		||||
#define _RPMSG_VIRTIO_H_
 | 
			
		||||
 | 
			
		||||
#include <metal/io.h>
 | 
			
		||||
#include <metal/mutex.h>
 | 
			
		||||
#include <openamp/rpmsg.h>
 | 
			
		||||
#include <openamp/virtio.h>
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Configurable parameters */
 | 
			
		||||
#ifndef RPMSG_BUFFER_SIZE
 | 
			
		||||
#define RPMSG_BUFFER_SIZE	(512)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* The feature bitmap for virtio rpmsg */
 | 
			
		||||
#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
 | 
			
		||||
 | 
			
		||||
struct rpmsg_virtio_shm_pool;
 | 
			
		||||
/**
 | 
			
		||||
 * struct rpmsg_virtio_shm_pool - shared memory pool used for rpmsg buffers
 | 
			
		||||
 * @get_buffer: function to get buffer from the pool
 | 
			
		||||
 * @base: base address of the memory pool
 | 
			
		||||
 * @avail: available memory size
 | 
			
		||||
 * @size: total pool size
 | 
			
		||||
 */
 | 
			
		||||
struct rpmsg_virtio_shm_pool {
 | 
			
		||||
	void *base;
 | 
			
		||||
	size_t avail;
 | 
			
		||||
	size_t size;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct rpmsg_virtio_device - representation of a rpmsg device based on virtio
 | 
			
		||||
 * @rdev: rpmsg device, first property in the struct
 | 
			
		||||
 * @vdev: pointer to the virtio device
 | 
			
		||||
 * @rvq: pointer to receive virtqueue
 | 
			
		||||
 * @svq: pointer to send virtqueue
 | 
			
		||||
 * @shbuf_io: pointer to the shared buffer I/O region
 | 
			
		||||
 * @shpool: pointer to the shared buffers pool
 | 
			
		||||
 * @endpoints: list of endpoints.
 | 
			
		||||
 */
 | 
			
		||||
struct rpmsg_virtio_device {
 | 
			
		||||
	struct rpmsg_device rdev;
 | 
			
		||||
	struct virtio_device *vdev;
 | 
			
		||||
	struct virtqueue *rvq;
 | 
			
		||||
	struct virtqueue *svq;
 | 
			
		||||
	struct metal_io_region *shbuf_io;
 | 
			
		||||
	struct rpmsg_virtio_shm_pool *shpool;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define RPMSG_REMOTE	VIRTIO_DEV_SLAVE
 | 
			
		||||
#define RPMSG_MASTER	VIRTIO_DEV_MASTER
 | 
			
		||||
static inline unsigned int
 | 
			
		||||
	rpmsg_virtio_get_role(struct rpmsg_virtio_device *rvdev)
 | 
			
		||||
{
 | 
			
		||||
	return rvdev->vdev->role;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void rpmsg_virtio_set_status(struct rpmsg_virtio_device *rvdev,
 | 
			
		||||
					   uint8_t status)
 | 
			
		||||
{
 | 
			
		||||
	rvdev->vdev->func->set_status(rvdev->vdev, status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint8_t rpmsg_virtio_get_status(struct rpmsg_virtio_device *rvdev)
 | 
			
		||||
{
 | 
			
		||||
	return rvdev->vdev->func->get_status(rvdev->vdev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint32_t
 | 
			
		||||
	rpmsg_virtio_get_features(struct rpmsg_virtio_device *rvdev)
 | 
			
		||||
{
 | 
			
		||||
	return rvdev->vdev->func->get_features(rvdev->vdev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int
 | 
			
		||||
	rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev,
 | 
			
		||||
				       int flags, unsigned int nvqs,
 | 
			
		||||
				       const char *names[],
 | 
			
		||||
				       vq_callback * callbacks[])
 | 
			
		||||
{
 | 
			
		||||
	return virtio_create_virtqueues(rvdev->vdev, flags, nvqs, names,
 | 
			
		||||
					callbacks);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_virtio_get_buffer_size - get rpmsg virtio buffer size
 | 
			
		||||
 *
 | 
			
		||||
 * @rdev - pointer to the rpmsg device
 | 
			
		||||
 *
 | 
			
		||||
 * @return - next available buffer size for text, negative value for failure
 | 
			
		||||
 */
 | 
			
		||||
int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_init_vdev - initialize rpmsg virtio device
 | 
			
		||||
 * Master side:
 | 
			
		||||
 * Initialize RPMsg virtio queues and shared buffers, the address of shm can be
 | 
			
		||||
 * ANY. In this case, function will get shared memory from system shared memory
 | 
			
		||||
 * pools. If the vdev has RPMsg name service feature, this API will create an
 | 
			
		||||
 * name service endpoint.
 | 
			
		||||
 *
 | 
			
		||||
 * Slave side:
 | 
			
		||||
 * This API will not return until the driver ready is set by the master side.
 | 
			
		||||
 *
 | 
			
		||||
 * @param rvdev  - pointer to the rpmsg virtio device
 | 
			
		||||
 * @param vdev   - pointer to the virtio device
 | 
			
		||||
 * @param ns_bind_cb  - callback handler for name service announcement without
 | 
			
		||||
 *                      local endpoints waiting to bind.
 | 
			
		||||
 * @param shm_io - pointer to the share memory I/O region.
 | 
			
		||||
 * @param shpool - pointer to shared memory pool. rpmsg_virtio_init_shm_pool has
 | 
			
		||||
 *                 to be called first to fill this structure.
 | 
			
		||||
 *
 | 
			
		||||
 * @return - status of function execution
 | 
			
		||||
 */
 | 
			
		||||
int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev,
 | 
			
		||||
		    struct virtio_device *vdev,
 | 
			
		||||
		    rpmsg_ns_bind_cb ns_bind_cb,
 | 
			
		||||
		    struct metal_io_region *shm_io,
 | 
			
		||||
		    struct rpmsg_virtio_shm_pool *shpool);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_deinit_vdev - deinitialize rpmsg virtio device
 | 
			
		||||
 *
 | 
			
		||||
 * @param rvdev - pointer to the rpmsg virtio device
 | 
			
		||||
 */
 | 
			
		||||
void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_virtio_init_shm_pool - initialize default shared buffers pool
 | 
			
		||||
 *
 | 
			
		||||
 * RPMsg virtio has default shared buffers pool implementation.
 | 
			
		||||
 * The memory assigned to this pool will be dedicated to the RPMsg
 | 
			
		||||
 * virtio. This function has to be called before calling rpmsg_init_vdev,
 | 
			
		||||
 * to initialize the rpmsg_virtio_shm_pool structure.
 | 
			
		||||
 *
 | 
			
		||||
 * @param shpool - pointer to the shared buffers pool structure
 | 
			
		||||
 * @param shbuf - pointer to the beginning of shared buffers
 | 
			
		||||
 * @param size - shared buffers total size
 | 
			
		||||
 */
 | 
			
		||||
void rpmsg_virtio_init_shm_pool(struct rpmsg_virtio_shm_pool *shpool,
 | 
			
		||||
				void *shbuf, size_t size);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_virtio_get_rpmsg_device - get RPMsg device from RPMsg virtio device
 | 
			
		||||
 *
 | 
			
		||||
 * @param rvdev - pointer to RPMsg virtio device
 | 
			
		||||
 * @return - RPMsg device pointed by RPMsg virtio device
 | 
			
		||||
 */
 | 
			
		||||
static inline struct rpmsg_device *
 | 
			
		||||
rpmsg_virtio_get_rpmsg_device(struct rpmsg_virtio_device *rvdev)
 | 
			
		||||
{
 | 
			
		||||
	return &rvdev->rdev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_virtio_shm_pool_get_buffer - get buffer in the shared memory pool
 | 
			
		||||
 *
 | 
			
		||||
 * RPMsg virtio has default shared buffers pool implementation.
 | 
			
		||||
 * The memory assigned to this pool will be dedicated to the RPMsg
 | 
			
		||||
 * virtio. If you prefer to have other shared buffers allocation,
 | 
			
		||||
 * you can implement your rpmsg_virtio_shm_pool_get_buffer function.
 | 
			
		||||
 *
 | 
			
		||||
 * @param shpool - pointer to the shared buffers pool
 | 
			
		||||
 * @param size - shared buffers total size
 | 
			
		||||
 * @return - buffer pointer if free buffer is available, NULL otherwise.
 | 
			
		||||
 */
 | 
			
		||||
metal_weak void *
 | 
			
		||||
rpmsg_virtio_shm_pool_get_buffer(struct rpmsg_virtio_shm_pool *shpool,
 | 
			
		||||
				 size_t size);
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif	/* _RPMSG_VIRTIO_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,64 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2014, Mentor Graphics Corporation
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef RSC_TABLE_PARSER_H
 | 
			
		||||
#define RSC_TABLE_PARSER_H
 | 
			
		||||
 | 
			
		||||
#include <openamp/remoteproc.h>
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define RSC_TAB_SUPPORTED_VERSION           1
 | 
			
		||||
#define RSC_TAB_HEADER_SIZE                 12
 | 
			
		||||
#define RSC_TAB_MAX_VRINGS                  2
 | 
			
		||||
 | 
			
		||||
/* Standard control request handling. */
 | 
			
		||||
typedef int (*rsc_handler) (struct remoteproc *rproc, void *rsc);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * handle_rsc_table
 | 
			
		||||
 *
 | 
			
		||||
 * This function parses resource table.
 | 
			
		||||
 *
 | 
			
		||||
 * @param rproc     - pointer to remote remoteproc
 | 
			
		||||
 * @param rsc_table - resource table to parse
 | 
			
		||||
 * @param size      - size of rsc table
 | 
			
		||||
 * @param io        - pointer to the resource table I/O region
 | 
			
		||||
 *                    It can be NULL if the resource table
 | 
			
		||||
 *                    is in the local memory.
 | 
			
		||||
 *
 | 
			
		||||
 * @returns - execution status
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
int handle_rsc_table(struct remoteproc *rproc,
 | 
			
		||||
		     struct resource_table *rsc_table, int len,
 | 
			
		||||
		     struct metal_io_region *io);
 | 
			
		||||
int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc);
 | 
			
		||||
int handle_trace_rsc(struct remoteproc *rproc, void *rsc);
 | 
			
		||||
int handle_vdev_rsc(struct remoteproc *rproc, void *rsc);
 | 
			
		||||
int handle_vendor_rsc(struct remoteproc *rproc, void *rsc);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * find_rsc
 | 
			
		||||
 *
 | 
			
		||||
 * find out location of a resource type in the resource table.
 | 
			
		||||
 *
 | 
			
		||||
 * @rsc_table - pointer to the resource table
 | 
			
		||||
 * @rsc_type - type of the resource
 | 
			
		||||
 * @index - index of the resource of the specified type
 | 
			
		||||
 *
 | 
			
		||||
 * return the offset to the resource on success, or 0 on failure
 | 
			
		||||
 */
 | 
			
		||||
size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index);
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif				/* RSC_TABLE_PARSER_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,176 @@
 | 
			
		|||
/*
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 *
 | 
			
		||||
 * $FreeBSD$
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _VIRTIO_H_
 | 
			
		||||
#define _VIRTIO_H_
 | 
			
		||||
 | 
			
		||||
#include <openamp/virtqueue.h>
 | 
			
		||||
#include <metal/spinlock.h>
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* TODO: define this as compiler flags */
 | 
			
		||||
#ifndef VIRTIO_MAX_NUM_VRINGS
 | 
			
		||||
#define VIRTIO_MAX_NUM_VRINGS 2
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* VirtIO device IDs. */
 | 
			
		||||
#define VIRTIO_ID_NETWORK    0x01UL
 | 
			
		||||
#define VIRTIO_ID_BLOCK      0x02UL
 | 
			
		||||
#define VIRTIO_ID_CONSOLE    0x03UL
 | 
			
		||||
#define VIRTIO_ID_ENTROPY    0x04UL
 | 
			
		||||
#define VIRTIO_ID_BALLOON    0x05UL
 | 
			
		||||
#define VIRTIO_ID_IOMEMORY   0x06UL
 | 
			
		||||
#define VIRTIO_ID_RPMSG	     0x07UL /* remote processor messaging */
 | 
			
		||||
#define VIRTIO_ID_SCSI       0x08UL
 | 
			
		||||
#define VIRTIO_ID_9P         0x09UL
 | 
			
		||||
#define VIRTIO_DEV_ANY_ID    (-1)UL
 | 
			
		||||
 | 
			
		||||
/* Status byte for guest to report progress. */
 | 
			
		||||
#define VIRTIO_CONFIG_STATUS_ACK       0x01
 | 
			
		||||
#define VIRTIO_CONFIG_STATUS_DRIVER    0x02
 | 
			
		||||
#define VIRTIO_CONFIG_STATUS_DRIVER_OK 0x04
 | 
			
		||||
#define VIRTIO_CONFIG_STATUS_NEEDS_RESET 0x40
 | 
			
		||||
#define VIRTIO_CONFIG_STATUS_FAILED    0x80
 | 
			
		||||
 | 
			
		||||
/* Virtio device role */
 | 
			
		||||
#define VIRTIO_DEV_MASTER	0UL
 | 
			
		||||
#define VIRTIO_DEV_SLAVE	1UL
 | 
			
		||||
 | 
			
		||||
struct virtio_device_id {
 | 
			
		||||
	uint32_t device;
 | 
			
		||||
	uint32_t vendor;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Generate interrupt when the virtqueue ring is
 | 
			
		||||
 * completely used, even if we've suppressed them.
 | 
			
		||||
 */
 | 
			
		||||
#define VIRTIO_F_NOTIFY_ON_EMPTY (1 << 24)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The guest should never negotiate this feature; it
 | 
			
		||||
 * is used to detect faulty drivers.
 | 
			
		||||
 */
 | 
			
		||||
#define VIRTIO_F_BAD_FEATURE (1 << 30)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Some VirtIO feature bits (currently bits 28 through 31) are
 | 
			
		||||
 * reserved for the transport being used (eg. virtio_ring), the
 | 
			
		||||
 * rest are per-device feature bits.
 | 
			
		||||
 */
 | 
			
		||||
#define VIRTIO_TRANSPORT_F_START      28
 | 
			
		||||
#define VIRTIO_TRANSPORT_F_END        32
 | 
			
		||||
 | 
			
		||||
typedef void (*virtio_dev_reset_cb)(struct virtio_device *vdev);
 | 
			
		||||
 | 
			
		||||
struct virtio_dispatch;
 | 
			
		||||
 | 
			
		||||
struct virtio_feature_desc {
 | 
			
		||||
	uint32_t vfd_val;
 | 
			
		||||
	const char *vfd_str;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct proc_shm
 | 
			
		||||
 *
 | 
			
		||||
 * This structure is maintained by hardware interface layer for
 | 
			
		||||
 * shared memory information. The shared memory provides buffers
 | 
			
		||||
 * for use by the vring to exchange messages between the cores.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
struct virtio_buffer_info {
 | 
			
		||||
	/* Start address of shared memory used for buffers. */
 | 
			
		||||
	void *vaddr;
 | 
			
		||||
	/* Start physical address of shared memory used for buffers. */
 | 
			
		||||
	metal_phys_addr_t paddr;
 | 
			
		||||
	/* sharmed memory I/O region */
 | 
			
		||||
	struct metal_io_region *io;
 | 
			
		||||
	/* Size of shared memory. */
 | 
			
		||||
	unsigned long size;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct remoteproc_vring - remoteproc vring structure
 | 
			
		||||
 * @vq virtio queue
 | 
			
		||||
 * @va logical address
 | 
			
		||||
 * @notifyid vring notify id
 | 
			
		||||
 * @num_descs number of descriptors
 | 
			
		||||
 * @align vring alignment
 | 
			
		||||
 * @io metal I/O region of the vring memory, can be NULL
 | 
			
		||||
 */
 | 
			
		||||
struct virtio_vring_info {
 | 
			
		||||
	struct virtqueue *vq;
 | 
			
		||||
	struct vring_alloc_info info;
 | 
			
		||||
	uint32_t notifyid;
 | 
			
		||||
	struct metal_io_region *io;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Structure definition for virtio devices for use by the
 | 
			
		||||
 * applications/drivers
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct virtio_device {
 | 
			
		||||
	uint32_t index; /**< unique position on the virtio bus */
 | 
			
		||||
	struct virtio_device_id id; /**< the device type identification
 | 
			
		||||
				      *  (used to match it with a driver
 | 
			
		||||
				      */
 | 
			
		||||
	uint64_t features; /**< the features supported by both ends. */
 | 
			
		||||
	unsigned int role; /**< if it is virtio backend or front end. */
 | 
			
		||||
	virtio_dev_reset_cb reset_cb; /**< user registered device callback */
 | 
			
		||||
	const struct virtio_dispatch *func; /**< Virtio dispatch table */
 | 
			
		||||
	void *priv; /**< TODO: remove pointer to virtio_device private data */
 | 
			
		||||
	unsigned int vrings_num; /**< number of vrings */
 | 
			
		||||
	struct virtio_vring_info *vrings_info;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Helper functions.
 | 
			
		||||
 */
 | 
			
		||||
const char *virtio_dev_name(uint16_t devid);
 | 
			
		||||
void virtio_describe(struct virtio_device *dev, const char *msg,
 | 
			
		||||
		     uint32_t features,
 | 
			
		||||
		     struct virtio_feature_desc *feature_desc);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Functions for virtio device configuration as defined in Rusty Russell's
 | 
			
		||||
 * paper.
 | 
			
		||||
 * Drivers are expected to implement these functions in their respective codes.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct virtio_dispatch {
 | 
			
		||||
	uint8_t (*get_status)(struct virtio_device *dev);
 | 
			
		||||
	void (*set_status)(struct virtio_device *dev, uint8_t status);
 | 
			
		||||
	uint32_t (*get_features)(struct virtio_device *dev);
 | 
			
		||||
	void (*set_features)(struct virtio_device *dev, uint32_t feature);
 | 
			
		||||
	uint32_t (*negotiate_features)(struct virtio_device *dev,
 | 
			
		||||
				       uint32_t features);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Read/write a variable amount from the device specific (ie, network)
 | 
			
		||||
	 * configuration region. This region is encoded in the same endian as
 | 
			
		||||
	 * the guest.
 | 
			
		||||
	 */
 | 
			
		||||
	void (*read_config)(struct virtio_device *dev, uint32_t offset,
 | 
			
		||||
			    void *dst, int length);
 | 
			
		||||
	void (*write_config)(struct virtio_device *dev, uint32_t offset,
 | 
			
		||||
			     void *src, int length);
 | 
			
		||||
	void (*reset_device)(struct virtio_device *dev);
 | 
			
		||||
	void (*notify)(struct virtqueue *vq);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags,
 | 
			
		||||
			     unsigned int nvqs, const char *names[],
 | 
			
		||||
			     vq_callback *callbacks[]);
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif				/* _VIRTIO_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,152 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright Rusty Russell IBM Corporation 2007.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 *
 | 
			
		||||
 * $FreeBSD$
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_RING_H
 | 
			
		||||
#define	VIRTIO_RING_H
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* This marks a buffer as continuing via the next field. */
 | 
			
		||||
#define VRING_DESC_F_NEXT       1
 | 
			
		||||
/* This marks a buffer as write-only (otherwise read-only). */
 | 
			
		||||
#define VRING_DESC_F_WRITE      2
 | 
			
		||||
/* This means the buffer contains a list of buffer descriptors. */
 | 
			
		||||
#define VRING_DESC_F_INDIRECT	4
 | 
			
		||||
 | 
			
		||||
/* The Host uses this in used->flags to advise the Guest: don't kick me
 | 
			
		||||
 * when you add a buffer.  It's unreliable, so it's simply an
 | 
			
		||||
 * optimization.  Guest will still kick if it's out of buffers.
 | 
			
		||||
 */
 | 
			
		||||
#define VRING_USED_F_NO_NOTIFY  1
 | 
			
		||||
/* The Guest uses this in avail->flags to advise the Host: don't
 | 
			
		||||
 * interrupt me when you consume a buffer.  It's unreliable, so it's
 | 
			
		||||
 * simply an optimization.
 | 
			
		||||
 */
 | 
			
		||||
#define VRING_AVAIL_F_NO_INTERRUPT      1
 | 
			
		||||
 | 
			
		||||
/* VirtIO ring descriptors: 16 bytes.
 | 
			
		||||
 * These can chain together via "next".
 | 
			
		||||
 */
 | 
			
		||||
struct vring_desc {
 | 
			
		||||
	/* Address (guest-physical). */
 | 
			
		||||
	uint64_t addr;
 | 
			
		||||
	/* Length. */
 | 
			
		||||
	uint32_t len;
 | 
			
		||||
	/* The flags as indicated above. */
 | 
			
		||||
	uint16_t flags;
 | 
			
		||||
	/* We chain unused descriptors via this, too. */
 | 
			
		||||
	uint16_t next;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct vring_avail {
 | 
			
		||||
	uint16_t flags;
 | 
			
		||||
	uint16_t idx;
 | 
			
		||||
	uint16_t ring[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* uint32_t is used here for ids for padding reasons. */
 | 
			
		||||
struct vring_used_elem {
 | 
			
		||||
	/* Index of start of used descriptor chain. */
 | 
			
		||||
	uint32_t id;
 | 
			
		||||
	/* Total length of the descriptor chain which was written to. */
 | 
			
		||||
	uint32_t len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct vring_used {
 | 
			
		||||
	uint16_t flags;
 | 
			
		||||
	uint16_t idx;
 | 
			
		||||
	struct vring_used_elem ring[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct vring {
 | 
			
		||||
	unsigned int num;
 | 
			
		||||
 | 
			
		||||
	struct vring_desc *desc;
 | 
			
		||||
	struct vring_avail *avail;
 | 
			
		||||
	struct vring_used *used;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* The standard layout for the ring is a continuous chunk of memory which
 | 
			
		||||
 * looks like this.  We assume num is a power of 2.
 | 
			
		||||
 *
 | 
			
		||||
 * struct vring {
 | 
			
		||||
 *      // The actual descriptors (16 bytes each)
 | 
			
		||||
 *      struct vring_desc desc[num];
 | 
			
		||||
 *
 | 
			
		||||
 *      // A ring of available descriptor heads with free-running index.
 | 
			
		||||
 *      __u16 avail_flags;
 | 
			
		||||
 *      __u16 avail_idx;
 | 
			
		||||
 *      __u16 available[num];
 | 
			
		||||
 *      __u16 used_event_idx;
 | 
			
		||||
 *
 | 
			
		||||
 *      // Padding to the next align boundary.
 | 
			
		||||
 *      char pad[];
 | 
			
		||||
 *
 | 
			
		||||
 *      // A ring of used descriptor heads with free-running index.
 | 
			
		||||
 *      __u16 used_flags;
 | 
			
		||||
 *      __u16 used_idx;
 | 
			
		||||
 *      struct vring_used_elem used[num];
 | 
			
		||||
 *      __u16 avail_event_idx;
 | 
			
		||||
 * };
 | 
			
		||||
 *
 | 
			
		||||
 * NOTE: for VirtIO PCI, align is 4096.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * We publish the used event index at the end of the available ring, and vice
 | 
			
		||||
 * versa. They are at the end for backwards compatibility.
 | 
			
		||||
 */
 | 
			
		||||
#define vring_used_event(vr)	((vr)->avail->ring[(vr)->num])
 | 
			
		||||
#define vring_avail_event(vr)	((vr)->used->ring[(vr)->num].id & 0xFFFF)
 | 
			
		||||
 | 
			
		||||
static inline int vring_size(unsigned int num, unsigned long align)
 | 
			
		||||
{
 | 
			
		||||
	int size;
 | 
			
		||||
 | 
			
		||||
	size = num * sizeof(struct vring_desc);
 | 
			
		||||
	size += sizeof(struct vring_avail) + (num * sizeof(uint16_t)) +
 | 
			
		||||
	    sizeof(uint16_t);
 | 
			
		||||
	size = (size + align - 1) & ~(align - 1);
 | 
			
		||||
	size += sizeof(struct vring_used) +
 | 
			
		||||
	    (num * sizeof(struct vring_used_elem)) + sizeof(uint16_t);
 | 
			
		||||
 | 
			
		||||
	return size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
vring_init(struct vring *vr, unsigned int num, uint8_t *p, unsigned long align)
 | 
			
		||||
{
 | 
			
		||||
	vr->num = num;
 | 
			
		||||
	vr->desc = (struct vring_desc *)p;
 | 
			
		||||
	vr->avail = (struct vring_avail *)(p + num * sizeof(struct vring_desc));
 | 
			
		||||
	vr->used = (struct vring_used *)
 | 
			
		||||
	    (((unsigned long)&vr->avail->ring[num] + sizeof(uint16_t) +
 | 
			
		||||
	      align - 1) & ~(align - 1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The following is used with VIRTIO_RING_F_EVENT_IDX.
 | 
			
		||||
 *
 | 
			
		||||
 * Assuming a given event_idx value from the other size, if we have
 | 
			
		||||
 * just incremented index from old to new_idx, should we trigger an
 | 
			
		||||
 * event?
 | 
			
		||||
 */
 | 
			
		||||
static inline int
 | 
			
		||||
vring_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old)
 | 
			
		||||
{
 | 
			
		||||
	return (uint16_t)(new_idx - event_idx - 1) <
 | 
			
		||||
	    (uint16_t)(new_idx - old);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif				/* VIRTIO_RING_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,238 @@
 | 
			
		|||
#ifndef VIRTQUEUE_H_
 | 
			
		||||
#define VIRTQUEUE_H_
 | 
			
		||||
 | 
			
		||||
/*-
 | 
			
		||||
 * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-2-Clause
 | 
			
		||||
 *
 | 
			
		||||
 * $FreeBSD$
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef uint8_t boolean;
 | 
			
		||||
 | 
			
		||||
#include <openamp/virtio_ring.h>
 | 
			
		||||
#include <metal/alloc.h>
 | 
			
		||||
#include <metal/io.h>
 | 
			
		||||
 | 
			
		||||
/*Error Codes*/
 | 
			
		||||
#define VQ_ERROR_BASE                                 -3000
 | 
			
		||||
#define ERROR_VRING_FULL                              (VQ_ERROR_BASE - 1)
 | 
			
		||||
#define ERROR_INVLD_DESC_IDX                          (VQ_ERROR_BASE - 2)
 | 
			
		||||
#define ERROR_EMPTY_RING                              (VQ_ERROR_BASE - 3)
 | 
			
		||||
#define ERROR_NO_MEM                                  (VQ_ERROR_BASE - 4)
 | 
			
		||||
#define ERROR_VRING_MAX_DESC                          (VQ_ERROR_BASE - 5)
 | 
			
		||||
#define ERROR_VRING_ALIGN                             (VQ_ERROR_BASE - 6)
 | 
			
		||||
#define ERROR_VRING_NO_BUFF                           (VQ_ERROR_BASE - 7)
 | 
			
		||||
#define ERROR_VQUEUE_INVLD_PARAM                      (VQ_ERROR_BASE - 8)
 | 
			
		||||
 | 
			
		||||
#define VQUEUE_SUCCESS                                0
 | 
			
		||||
 | 
			
		||||
/* The maximum virtqueue size is 2^15. Use that value as the end of
 | 
			
		||||
 * descriptor chain terminator since it will never be a valid index
 | 
			
		||||
 * in the descriptor table. This is used to verify we are correctly
 | 
			
		||||
 * handling vq_free_cnt.
 | 
			
		||||
 */
 | 
			
		||||
#define VQ_RING_DESC_CHAIN_END                         32768
 | 
			
		||||
#define VIRTQUEUE_FLAG_INDIRECT                        0x0001
 | 
			
		||||
#define VIRTQUEUE_FLAG_EVENT_IDX                       0x0002
 | 
			
		||||
#define VIRTQUEUE_MAX_NAME_SZ                          32
 | 
			
		||||
 | 
			
		||||
/* Support for indirect buffer descriptors. */
 | 
			
		||||
#define VIRTIO_RING_F_INDIRECT_DESC    (1 << 28)
 | 
			
		||||
 | 
			
		||||
/* Support to suppress interrupt until specific index is reached. */
 | 
			
		||||
#define VIRTIO_RING_F_EVENT_IDX        (1 << 29)
 | 
			
		||||
 | 
			
		||||
struct virtqueue_buf {
 | 
			
		||||
	void *buf;
 | 
			
		||||
	int len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct vq_desc_extra {
 | 
			
		||||
	void *cookie;
 | 
			
		||||
	uint16_t ndescs;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct virtqueue {
 | 
			
		||||
	struct virtio_device *vq_dev;
 | 
			
		||||
	const char *vq_name;
 | 
			
		||||
	uint16_t vq_queue_index;
 | 
			
		||||
	uint16_t vq_nentries;
 | 
			
		||||
	uint32_t vq_flags;
 | 
			
		||||
	void (*callback)(struct virtqueue *vq);
 | 
			
		||||
	void (*notify)(struct virtqueue *vq);
 | 
			
		||||
	struct vring vq_ring;
 | 
			
		||||
	uint16_t vq_free_cnt;
 | 
			
		||||
	uint16_t vq_queued_cnt;
 | 
			
		||||
	void *shm_io; /* opaque pointer to data needed to allow v2p & p2v */
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Head of the free chain in the descriptor table. If
 | 
			
		||||
	 * there are no free descriptors, this will be set to
 | 
			
		||||
	 * VQ_RING_DESC_CHAIN_END.
 | 
			
		||||
	 */
 | 
			
		||||
	uint16_t vq_desc_head_idx;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Last consumed descriptor in the used table,
 | 
			
		||||
	 * trails vq_ring.used->idx.
 | 
			
		||||
	 */
 | 
			
		||||
	uint16_t vq_used_cons_idx;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Last consumed descriptor in the available table -
 | 
			
		||||
	 * used by the consumer side.
 | 
			
		||||
	 */
 | 
			
		||||
	uint16_t vq_available_idx;
 | 
			
		||||
 | 
			
		||||
#ifdef VQUEUE_DEBUG
 | 
			
		||||
	boolean vq_inuse;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Used by the host side during callback. Cookie
 | 
			
		||||
	 * holds the address of buffer received from other side.
 | 
			
		||||
	 * Other fields in this structure are not used currently.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	struct vq_desc_extra vq_descx[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* struct to hold vring specific information */
 | 
			
		||||
struct vring_alloc_info {
 | 
			
		||||
	void *vaddr;
 | 
			
		||||
	uint32_t align;
 | 
			
		||||
	uint16_t num_descs;
 | 
			
		||||
	uint16_t pad;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef void vq_callback(struct virtqueue *);
 | 
			
		||||
typedef void vq_notify(struct virtqueue *);
 | 
			
		||||
 | 
			
		||||
#ifdef VQUEUE_DEBUG
 | 
			
		||||
#include <metal/log.h>
 | 
			
		||||
#include <metal/assert.h>
 | 
			
		||||
 | 
			
		||||
#define VQASSERT(_vq, _exp, _msg) \
 | 
			
		||||
	do { \
 | 
			
		||||
		if (!(_exp)) { \
 | 
			
		||||
			metal_log(METAL_LOG_EMERGENCY, \
 | 
			
		||||
				  "%s: %s - _msg", __func__, (_vq)->vq_name); \
 | 
			
		||||
			metal_assert(_exp); \
 | 
			
		||||
		} \
 | 
			
		||||
	} while (0)
 | 
			
		||||
 | 
			
		||||
#define VQ_RING_ASSERT_VALID_IDX(_vq, _idx)            \
 | 
			
		||||
	VQASSERT((_vq), (_idx) < (_vq)->vq_nentries, "invalid ring index")
 | 
			
		||||
 | 
			
		||||
#define VQ_RING_ASSERT_CHAIN_TERM(_vq)                \
 | 
			
		||||
	VQASSERT((_vq), (_vq)->vq_desc_head_idx ==            \
 | 
			
		||||
	VQ_RING_DESC_CHAIN_END, \
 | 
			
		||||
	"full ring terminated incorrectly: invalid head")
 | 
			
		||||
 | 
			
		||||
#define VQ_PARAM_CHK(condition, status_var, status_err) \
 | 
			
		||||
	do {						\
 | 
			
		||||
		if (((status_var) == 0) && (condition)) { \
 | 
			
		||||
			status_var = status_err;        \
 | 
			
		||||
		}					\
 | 
			
		||||
	} while (0)
 | 
			
		||||
 | 
			
		||||
#define VQUEUE_BUSY(vq) \
 | 
			
		||||
	do {						     \
 | 
			
		||||
		if (!(vq)->vq_inuse)                 \
 | 
			
		||||
			(vq)->vq_inuse = true;               \
 | 
			
		||||
		else                                         \
 | 
			
		||||
			VQASSERT(vq, !(vq)->vq_inuse,\
 | 
			
		||||
				"VirtQueue already in use");  \
 | 
			
		||||
	} while (0)
 | 
			
		||||
 | 
			
		||||
#define VQUEUE_IDLE(vq)            ((vq)->vq_inuse = false)
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#define KASSERT(cond, str)
 | 
			
		||||
#define VQASSERT(_vq, _exp, _msg)
 | 
			
		||||
#define VQ_RING_ASSERT_VALID_IDX(_vq, _idx)
 | 
			
		||||
#define VQ_RING_ASSERT_CHAIN_TERM(_vq)
 | 
			
		||||
#define VQ_PARAM_CHK(condition, status_var, status_err)
 | 
			
		||||
#define VQUEUE_BUSY(vq)
 | 
			
		||||
#define VQUEUE_IDLE(vq)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int virtqueue_create(struct virtio_device *device, unsigned short id,
 | 
			
		||||
		     const char *name, struct vring_alloc_info *ring,
 | 
			
		||||
		     void (*callback)(struct virtqueue *vq),
 | 
			
		||||
		     void (*notify)(struct virtqueue *vq),
 | 
			
		||||
		     struct virtqueue *v_queue);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * virtqueue_set_shmem_io
 | 
			
		||||
 *
 | 
			
		||||
 * set virtqueue shared memory I/O region
 | 
			
		||||
 *
 | 
			
		||||
 * @vq - virt queue
 | 
			
		||||
 * @io - pointer to the shared memory I/O region
 | 
			
		||||
 */
 | 
			
		||||
static inline void virtqueue_set_shmem_io(struct virtqueue *vq,
 | 
			
		||||
					  struct metal_io_region *io)
 | 
			
		||||
{
 | 
			
		||||
	vq->shm_io = io;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list,
 | 
			
		||||
			 int readable, int writable, void *cookie);
 | 
			
		||||
 | 
			
		||||
void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx);
 | 
			
		||||
 | 
			
		||||
void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx,
 | 
			
		||||
				     uint32_t *len);
 | 
			
		||||
 | 
			
		||||
int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx,
 | 
			
		||||
				  uint32_t len);
 | 
			
		||||
 | 
			
		||||
void virtqueue_disable_cb(struct virtqueue *vq);
 | 
			
		||||
 | 
			
		||||
int virtqueue_enable_cb(struct virtqueue *vq);
 | 
			
		||||
 | 
			
		||||
void virtqueue_kick(struct virtqueue *vq);
 | 
			
		||||
 | 
			
		||||
static inline struct virtqueue *virtqueue_allocate(unsigned int num_desc_extra)
 | 
			
		||||
{
 | 
			
		||||
	struct virtqueue *vqs;
 | 
			
		||||
	uint32_t vq_size = sizeof(struct virtqueue) +
 | 
			
		||||
		 num_desc_extra * sizeof(struct vq_desc_extra);
 | 
			
		||||
 | 
			
		||||
	vqs = (struct virtqueue *)metal_allocate_memory(vq_size);
 | 
			
		||||
 | 
			
		||||
	if (vqs) {
 | 
			
		||||
		memset(vqs, 0x00, vq_size);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return vqs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void virtqueue_free(struct virtqueue *vq);
 | 
			
		||||
 | 
			
		||||
void virtqueue_dump(struct virtqueue *vq);
 | 
			
		||||
 | 
			
		||||
void virtqueue_notification(struct virtqueue *vq);
 | 
			
		||||
 | 
			
		||||
uint32_t virtqueue_get_desc_size(struct virtqueue *vq);
 | 
			
		||||
 | 
			
		||||
uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx);
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif				/* VIRTQUEUE_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
SRC_DIR := 
 | 
			
		||||
 | 
			
		||||
SRC_FILES := $(wildcard *.c)
 | 
			
		||||
 | 
			
		||||
include $(KERNEL_ROOT)/compiler.mk
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,711 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2014, Mentor Graphics Corporation
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <metal/alloc.h>
 | 
			
		||||
#include <metal/log.h>
 | 
			
		||||
#include <openamp/elf_loader.h>
 | 
			
		||||
#include <openamp/remoteproc.h>
 | 
			
		||||
 | 
			
		||||
static int elf_is_64(const void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	const unsigned char *tmp = elf_info;
 | 
			
		||||
 | 
			
		||||
	if (tmp[EI_CLASS] == ELFCLASS64)
 | 
			
		||||
		return 1;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t elf_ehdr_size(const void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_info == NULL)
 | 
			
		||||
		return sizeof(Elf64_Ehdr);
 | 
			
		||||
	else if (elf_is_64(elf_info) != 0)
 | 
			
		||||
		return sizeof(Elf64_Ehdr);
 | 
			
		||||
	else
 | 
			
		||||
		return sizeof(Elf32_Ehdr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t elf_phoff(const void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		const Elf32_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_phoff;
 | 
			
		||||
	} else {
 | 
			
		||||
		const Elf64_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_phoff;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t elf_phentsize(const void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		const Elf32_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_phentsize;
 | 
			
		||||
	} else {
 | 
			
		||||
		const Elf64_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_phentsize;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int elf_phnum(const void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		const Elf32_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_phnum;
 | 
			
		||||
	} else {
 | 
			
		||||
		const Elf64_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_phnum;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t elf_shoff(const void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		const Elf32_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_shoff;
 | 
			
		||||
	} else {
 | 
			
		||||
		const Elf64_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_shoff;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t elf_shentsize(const void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		const Elf32_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_shentsize;
 | 
			
		||||
	} else {
 | 
			
		||||
		const Elf64_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_shentsize;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int elf_shnum(const void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		const Elf32_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_shnum;
 | 
			
		||||
	} else {
 | 
			
		||||
		const Elf64_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_shnum;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int elf_shstrndx(const void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		const Elf32_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_shstrndx;
 | 
			
		||||
	} else {
 | 
			
		||||
		const Elf64_Ehdr *ehdr = elf_info;
 | 
			
		||||
 | 
			
		||||
		return ehdr->e_shstrndx;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *elf_phtable_ptr(void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		struct elf32_info *einfo = elf_info;
 | 
			
		||||
 | 
			
		||||
		return (void *)&einfo->phdrs;
 | 
			
		||||
	} else {
 | 
			
		||||
		struct elf64_info *einfo = elf_info;
 | 
			
		||||
 | 
			
		||||
		return (void *)&einfo->phdrs;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *elf_shtable_ptr(void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		struct elf32_info *einfo = elf_info;
 | 
			
		||||
 | 
			
		||||
		return (void *)(&einfo->shdrs);
 | 
			
		||||
	} else {
 | 
			
		||||
		struct elf64_info *einfo = elf_info;
 | 
			
		||||
 | 
			
		||||
		return (void *)(&einfo->shdrs);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void **elf_shstrtab_ptr(void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		struct elf32_info *einfo = elf_info;
 | 
			
		||||
 | 
			
		||||
		return &einfo->shstrtab;
 | 
			
		||||
	} else {
 | 
			
		||||
		struct elf64_info *einfo = elf_info;
 | 
			
		||||
 | 
			
		||||
		return &einfo->shstrtab;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned int *elf_load_state(void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		struct elf32_info *einfo = elf_info;
 | 
			
		||||
 | 
			
		||||
		return &einfo->load_state;
 | 
			
		||||
	} else {
 | 
			
		||||
		struct elf64_info *einfo = elf_info;
 | 
			
		||||
 | 
			
		||||
		return &einfo->load_state;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void elf_parse_segment(void *elf_info, const void *elf_phdr,
 | 
			
		||||
			      unsigned int *p_type, size_t *p_offset,
 | 
			
		||||
			      metal_phys_addr_t *p_vaddr,
 | 
			
		||||
			      metal_phys_addr_t *p_paddr,
 | 
			
		||||
			      size_t *p_filesz, size_t *p_memsz)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		const Elf32_Phdr *phdr = elf_phdr;
 | 
			
		||||
 | 
			
		||||
		if (p_type != NULL)
 | 
			
		||||
			*p_type = (unsigned int)phdr->p_type;
 | 
			
		||||
		if (p_offset != NULL)
 | 
			
		||||
			*p_offset = (size_t)phdr->p_offset;
 | 
			
		||||
		if (p_vaddr != NULL)
 | 
			
		||||
			*p_vaddr = (metal_phys_addr_t)phdr->p_vaddr;
 | 
			
		||||
		if (p_paddr != NULL)
 | 
			
		||||
			*p_paddr = (metal_phys_addr_t)phdr->p_paddr;
 | 
			
		||||
		if (p_filesz != NULL)
 | 
			
		||||
			*p_filesz = (size_t)phdr->p_filesz;
 | 
			
		||||
		if (p_memsz != NULL)
 | 
			
		||||
			*p_memsz = (size_t)phdr->p_memsz;
 | 
			
		||||
	} else {
 | 
			
		||||
		const Elf64_Phdr *phdr = elf_phdr;
 | 
			
		||||
 | 
			
		||||
		if (p_type != NULL)
 | 
			
		||||
			*p_type = (unsigned int)phdr->p_type;
 | 
			
		||||
		if (p_offset != NULL)
 | 
			
		||||
			*p_offset = (size_t)phdr->p_offset;
 | 
			
		||||
		if (p_vaddr != NULL)
 | 
			
		||||
		if (p_vaddr != NULL)
 | 
			
		||||
			*p_vaddr = (metal_phys_addr_t)phdr->p_vaddr;
 | 
			
		||||
		if (p_paddr != NULL)
 | 
			
		||||
			*p_paddr = (metal_phys_addr_t)phdr->p_paddr;
 | 
			
		||||
		if (p_filesz != NULL)
 | 
			
		||||
			*p_filesz = (size_t)phdr->p_filesz;
 | 
			
		||||
		if (p_memsz != NULL)
 | 
			
		||||
			*p_memsz = (size_t)phdr->p_memsz;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const void *elf_get_segment_from_index(void *elf_info, int index)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		const struct elf32_info *einfo = elf_info;
 | 
			
		||||
		const Elf32_Ehdr *ehdr = &einfo->ehdr;
 | 
			
		||||
		const Elf32_Phdr *phdrs = einfo->phdrs;
 | 
			
		||||
 | 
			
		||||
		if (phdrs == NULL)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		if (index < 0 || index > ehdr->e_phnum)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		return &phdrs[index];
 | 
			
		||||
	} else {
 | 
			
		||||
		const struct elf64_info *einfo = elf_info;
 | 
			
		||||
		const Elf64_Ehdr *ehdr = &einfo->ehdr;
 | 
			
		||||
		const Elf64_Phdr *phdrs = einfo->phdrs;
 | 
			
		||||
 | 
			
		||||
		if (phdrs == NULL)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		if (index < 0 || index > ehdr->e_phnum)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		return &phdrs[index];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *elf_get_section_from_name(void *elf_info, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	const char *name_table;
 | 
			
		||||
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		struct elf32_info *einfo = elf_info;
 | 
			
		||||
		Elf32_Ehdr *ehdr = &einfo->ehdr;
 | 
			
		||||
		Elf32_Shdr *shdr = einfo->shdrs;
 | 
			
		||||
 | 
			
		||||
		name_table = einfo->shstrtab;
 | 
			
		||||
		if (shdr == NULL || name_table == NULL)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
 | 
			
		||||
			if (strcmp(name, name_table + shdr->sh_name))
 | 
			
		||||
				continue;
 | 
			
		||||
			else
 | 
			
		||||
				return shdr;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		struct elf64_info *einfo = elf_info;
 | 
			
		||||
		Elf64_Ehdr *ehdr = &einfo->ehdr;
 | 
			
		||||
		Elf64_Shdr *shdr = einfo->shdrs;
 | 
			
		||||
 | 
			
		||||
		name_table = einfo->shstrtab;
 | 
			
		||||
		if (shdr == NULL || name_table == NULL)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
 | 
			
		||||
			if (strcmp(name, name_table + shdr->sh_name))
 | 
			
		||||
				continue;
 | 
			
		||||
			else
 | 
			
		||||
				return shdr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *elf_get_section_from_index(void *elf_info, int index)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		struct elf32_info *einfo = elf_info;
 | 
			
		||||
		Elf32_Ehdr *ehdr = &einfo->ehdr;
 | 
			
		||||
		Elf32_Shdr *shdr = einfo->shdrs;
 | 
			
		||||
 | 
			
		||||
		if (shdr == NULL)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		if (index > ehdr->e_shnum)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		return &einfo->shdrs[index];
 | 
			
		||||
	} else {
 | 
			
		||||
		struct elf64_info *einfo = elf_info;
 | 
			
		||||
		Elf64_Ehdr *ehdr = &einfo->ehdr;
 | 
			
		||||
		Elf64_Shdr *shdr = einfo->shdrs;
 | 
			
		||||
 | 
			
		||||
		if (shdr == NULL)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		if (index > ehdr->e_shnum)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		return &einfo->shdrs[index];
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void elf_parse_section(void *elf_info, void *elf_shdr,
 | 
			
		||||
			      unsigned int *sh_type, unsigned int *sh_flags,
 | 
			
		||||
			      metal_phys_addr_t *sh_addr,
 | 
			
		||||
			      size_t *sh_offset, size_t *sh_size,
 | 
			
		||||
			      unsigned int *sh_link, unsigned int *sh_info,
 | 
			
		||||
			      unsigned int *sh_addralign,
 | 
			
		||||
			      size_t *sh_entsize)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		Elf32_Shdr *shdr = elf_shdr;
 | 
			
		||||
 | 
			
		||||
		if (sh_type != NULL)
 | 
			
		||||
			*sh_type = shdr->sh_type;
 | 
			
		||||
		if (sh_flags != NULL)
 | 
			
		||||
			*sh_flags = shdr->sh_flags;
 | 
			
		||||
		if (sh_addr != NULL)
 | 
			
		||||
			*sh_addr = (metal_phys_addr_t)shdr->sh_addr;
 | 
			
		||||
		if (sh_offset != NULL)
 | 
			
		||||
			*sh_offset = shdr->sh_offset;
 | 
			
		||||
		if (sh_size != NULL)
 | 
			
		||||
			*sh_size = shdr->sh_size;
 | 
			
		||||
		if (sh_link != NULL)
 | 
			
		||||
			*sh_link = shdr->sh_link;
 | 
			
		||||
		if (sh_info != NULL)
 | 
			
		||||
			*sh_info = shdr->sh_info;
 | 
			
		||||
		if (sh_addralign != NULL)
 | 
			
		||||
			*sh_addralign = shdr->sh_addralign;
 | 
			
		||||
		if (sh_entsize != NULL)
 | 
			
		||||
			*sh_entsize = shdr->sh_entsize;
 | 
			
		||||
	} else {
 | 
			
		||||
		Elf64_Shdr *shdr = elf_shdr;
 | 
			
		||||
 | 
			
		||||
		if (sh_type != NULL)
 | 
			
		||||
			*sh_type = shdr->sh_type;
 | 
			
		||||
		if (sh_flags != NULL)
 | 
			
		||||
			*sh_flags = shdr->sh_flags;
 | 
			
		||||
		if (sh_addr != NULL)
 | 
			
		||||
			*sh_addr = (metal_phys_addr_t)(shdr->sh_addr &
 | 
			
		||||
				   (metal_phys_addr_t)(-1));
 | 
			
		||||
		if (sh_offset != NULL)
 | 
			
		||||
			*sh_offset = shdr->sh_offset;
 | 
			
		||||
		if (sh_size != NULL)
 | 
			
		||||
			*sh_size = shdr->sh_size;
 | 
			
		||||
		if (sh_link != NULL)
 | 
			
		||||
			*sh_link = shdr->sh_link;
 | 
			
		||||
		if (sh_info != NULL)
 | 
			
		||||
			*sh_info = shdr->sh_info;
 | 
			
		||||
		if (sh_addralign != NULL)
 | 
			
		||||
			*sh_addralign = shdr->sh_addralign;
 | 
			
		||||
		if (sh_entsize != NULL)
 | 
			
		||||
			*sh_entsize = shdr->sh_entsize;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const void *elf_next_load_segment(void *elf_info, int *nseg,
 | 
			
		||||
				   metal_phys_addr_t *da,
 | 
			
		||||
				   size_t *noffset, size_t *nfsize,
 | 
			
		||||
				   size_t *nmsize)
 | 
			
		||||
{
 | 
			
		||||
	const void *phdr;
 | 
			
		||||
	unsigned int p_type = PT_NULL;
 | 
			
		||||
 | 
			
		||||
	if (elf_info == NULL || nseg == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	while(p_type != PT_LOAD) {
 | 
			
		||||
		phdr = elf_get_segment_from_index(elf_info, *nseg);
 | 
			
		||||
		if (phdr == NULL)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		elf_parse_segment(elf_info, phdr, &p_type, noffset,
 | 
			
		||||
				  da, NULL, nfsize, nmsize);
 | 
			
		||||
		*nseg = *nseg + 1;
 | 
			
		||||
	}
 | 
			
		||||
	return phdr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t elf_info_size(const void *img_data)
 | 
			
		||||
{
 | 
			
		||||
	if (elf_is_64(img_data) == 0)
 | 
			
		||||
		return sizeof(struct elf32_info);
 | 
			
		||||
	else
 | 
			
		||||
		return sizeof(struct elf64_info);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elf_identify(const void *img_data, size_t len)
 | 
			
		||||
{
 | 
			
		||||
	if (len < SELFMAG || img_data == NULL)
 | 
			
		||||
		return -RPROC_EINVAL;
 | 
			
		||||
	if (memcmp(img_data, ELFMAG, SELFMAG) != 0)
 | 
			
		||||
		return -RPROC_EINVAL;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elf_load_header(const void *img_data, size_t offset, size_t len,
 | 
			
		||||
		    void **img_info, int last_load_state,
 | 
			
		||||
		    size_t *noffset, size_t *nlen)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int *load_state;
 | 
			
		||||
 | 
			
		||||
	metal_assert(noffset != NULL);
 | 
			
		||||
	metal_assert(nlen != NULL);
 | 
			
		||||
	/* Get ELF header */
 | 
			
		||||
	if (last_load_state == ELF_STATE_INIT) {
 | 
			
		||||
		size_t tmpsize;
 | 
			
		||||
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG, "Loading ELF headering\r\n");
 | 
			
		||||
		tmpsize = elf_ehdr_size(img_data);
 | 
			
		||||
		if (len < tmpsize) {
 | 
			
		||||
			*noffset = 0;
 | 
			
		||||
			*nlen = tmpsize;
 | 
			
		||||
			return ELF_STATE_INIT;
 | 
			
		||||
		} else {
 | 
			
		||||
			size_t infosize = elf_info_size(img_data);
 | 
			
		||||
 | 
			
		||||
			if (*img_info == NULL) {
 | 
			
		||||
				*img_info = metal_allocate_memory(infosize);
 | 
			
		||||
				if (*img_info == NULL)
 | 
			
		||||
					return -ENOMEM;
 | 
			
		||||
				memset(*img_info, 0, infosize);
 | 
			
		||||
			}
 | 
			
		||||
			memcpy(*img_info, img_data, tmpsize);
 | 
			
		||||
			load_state = elf_load_state(*img_info);
 | 
			
		||||
			*load_state = ELF_STATE_WAIT_FOR_PHDRS;
 | 
			
		||||
			last_load_state = ELF_STATE_WAIT_FOR_PHDRS;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	metal_assert(*img_info != NULL);
 | 
			
		||||
	load_state = elf_load_state(*img_info);
 | 
			
		||||
	if (last_load_state != (int)*load_state)
 | 
			
		||||
		return -RPROC_EINVAL;
 | 
			
		||||
	/* Get ELF program headers */
 | 
			
		||||
	if (*load_state == ELF_STATE_WAIT_FOR_PHDRS) {
 | 
			
		||||
		size_t phdrs_size;
 | 
			
		||||
		size_t phdrs_offset;
 | 
			
		||||
		char **phdrs;
 | 
			
		||||
		const void *img_phdrs;
 | 
			
		||||
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG, "Loading ELF program header.\r\n");
 | 
			
		||||
		phdrs_offset = elf_phoff(*img_info);
 | 
			
		||||
		phdrs_size = elf_phnum(*img_info) * elf_phentsize(*img_info);
 | 
			
		||||
		if (offset > phdrs_offset ||
 | 
			
		||||
		    offset + len < phdrs_offset + phdrs_size) {
 | 
			
		||||
			*noffset = phdrs_offset;
 | 
			
		||||
			*nlen = phdrs_size;
 | 
			
		||||
			return (int)*load_state;
 | 
			
		||||
		}
 | 
			
		||||
		/* caculate the programs headers offset to the image_data */
 | 
			
		||||
		phdrs_offset -= offset;
 | 
			
		||||
		img_phdrs = (const void *)
 | 
			
		||||
			    ((const char *)img_data + phdrs_offset);
 | 
			
		||||
		phdrs = (char **)elf_phtable_ptr(*img_info);
 | 
			
		||||
		(*phdrs) = metal_allocate_memory(phdrs_size);
 | 
			
		||||
		if (*phdrs == NULL)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
		memcpy((void *)(*phdrs), img_phdrs, phdrs_size);
 | 
			
		||||
		*load_state = ELF_STATE_WAIT_FOR_SHDRS |
 | 
			
		||||
			       RPROC_LOADER_READY_TO_LOAD;
 | 
			
		||||
	}
 | 
			
		||||
	/* Get ELF Section Headers */
 | 
			
		||||
	if ((*load_state & ELF_STATE_WAIT_FOR_SHDRS) != 0) {
 | 
			
		||||
		size_t shdrs_size;
 | 
			
		||||
		size_t shdrs_offset;
 | 
			
		||||
		char **shdrs;
 | 
			
		||||
		const void *img_shdrs;
 | 
			
		||||
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG, "Loading ELF section header.\r\n");
 | 
			
		||||
		shdrs_offset = elf_shoff(*img_info);
 | 
			
		||||
		if (elf_shnum(*img_info) == 0) {
 | 
			
		||||
			*load_state = (*load_state & (~ELF_STATE_MASK)) |
 | 
			
		||||
				       ELF_STATE_HDRS_COMPLETE;
 | 
			
		||||
		       *nlen = 0;
 | 
			
		||||
			return (int)*load_state;
 | 
			
		||||
		}
 | 
			
		||||
		shdrs_size = elf_shnum(*img_info) * elf_shentsize(*img_info);
 | 
			
		||||
		if (offset > shdrs_offset ||
 | 
			
		||||
		    offset + len < shdrs_offset + shdrs_size) {
 | 
			
		||||
			*noffset = shdrs_offset;
 | 
			
		||||
			*nlen = shdrs_size;
 | 
			
		||||
			return (int)*load_state;
 | 
			
		||||
		}
 | 
			
		||||
		/* caculate the sections headers offset to the image_data */
 | 
			
		||||
		shdrs_offset -= offset;
 | 
			
		||||
		img_shdrs = (const void *)
 | 
			
		||||
			    ((const char *)img_data + shdrs_offset);
 | 
			
		||||
		shdrs = (char **)elf_shtable_ptr(*img_info);
 | 
			
		||||
		(*shdrs) = metal_allocate_memory(shdrs_size);
 | 
			
		||||
		if (*shdrs == NULL)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
		memcpy((void *)*shdrs, img_shdrs, shdrs_size);
 | 
			
		||||
		*load_state = (*load_state & (~ELF_STATE_MASK)) |
 | 
			
		||||
			       ELF_STATE_WAIT_FOR_SHSTRTAB;
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG,
 | 
			
		||||
			  "Loading ELF section header complete.\r\n");
 | 
			
		||||
	}
 | 
			
		||||
	/* Get ELF SHSTRTAB section */
 | 
			
		||||
	if ((*load_state & ELF_STATE_WAIT_FOR_SHSTRTAB) != 0) {
 | 
			
		||||
		size_t shstrtab_size;
 | 
			
		||||
		size_t shstrtab_offset;
 | 
			
		||||
		int shstrndx;
 | 
			
		||||
		void *shdr;
 | 
			
		||||
		void **shstrtab;
 | 
			
		||||
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG, "Loading ELF shstrtab.\r\n");
 | 
			
		||||
		shstrndx = elf_shstrndx(*img_info);
 | 
			
		||||
		shdr = elf_get_section_from_index(*img_info, shstrndx);
 | 
			
		||||
		if (shdr == NULL)
 | 
			
		||||
			return -RPROC_EINVAL;
 | 
			
		||||
		elf_parse_section(*img_info, shdr, NULL, NULL,
 | 
			
		||||
				  NULL, &shstrtab_offset,
 | 
			
		||||
				  &shstrtab_size, NULL, NULL,
 | 
			
		||||
				  NULL, NULL);
 | 
			
		||||
		if (offset > shstrtab_offset ||
 | 
			
		||||
		    offset + len < shstrtab_offset + shstrtab_size) {
 | 
			
		||||
			*noffset = shstrtab_offset;
 | 
			
		||||
			*nlen = shstrtab_size;
 | 
			
		||||
			return (int)*load_state;
 | 
			
		||||
		}
 | 
			
		||||
		/* Caculate shstrtab section offset to the input image data */
 | 
			
		||||
		shstrtab_offset -= offset;
 | 
			
		||||
		shstrtab = elf_shstrtab_ptr(*img_info);
 | 
			
		||||
		*shstrtab = metal_allocate_memory(shstrtab_size);
 | 
			
		||||
		if (*shstrtab == NULL)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
		memcpy(*shstrtab,
 | 
			
		||||
		       (const void *)((const char *)img_data + shstrtab_offset),
 | 
			
		||||
		       shstrtab_size);
 | 
			
		||||
		*load_state = (*load_state & (~ELF_STATE_MASK)) |
 | 
			
		||||
			       ELF_STATE_HDRS_COMPLETE;
 | 
			
		||||
		*nlen = 0;
 | 
			
		||||
		return *load_state;
 | 
			
		||||
	}
 | 
			
		||||
	return last_load_state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elf_load(struct remoteproc *rproc,
 | 
			
		||||
	     const void *img_data, size_t offset, size_t len,
 | 
			
		||||
	     void **img_info, int last_load_state,
 | 
			
		||||
	     metal_phys_addr_t *da,
 | 
			
		||||
	     size_t *noffset, size_t *nlen,
 | 
			
		||||
	     unsigned char *padding, size_t *nmemsize)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int *load_state;
 | 
			
		||||
	const void *phdr;
 | 
			
		||||
 | 
			
		||||
	(void)rproc;
 | 
			
		||||
	metal_assert(da != NULL);
 | 
			
		||||
	metal_assert(noffset != NULL);
 | 
			
		||||
	metal_assert(nlen != NULL);
 | 
			
		||||
	if ((last_load_state & RPROC_LOADER_MASK) == RPROC_LOADER_NOT_READY) {
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG,
 | 
			
		||||
			  "%s, needs to load header first\r\n");
 | 
			
		||||
		last_load_state = elf_load_header(img_data, offset, len,
 | 
			
		||||
						  img_info, last_load_state,
 | 
			
		||||
						  noffset, nlen);
 | 
			
		||||
		if ((last_load_state & RPROC_LOADER_MASK) ==
 | 
			
		||||
		    RPROC_LOADER_NOT_READY) {
 | 
			
		||||
			*da = RPROC_LOAD_ANYADDR;
 | 
			
		||||
			return last_load_state;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	metal_assert(img_info != NULL && *img_info != NULL);
 | 
			
		||||
	load_state = elf_load_state(*img_info);
 | 
			
		||||
	/* For ELF, segment padding value is 0 */
 | 
			
		||||
	if (padding != NULL)
 | 
			
		||||
		*padding = 0;
 | 
			
		||||
	if ((*load_state & RPROC_LOADER_READY_TO_LOAD) != 0) {
 | 
			
		||||
		int nsegment;
 | 
			
		||||
		size_t nsegmsize = 0;
 | 
			
		||||
		size_t nsize = 0;
 | 
			
		||||
		int phnums = 0;
 | 
			
		||||
 | 
			
		||||
		nsegment = (int)(*load_state & ELF_NEXT_SEGMENT_MASK);
 | 
			
		||||
		phdr = elf_next_load_segment(*img_info, &nsegment, da,
 | 
			
		||||
					     noffset, &nsize, &nsegmsize);
 | 
			
		||||
		if (phdr == NULL) {
 | 
			
		||||
			metal_log(METAL_LOG_DEBUG, "cannot find more segement\r\n");
 | 
			
		||||
			*load_state = (*load_state & (~ELF_NEXT_SEGMENT_MASK)) |
 | 
			
		||||
				      (unsigned int)(nsegment & ELF_NEXT_SEGMENT_MASK);
 | 
			
		||||
			return *load_state;
 | 
			
		||||
		}
 | 
			
		||||
		*nlen = nsize;
 | 
			
		||||
		*nmemsize = nsegmsize;
 | 
			
		||||
		phnums = elf_phnum(*img_info);
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG, "segment: %d, total segs %d\r\n",
 | 
			
		||||
			  nsegment, phnums);
 | 
			
		||||
		if (nsegment == elf_phnum(*img_info)) {
 | 
			
		||||
			*load_state = (*load_state & (~RPROC_LOADER_MASK)) |
 | 
			
		||||
				      RPROC_LOADER_POST_DATA_LOAD;
 | 
			
		||||
		}
 | 
			
		||||
		*load_state = (*load_state & (~ELF_NEXT_SEGMENT_MASK)) |
 | 
			
		||||
			      (unsigned int)(nsegment & ELF_NEXT_SEGMENT_MASK);
 | 
			
		||||
	} else if ((*load_state & RPROC_LOADER_POST_DATA_LOAD) != 0) {
 | 
			
		||||
		if ((*load_state & ELF_STATE_HDRS_COMPLETE) == 0) {
 | 
			
		||||
			last_load_state = elf_load_header(img_data, offset,
 | 
			
		||||
							  len, img_info,
 | 
			
		||||
							  last_load_state,
 | 
			
		||||
							  noffset, nlen);
 | 
			
		||||
			if (last_load_state < 0)
 | 
			
		||||
				return last_load_state;
 | 
			
		||||
			if ((last_load_state & ELF_STATE_HDRS_COMPLETE) != 0) {
 | 
			
		||||
				*load_state = (*load_state &
 | 
			
		||||
						(~RPROC_LOADER_MASK)) |
 | 
			
		||||
						RPROC_LOADER_LOAD_COMPLETE;
 | 
			
		||||
				*nlen = 0;
 | 
			
		||||
			}
 | 
			
		||||
			*da = RPROC_LOAD_ANYADDR;
 | 
			
		||||
		} else {
 | 
			
		||||
		/* TODO: will handle relocate later */
 | 
			
		||||
			*nlen = 0;
 | 
			
		||||
			*load_state = (*load_state &
 | 
			
		||||
					(~RPROC_LOADER_MASK)) |
 | 
			
		||||
					RPROC_LOADER_LOAD_COMPLETE;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return *load_state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void elf_release(void *img_info)
 | 
			
		||||
{
 | 
			
		||||
	if (img_info == NULL)
 | 
			
		||||
		return;
 | 
			
		||||
	if (elf_is_64(img_info) == 0) {
 | 
			
		||||
		struct elf32_info *elf_info = img_info;
 | 
			
		||||
 | 
			
		||||
		if (elf_info->phdrs != NULL)
 | 
			
		||||
			metal_free_memory(elf_info->phdrs);
 | 
			
		||||
		if (elf_info->shdrs != NULL)
 | 
			
		||||
			metal_free_memory(elf_info->shdrs);
 | 
			
		||||
		if (elf_info->shstrtab != NULL)
 | 
			
		||||
			metal_free_memory(elf_info->shstrtab);
 | 
			
		||||
		metal_free_memory(img_info);
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		struct elf64_info *elf_info = img_info;
 | 
			
		||||
 | 
			
		||||
		if (elf_info->phdrs != NULL)
 | 
			
		||||
			metal_free_memory(elf_info->phdrs);
 | 
			
		||||
		if (elf_info->shdrs != NULL)
 | 
			
		||||
			metal_free_memory(elf_info->shdrs);
 | 
			
		||||
		if (elf_info->shstrtab != NULL)
 | 
			
		||||
			metal_free_memory(elf_info->shstrtab);
 | 
			
		||||
		metal_free_memory(img_info);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
metal_phys_addr_t elf_get_entry(void *elf_info)
 | 
			
		||||
{
 | 
			
		||||
	if (!elf_info)
 | 
			
		||||
		return METAL_BAD_PHYS;
 | 
			
		||||
 | 
			
		||||
	if (elf_is_64(elf_info) == 0) {
 | 
			
		||||
		Elf32_Ehdr *elf_ehdr = (Elf32_Ehdr *)elf_info;
 | 
			
		||||
		Elf32_Addr e_entry;
 | 
			
		||||
 | 
			
		||||
		e_entry = elf_ehdr->e_entry;
 | 
			
		||||
		return (metal_phys_addr_t)e_entry;
 | 
			
		||||
	} else {
 | 
			
		||||
		Elf64_Ehdr *elf_ehdr = (Elf64_Ehdr *)elf_info;
 | 
			
		||||
		Elf64_Addr e_entry;
 | 
			
		||||
 | 
			
		||||
		e_entry = elf_ehdr->e_entry;
 | 
			
		||||
		return (metal_phys_addr_t)(e_entry & (metal_phys_addr_t)(-1));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elf_locate_rsc_table(void *elf_info, metal_phys_addr_t *da,
 | 
			
		||||
			 size_t *offset, size_t *size)
 | 
			
		||||
{
 | 
			
		||||
	char *sect_name = ".resource_table";
 | 
			
		||||
	void *shdr;
 | 
			
		||||
	unsigned int *load_state;
 | 
			
		||||
 | 
			
		||||
	if (elf_info == NULL)
 | 
			
		||||
		return -RPROC_EINVAL;
 | 
			
		||||
 | 
			
		||||
	load_state = elf_load_state(elf_info);
 | 
			
		||||
	if ((*load_state & ELF_STATE_HDRS_COMPLETE) == 0)
 | 
			
		||||
		return -RPROC_ERR_LOADER_STATE;
 | 
			
		||||
	shdr = elf_get_section_from_name(elf_info, sect_name);
 | 
			
		||||
	if (shdr == NULL) {
 | 
			
		||||
		metal_assert(size != NULL);
 | 
			
		||||
		*size = 0;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	elf_parse_section(elf_info, shdr, NULL, NULL,
 | 
			
		||||
			  da, offset, size,
 | 
			
		||||
			  NULL, NULL, NULL, NULL);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elf_get_load_state(void *img_info)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int *load_state;
 | 
			
		||||
 | 
			
		||||
	if (img_info == NULL)
 | 
			
		||||
		return -RPROC_EINVAL;
 | 
			
		||||
	load_state = elf_load_state(img_info);
 | 
			
		||||
	return (int)(*load_state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct loader_ops elf_ops = {
 | 
			
		||||
	.load_header = elf_load_header,
 | 
			
		||||
	.load_data = elf_load,
 | 
			
		||||
	.locate_rsc_table = elf_locate_rsc_table,
 | 
			
		||||
	.release = elf_release,
 | 
			
		||||
	.get_entry = elf_get_entry,
 | 
			
		||||
	.get_load_state = elf_get_load_state,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,965 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2014, Mentor Graphics Corporation
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 * Copyright (c) 2015 Xilinx, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <metal/alloc.h>
 | 
			
		||||
#include <metal/log.h>
 | 
			
		||||
#include <metal/utilities.h>
 | 
			
		||||
#include <openamp/elf_loader.h>
 | 
			
		||||
#include <openamp/remoteproc.h>
 | 
			
		||||
#include <openamp/remoteproc_loader.h>
 | 
			
		||||
#include <openamp/remoteproc_virtio.h>
 | 
			
		||||
#include <openamp/rsc_table_parser.h>
 | 
			
		||||
 | 
			
		||||
/******************************************************************************
 | 
			
		||||
 *  static functions
 | 
			
		||||
 *****************************************************************************/
 | 
			
		||||
static struct loader_ops *
 | 
			
		||||
remoteproc_check_fw_format(const void *img_data, size_t img_len)
 | 
			
		||||
{
 | 
			
		||||
	if (img_len <= 0)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	else if (elf_identify(img_data, img_len) == 0)
 | 
			
		||||
		return &elf_ops;
 | 
			
		||||
	else
 | 
			
		||||
		return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct remoteproc_mem *
 | 
			
		||||
remoteproc_get_mem(struct remoteproc *rproc, const char *name,
 | 
			
		||||
		   metal_phys_addr_t pa, metal_phys_addr_t da,
 | 
			
		||||
		   void *va, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_list *node;
 | 
			
		||||
	struct remoteproc_mem *mem;
 | 
			
		||||
 | 
			
		||||
	metal_list_for_each(&rproc->mems, node) {
 | 
			
		||||
		mem = metal_container_of(node, struct remoteproc_mem, node);
 | 
			
		||||
		if (name) {
 | 
			
		||||
			if (!strncmp(name, mem->name, sizeof(mem->name)))
 | 
			
		||||
				return mem;
 | 
			
		||||
		} else if (pa != METAL_BAD_PHYS) {
 | 
			
		||||
			metal_phys_addr_t pa_start, pa_end;
 | 
			
		||||
 | 
			
		||||
			pa_start = mem->pa;
 | 
			
		||||
			pa_end = pa_start + mem->size;
 | 
			
		||||
			if (pa >= pa_start && (pa + size) <= pa_end)
 | 
			
		||||
				return mem;
 | 
			
		||||
		} else if (da != METAL_BAD_PHYS) {
 | 
			
		||||
			metal_phys_addr_t da_start, da_end;
 | 
			
		||||
 | 
			
		||||
			da_start = mem->da;
 | 
			
		||||
			da_end = da_start + mem->size;
 | 
			
		||||
			if (da >= da_start && (da + size) <= da_end)
 | 
			
		||||
				return mem;
 | 
			
		||||
		} else if (va) {
 | 
			
		||||
			if (metal_io_virt_to_offset(mem->io, va) !=
 | 
			
		||||
			    METAL_BAD_OFFSET)
 | 
			
		||||
				return mem;
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
			return NULL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static metal_phys_addr_t
 | 
			
		||||
remoteproc_datopa(struct remoteproc_mem *mem, metal_phys_addr_t da)
 | 
			
		||||
{
 | 
			
		||||
	metal_phys_addr_t pa;
 | 
			
		||||
 | 
			
		||||
	pa = mem->pa + da - mem->da;
 | 
			
		||||
	return pa;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static metal_phys_addr_t
 | 
			
		||||
remoteproc_patoda(struct remoteproc_mem *mem, metal_phys_addr_t pa)
 | 
			
		||||
{
 | 
			
		||||
	metal_phys_addr_t da;
 | 
			
		||||
 | 
			
		||||
	da = mem->da + pa - mem->pa;
 | 
			
		||||
	return da;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *remoteproc_get_rsc_table(struct remoteproc *rproc,
 | 
			
		||||
				      void *store,
 | 
			
		||||
				      struct image_store_ops *store_ops,
 | 
			
		||||
				      size_t offset,
 | 
			
		||||
				      size_t len)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	void *rsc_table = NULL;
 | 
			
		||||
	const void *img_data;
 | 
			
		||||
 | 
			
		||||
	/* Copy the resource table to local memory,
 | 
			
		||||
	 * the caller should be responsible to release the memory
 | 
			
		||||
	 */
 | 
			
		||||
	rsc_table = metal_allocate_memory(len);
 | 
			
		||||
	if (!rsc_table) {
 | 
			
		||||
		return RPROC_ERR_PTR(-RPROC_ENOMEM);
 | 
			
		||||
	}
 | 
			
		||||
	ret = store_ops->load(store, offset, len, &img_data, RPROC_LOAD_ANYADDR,
 | 
			
		||||
			      NULL, 1);
 | 
			
		||||
	if (ret < 0 || ret < (int)len || img_data == NULL) {
 | 
			
		||||
		metal_log(METAL_LOG_ERROR,
 | 
			
		||||
			  "get rsc failed: 0x%llx, 0x%llx\r\n", offset, len);
 | 
			
		||||
		rsc_table = RPROC_ERR_PTR(-RPROC_EINVAL);
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(rsc_table, img_data, len);
 | 
			
		||||
 | 
			
		||||
	ret = handle_rsc_table(rproc, rsc_table, len, NULL);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		rsc_table = RPROC_ERR_PTR(ret);
 | 
			
		||||
		goto error;
 | 
			
		||||
	}
 | 
			
		||||
	return rsc_table;
 | 
			
		||||
 | 
			
		||||
error:
 | 
			
		||||
	metal_free_memory(rsc_table);
 | 
			
		||||
	return rsc_table;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int remoteproc_parse_rsc_table(struct remoteproc *rproc,
 | 
			
		||||
			       struct resource_table *rsc_table,
 | 
			
		||||
			       size_t rsc_size)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_io_region *io;
 | 
			
		||||
 | 
			
		||||
	io = remoteproc_get_io_with_va(rproc, (void *)rsc_table);
 | 
			
		||||
	return handle_rsc_table(rproc, rsc_table, rsc_size, io);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int remoteproc_set_rsc_table(struct remoteproc *rproc,
 | 
			
		||||
			     struct resource_table *rsc_table,
 | 
			
		||||
			     size_t rsc_size)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct metal_io_region *io;
 | 
			
		||||
 | 
			
		||||
	io = remoteproc_get_io_with_va(rproc, (void *)rsc_table);
 | 
			
		||||
	if (!io)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	ret = remoteproc_parse_rsc_table(rproc, rsc_table, rsc_size);
 | 
			
		||||
	if (!ret) {
 | 
			
		||||
		rproc->rsc_table = rsc_table;
 | 
			
		||||
		rproc->rsc_len = rsc_size;
 | 
			
		||||
		rproc->rsc_io = io;
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct remoteproc *remoteproc_init(struct remoteproc *rproc,
 | 
			
		||||
				   struct remoteproc_ops *ops, void *priv)
 | 
			
		||||
{
 | 
			
		||||
	if (rproc) {
 | 
			
		||||
		memset(rproc, 0, sizeof (*rproc));
 | 
			
		||||
		rproc->state = RPROC_OFFLINE;
 | 
			
		||||
		metal_mutex_init(&rproc->lock);
 | 
			
		||||
		metal_list_init(&rproc->mems);
 | 
			
		||||
		metal_list_init(&rproc->vdevs);
 | 
			
		||||
	}
 | 
			
		||||
	rproc = ops->init(rproc, ops, priv);
 | 
			
		||||
	return rproc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int remoteproc_remove(struct remoteproc *rproc)
 | 
			
		||||
{
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	if (rproc) {
 | 
			
		||||
		metal_mutex_acquire(&rproc->lock);
 | 
			
		||||
		if (rproc->state == RPROC_OFFLINE)
 | 
			
		||||
			rproc->ops->remove(rproc);
 | 
			
		||||
		else
 | 
			
		||||
			ret = -EBUSY;
 | 
			
		||||
		metal_mutex_release(&rproc->lock);
 | 
			
		||||
	} else {
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int remoteproc_config(struct remoteproc *rproc, void *data)
 | 
			
		||||
{
 | 
			
		||||
	int ret = -RPROC_ENODEV;
 | 
			
		||||
 | 
			
		||||
	if (rproc) {
 | 
			
		||||
		metal_mutex_acquire(&rproc->lock);
 | 
			
		||||
		if (rproc->state == RPROC_OFFLINE) {
 | 
			
		||||
			/* configure operation is allowed if the state is
 | 
			
		||||
			 * offline or ready. This function can be called
 | 
			
		||||
			 * mulitple times before start the remote.
 | 
			
		||||
			 */
 | 
			
		||||
			if (rproc->ops->config)
 | 
			
		||||
				ret = rproc->ops->config(rproc, data);
 | 
			
		||||
			rproc->state = RPROC_READY;
 | 
			
		||||
		} else {
 | 
			
		||||
			ret = -RPROC_EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		metal_mutex_release(&rproc->lock);
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int remoteproc_start(struct remoteproc *rproc)
 | 
			
		||||
{
 | 
			
		||||
	int ret = -RPROC_ENODEV;
 | 
			
		||||
 | 
			
		||||
	if (rproc) {
 | 
			
		||||
		metal_mutex_acquire(&rproc->lock);
 | 
			
		||||
		if (rproc->state == RPROC_READY) {
 | 
			
		||||
			ret = rproc->ops->start(rproc);
 | 
			
		||||
			rproc->state = RPROC_RUNNING;
 | 
			
		||||
		} else {
 | 
			
		||||
			ret = -RPROC_EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		metal_mutex_release(&rproc->lock);
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int remoteproc_stop(struct remoteproc *rproc)
 | 
			
		||||
{
 | 
			
		||||
	int ret = -RPROC_ENODEV;
 | 
			
		||||
 | 
			
		||||
	if (rproc) {
 | 
			
		||||
		metal_mutex_acquire(&rproc->lock);
 | 
			
		||||
		if (rproc->state != RPROC_STOPPED &&
 | 
			
		||||
		    rproc->state != RPROC_OFFLINE) {
 | 
			
		||||
			if (rproc->ops->stop)
 | 
			
		||||
				ret = rproc->ops->stop(rproc);
 | 
			
		||||
			rproc->state = RPROC_STOPPED;
 | 
			
		||||
		} else {
 | 
			
		||||
			ret = 0;
 | 
			
		||||
		}
 | 
			
		||||
		metal_mutex_release(&rproc->lock);
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int remoteproc_shutdown(struct remoteproc *rproc)
 | 
			
		||||
{
 | 
			
		||||
	int ret = -RPROC_ENODEV;
 | 
			
		||||
 | 
			
		||||
	if (rproc) {
 | 
			
		||||
		ret = 0;
 | 
			
		||||
		metal_mutex_acquire(&rproc->lock);
 | 
			
		||||
		if (rproc->state != RPROC_OFFLINE) {
 | 
			
		||||
			if (rproc->state != RPROC_STOPPED) {
 | 
			
		||||
				if (rproc->ops->stop)
 | 
			
		||||
					ret = rproc->ops->stop(rproc);
 | 
			
		||||
			}
 | 
			
		||||
			if (!ret) {
 | 
			
		||||
				if (rproc->ops->shutdown)
 | 
			
		||||
					ret = rproc->ops->shutdown(rproc);
 | 
			
		||||
				if (!ret) {
 | 
			
		||||
					rproc->state = RPROC_OFFLINE;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		metal_mutex_release(&rproc->lock);
 | 
			
		||||
	}
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct metal_io_region *
 | 
			
		||||
remoteproc_get_io_with_name(struct remoteproc *rproc,
 | 
			
		||||
			    const char *name)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc_mem *mem;
 | 
			
		||||
 | 
			
		||||
	mem = remoteproc_get_mem(rproc, name,
 | 
			
		||||
				 METAL_BAD_PHYS, METAL_BAD_PHYS, NULL, 0);
 | 
			
		||||
	if (mem)
 | 
			
		||||
		return mem->io;
 | 
			
		||||
	else
 | 
			
		||||
		return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct metal_io_region *
 | 
			
		||||
remoteproc_get_io_with_pa(struct remoteproc *rproc,
 | 
			
		||||
			  metal_phys_addr_t pa)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc_mem *mem;
 | 
			
		||||
 | 
			
		||||
	mem = remoteproc_get_mem(rproc, NULL, pa, METAL_BAD_PHYS, NULL, 0);
 | 
			
		||||
	if (mem)
 | 
			
		||||
		return mem->io;
 | 
			
		||||
	else
 | 
			
		||||
		return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct metal_io_region *
 | 
			
		||||
remoteproc_get_io_with_da(struct remoteproc *rproc,
 | 
			
		||||
			  metal_phys_addr_t da,
 | 
			
		||||
			  unsigned long *offset)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc_mem *mem;
 | 
			
		||||
 | 
			
		||||
	mem = remoteproc_get_mem(rproc, NULL, METAL_BAD_PHYS, da, NULL, 0);
 | 
			
		||||
	if (mem) {
 | 
			
		||||
		struct metal_io_region *io;
 | 
			
		||||
		metal_phys_addr_t pa;
 | 
			
		||||
 | 
			
		||||
		io = mem->io;
 | 
			
		||||
		pa = remoteproc_datopa(mem, da);
 | 
			
		||||
		*offset = metal_io_phys_to_offset(io, pa);
 | 
			
		||||
		return io;
 | 
			
		||||
	} else {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct metal_io_region *
 | 
			
		||||
remoteproc_get_io_with_va(struct remoteproc *rproc, void *va)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc_mem *mem;
 | 
			
		||||
 | 
			
		||||
	mem = remoteproc_get_mem(rproc, NULL, METAL_BAD_PHYS, METAL_BAD_PHYS,
 | 
			
		||||
				 va, 0);
 | 
			
		||||
	if (mem)
 | 
			
		||||
		return mem->io;
 | 
			
		||||
	else
 | 
			
		||||
		return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *remoteproc_mmap(struct remoteproc *rproc,
 | 
			
		||||
		      metal_phys_addr_t *pa, metal_phys_addr_t *da,
 | 
			
		||||
		      size_t size, unsigned int attribute,
 | 
			
		||||
		      struct metal_io_region **io)
 | 
			
		||||
{
 | 
			
		||||
	void *va = NULL;
 | 
			
		||||
	metal_phys_addr_t lpa, lda;
 | 
			
		||||
	struct remoteproc_mem *mem;
 | 
			
		||||
 | 
			
		||||
	if (!rproc)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	else if (!pa && !da)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	if (pa)
 | 
			
		||||
		lpa = *pa;
 | 
			
		||||
	else
 | 
			
		||||
		lpa = METAL_BAD_PHYS;
 | 
			
		||||
	if (da)
 | 
			
		||||
		lda =  *da;
 | 
			
		||||
	else
 | 
			
		||||
		lda = METAL_BAD_PHYS;
 | 
			
		||||
	mem = remoteproc_get_mem(rproc, NULL, lpa, lda, NULL, size);
 | 
			
		||||
	if (mem) {
 | 
			
		||||
		if (lpa != METAL_BAD_PHYS)
 | 
			
		||||
			lda = remoteproc_patoda(mem, lpa);
 | 
			
		||||
		else if (lda != METAL_BAD_PHYS)
 | 
			
		||||
			lpa = remoteproc_datopa(mem, lda);
 | 
			
		||||
		if (io)
 | 
			
		||||
			*io = mem->io;
 | 
			
		||||
		va = metal_io_phys_to_virt(mem->io, lpa);
 | 
			
		||||
	} else if (rproc->ops->mmap) {
 | 
			
		||||
		va = rproc->ops->mmap(rproc, &lpa, &lda, size, attribute, io);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (pa)
 | 
			
		||||
		*pa  = lpa;
 | 
			
		||||
	if (da)
 | 
			
		||||
		*da = lda;
 | 
			
		||||
	return va;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int remoteproc_load(struct remoteproc *rproc, const char *path,
 | 
			
		||||
		    void *store, struct image_store_ops *store_ops,
 | 
			
		||||
		    void **img_info)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct loader_ops *loader;
 | 
			
		||||
	const void *img_data;
 | 
			
		||||
	void *limg_info = NULL;
 | 
			
		||||
	size_t offset, noffset;
 | 
			
		||||
	size_t len, nlen;
 | 
			
		||||
	int last_load_state;
 | 
			
		||||
	metal_phys_addr_t da, rsc_da;
 | 
			
		||||
	int rsc_len;
 | 
			
		||||
	size_t rsc_size;
 | 
			
		||||
	void *rsc_table = NULL;
 | 
			
		||||
	struct metal_io_region *io = NULL;
 | 
			
		||||
 | 
			
		||||
	if (!rproc)
 | 
			
		||||
		return -RPROC_ENODEV;
 | 
			
		||||
 | 
			
		||||
	metal_mutex_acquire(&rproc->lock);
 | 
			
		||||
	metal_log(METAL_LOG_DEBUG, "%s: check remoteproc status\r\n", __func__);
 | 
			
		||||
	/* If remoteproc is not in ready state, cannot load executable */
 | 
			
		||||
	if (rproc->state != RPROC_READY && rproc->state != RPROC_CONFIGURED) {
 | 
			
		||||
		metal_log(METAL_LOG_ERROR,
 | 
			
		||||
			  "load failure: invalid rproc state %d.\r\n",
 | 
			
		||||
			  rproc->state);
 | 
			
		||||
		metal_mutex_release(&rproc->lock);
 | 
			
		||||
		return -RPROC_EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!store_ops) {
 | 
			
		||||
		metal_log(METAL_LOG_ERROR,
 | 
			
		||||
			  "load failure: loader ops is not set.\r\n");
 | 
			
		||||
		metal_mutex_release(&rproc->lock);
 | 
			
		||||
		return -RPROC_EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Open exectuable to get ready to parse */
 | 
			
		||||
	metal_log(METAL_LOG_DEBUG, "%s: open exectuable image\r\n", __func__);
 | 
			
		||||
	ret = store_ops->open(store, path, &img_data);
 | 
			
		||||
	if (ret <= 0) {
 | 
			
		||||
		metal_log(METAL_LOG_ERROR,
 | 
			
		||||
			  "load failure: failed to open firmware %d.\n",
 | 
			
		||||
			  ret);
 | 
			
		||||
		metal_mutex_release(&rproc->lock);
 | 
			
		||||
		return -RPROC_EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
	len = ret;
 | 
			
		||||
	metal_assert(img_data != NULL);
 | 
			
		||||
 | 
			
		||||
	/* Check executable format to select a parser */
 | 
			
		||||
	loader = rproc->loader;
 | 
			
		||||
	if (!loader) {
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG, "%s: check loader\r\n", __func__);
 | 
			
		||||
		loader = remoteproc_check_fw_format(img_data, len);
 | 
			
		||||
		if (!loader) {
 | 
			
		||||
			metal_log(METAL_LOG_ERROR,
 | 
			
		||||
			       "load failure: failed to get store ops.\n");
 | 
			
		||||
			ret = -RPROC_EINVAL;
 | 
			
		||||
			goto error1;
 | 
			
		||||
		}
 | 
			
		||||
		rproc->loader = loader;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Load exectuable headers */
 | 
			
		||||
	metal_log(METAL_LOG_DEBUG, "%s: loading headers\r\n", __func__);
 | 
			
		||||
	offset = 0;
 | 
			
		||||
	last_load_state = RPROC_LOADER_NOT_READY;
 | 
			
		||||
	while(1) {
 | 
			
		||||
		ret = loader->load_header(img_data, offset, len,
 | 
			
		||||
					  &limg_info, last_load_state,
 | 
			
		||||
					  &noffset, &nlen);
 | 
			
		||||
		last_load_state = (unsigned int)ret;
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG,
 | 
			
		||||
			  "%s, load header 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n",
 | 
			
		||||
			  __func__, offset, len, noffset, nlen);
 | 
			
		||||
		if (ret < 0) {
 | 
			
		||||
			metal_log(METAL_LOG_ERROR,
 | 
			
		||||
				  "load header failed 0x%lx,%d.\r\n",
 | 
			
		||||
				  offset, len);
 | 
			
		||||
 | 
			
		||||
			goto error2;
 | 
			
		||||
		} else if ((ret & RPROC_LOADER_READY_TO_LOAD) != 0) {
 | 
			
		||||
			if (nlen == 0)
 | 
			
		||||
				break;
 | 
			
		||||
			else if ((noffset > (offset + len)) &&
 | 
			
		||||
				 (store_ops->features & SUPPORT_SEEK) == 0) {
 | 
			
		||||
				/* Required data is not continued, however
 | 
			
		||||
				 * seek is not supported, stop to load
 | 
			
		||||
				 * headers such as ELF section headers which
 | 
			
		||||
				 * is usually located to the end of image.
 | 
			
		||||
				 * Continue to load binary data to target
 | 
			
		||||
				 * memory.
 | 
			
		||||
				 */
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		/* Continue to load headers image data */
 | 
			
		||||
		img_data = NULL;
 | 
			
		||||
		ret = store_ops->load(store, noffset, nlen,
 | 
			
		||||
				      &img_data,
 | 
			
		||||
				      RPROC_LOAD_ANYADDR,
 | 
			
		||||
				      NULL, 1);
 | 
			
		||||
		if (ret < (int)nlen) {
 | 
			
		||||
			metal_log(METAL_LOG_ERROR,
 | 
			
		||||
				  "load image data failed 0x%x,%d\r\n",
 | 
			
		||||
				  noffset, nlen);
 | 
			
		||||
			goto error2;
 | 
			
		||||
		}
 | 
			
		||||
		offset = noffset;
 | 
			
		||||
		len = nlen;
 | 
			
		||||
	}
 | 
			
		||||
	ret = elf_locate_rsc_table(limg_info, &rsc_da, &offset, &rsc_size);
 | 
			
		||||
	if (ret == 0 && rsc_size > 0) {
 | 
			
		||||
		/* parse resource table */
 | 
			
		||||
		rsc_len = (int)rsc_size;
 | 
			
		||||
		rsc_table = remoteproc_get_rsc_table(rproc, store, store_ops,
 | 
			
		||||
						     offset, rsc_len);
 | 
			
		||||
	} else {
 | 
			
		||||
		rsc_len = ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* load executable data */
 | 
			
		||||
	metal_log(METAL_LOG_DEBUG, "%s: load executable data\r\n", __func__);
 | 
			
		||||
	offset = 0;
 | 
			
		||||
	len = 0;
 | 
			
		||||
	ret = -EINVAL;
 | 
			
		||||
	while(1) {
 | 
			
		||||
		unsigned char padding;
 | 
			
		||||
		size_t nmemsize;
 | 
			
		||||
		metal_phys_addr_t pa;
 | 
			
		||||
 | 
			
		||||
		da = RPROC_LOAD_ANYADDR;
 | 
			
		||||
		nlen = 0;
 | 
			
		||||
		nmemsize = 0;
 | 
			
		||||
		noffset = 0;
 | 
			
		||||
		ret = loader->load_data(rproc, img_data, offset, len,
 | 
			
		||||
					&limg_info, last_load_state, &da,
 | 
			
		||||
					&noffset, &nlen, &padding, &nmemsize);
 | 
			
		||||
		if (ret < 0) {
 | 
			
		||||
			metal_log(METAL_LOG_ERROR,
 | 
			
		||||
				  "load data failed,0x%lx,%d\r\n",
 | 
			
		||||
				  noffset, nlen);
 | 
			
		||||
			goto error3;
 | 
			
		||||
		}
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG,
 | 
			
		||||
			  "load data: da 0x%lx, offset 0x%lx, len = 0x%lx, memsize = 0x%lx, state 0x%x\r\n",
 | 
			
		||||
			  da, noffset, nlen, nmemsize, ret);
 | 
			
		||||
		last_load_state = ret;
 | 
			
		||||
		if (da != RPROC_LOAD_ANYADDR) {
 | 
			
		||||
			/* Data is supposed to be loaded to target memory */
 | 
			
		||||
			img_data = NULL;
 | 
			
		||||
			/* get the I/O region from remoteproc */
 | 
			
		||||
			pa = METAL_BAD_PHYS;
 | 
			
		||||
			(void)remoteproc_mmap(rproc, &pa, &da, nmemsize, 0, &io);
 | 
			
		||||
			if (pa == METAL_BAD_PHYS || io == NULL) {
 | 
			
		||||
				metal_log(METAL_LOG_ERROR,
 | 
			
		||||
					  "load failed, no mapping for 0x%llx.\r\n",
 | 
			
		||||
					  da);
 | 
			
		||||
				ret = -RPROC_EINVAL;
 | 
			
		||||
				goto error3;
 | 
			
		||||
			}
 | 
			
		||||
			if (nlen > 0) {
 | 
			
		||||
				ret = store_ops->load(store, noffset, nlen,
 | 
			
		||||
						      &img_data, pa, io, 1);
 | 
			
		||||
				if (ret != (int)nlen) {
 | 
			
		||||
					metal_log(METAL_LOG_ERROR,
 | 
			
		||||
						  "load data failed 0x%lx, 0x%lx, 0x%x\r\n",
 | 
			
		||||
						  pa, noffset, nlen);
 | 
			
		||||
					ret = -RPROC_EINVAL;
 | 
			
		||||
					goto error3;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (nmemsize > nlen) {
 | 
			
		||||
				size_t tmpoffset;
 | 
			
		||||
 | 
			
		||||
				tmpoffset = metal_io_phys_to_offset(io,
 | 
			
		||||
								    pa + nlen);
 | 
			
		||||
				metal_io_block_set(io, tmpoffset,
 | 
			
		||||
						   padding, (nmemsize - nlen));
 | 
			
		||||
			}
 | 
			
		||||
		} else if (nlen != 0) {
 | 
			
		||||
			ret = store_ops->load(store, noffset, nlen,
 | 
			
		||||
					      &img_data,
 | 
			
		||||
					      RPROC_LOAD_ANYADDR,
 | 
			
		||||
					      NULL, 1);
 | 
			
		||||
			if (ret < (int)nlen) {
 | 
			
		||||
				if ((last_load_state &
 | 
			
		||||
				    RPROC_LOADER_POST_DATA_LOAD) != 0) {
 | 
			
		||||
					metal_log(METAL_LOG_WARNING,
 | 
			
		||||
						  "not all the headers are loaded\r\n");
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
				metal_log(METAL_LOG_ERROR,
 | 
			
		||||
					  "post-load image data failed 0x%x,%d\r\n",
 | 
			
		||||
					  noffset, nlen);
 | 
			
		||||
				goto error3;
 | 
			
		||||
			}
 | 
			
		||||
			offset = noffset;
 | 
			
		||||
			len = nlen;
 | 
			
		||||
		} else {
 | 
			
		||||
			/* (last_load_state & RPROC_LOADER_LOAD_COMPLETE) != 0 */
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (rsc_len < 0) {
 | 
			
		||||
		ret = elf_locate_rsc_table(limg_info, &rsc_da,
 | 
			
		||||
					   &offset, &rsc_size);
 | 
			
		||||
		if (ret == 0 && rsc_size > 0) {
 | 
			
		||||
			/* parse resource table */
 | 
			
		||||
			rsc_len = (int)rsc_size;
 | 
			
		||||
			rsc_table = remoteproc_get_rsc_table(rproc, store,
 | 
			
		||||
							     store_ops,
 | 
			
		||||
							     offset,
 | 
			
		||||
							     rsc_len);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Update resource table */
 | 
			
		||||
	if (rsc_len && rsc_da != METAL_BAD_PHYS) {
 | 
			
		||||
		void *rsc_table_cp = rsc_table;
 | 
			
		||||
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG,
 | 
			
		||||
			  "%s, update resource table\r\n", __func__);
 | 
			
		||||
		rsc_table = remoteproc_mmap(rproc, NULL, &rsc_da,
 | 
			
		||||
					    rsc_len, 0, &io);
 | 
			
		||||
		if (rsc_table) {
 | 
			
		||||
			size_t rsc_io_offset;
 | 
			
		||||
 | 
			
		||||
			/* Update resource table */
 | 
			
		||||
			rsc_io_offset = metal_io_virt_to_offset(io, rsc_table);
 | 
			
		||||
			ret = metal_io_block_write(io, rsc_io_offset,
 | 
			
		||||
						   rsc_table_cp, rsc_len);
 | 
			
		||||
			if (ret != rsc_len) {
 | 
			
		||||
				metal_log(METAL_LOG_WARNING,
 | 
			
		||||
					  "load: failed to update rsc\r\n");
 | 
			
		||||
			}
 | 
			
		||||
			rproc->rsc_table = rsc_table;
 | 
			
		||||
			rproc->rsc_len = rsc_len;
 | 
			
		||||
		} else {
 | 
			
		||||
			metal_log(METAL_LOG_WARNING,
 | 
			
		||||
				  "load: not able to update rsc table.\n");
 | 
			
		||||
		}
 | 
			
		||||
		metal_free_memory(rsc_table_cp);
 | 
			
		||||
		/* So that the rsc_table will not get released */
 | 
			
		||||
		rsc_table = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	metal_log(METAL_LOG_DEBUG, "%s: successfully load firmware\r\n",
 | 
			
		||||
		  __func__);
 | 
			
		||||
	/* get entry point from the firmware */
 | 
			
		||||
	rproc->bootaddr = loader->get_entry(limg_info);
 | 
			
		||||
	rproc->state = RPROC_READY;
 | 
			
		||||
 | 
			
		||||
	metal_mutex_release(&rproc->lock);
 | 
			
		||||
	if (img_info)
 | 
			
		||||
		*img_info = limg_info;
 | 
			
		||||
	else
 | 
			
		||||
		loader->release(limg_info);
 | 
			
		||||
	store_ops->close(store);
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
error3:
 | 
			
		||||
	if (rsc_table)
 | 
			
		||||
		metal_free_memory(rsc_table);
 | 
			
		||||
error2:
 | 
			
		||||
	loader->release(limg_info);
 | 
			
		||||
error1:
 | 
			
		||||
	store_ops->close(store);
 | 
			
		||||
	metal_mutex_release(&rproc->lock);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int remoteproc_load_noblock(struct remoteproc *rproc,
 | 
			
		||||
			    const void *img_data, size_t offset, size_t len,
 | 
			
		||||
			    void **img_info,
 | 
			
		||||
			    metal_phys_addr_t *pa, struct metal_io_region **io,
 | 
			
		||||
			    size_t *noffset, size_t *nlen,
 | 
			
		||||
			    size_t *nmlen, unsigned char *padding)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct loader_ops *loader;
 | 
			
		||||
	void *limg_info = NULL;
 | 
			
		||||
	int last_load_state;
 | 
			
		||||
	metal_phys_addr_t da, rsc_da;
 | 
			
		||||
	size_t rsc_size;
 | 
			
		||||
	void *rsc_table = NULL, *lrsc_table = NULL;
 | 
			
		||||
 | 
			
		||||
	if (!rproc)
 | 
			
		||||
		return -RPROC_ENODEV;
 | 
			
		||||
 | 
			
		||||
	metal_assert(pa != NULL);
 | 
			
		||||
	metal_assert(io != NULL);
 | 
			
		||||
	metal_assert(noffset != NULL);
 | 
			
		||||
	metal_assert(nlen != NULL);
 | 
			
		||||
	metal_assert(nmlen != NULL);
 | 
			
		||||
	metal_assert(padding != NULL);
 | 
			
		||||
 | 
			
		||||
	metal_mutex_acquire(&rproc->lock);
 | 
			
		||||
	metal_log(METAL_LOG_DEBUG, "%s: check remoteproc status\r\n", __func__);
 | 
			
		||||
	/* If remoteproc is not in ready state, cannot load executable */
 | 
			
		||||
	if (rproc->state != RPROC_READY) {
 | 
			
		||||
		metal_log(METAL_LOG_ERROR,
 | 
			
		||||
			  "load failure: invalid rproc state %d.\r\n",
 | 
			
		||||
			  rproc->state);
 | 
			
		||||
		metal_mutex_release(&rproc->lock);
 | 
			
		||||
		return -RPROC_EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Check executable format to select a parser */
 | 
			
		||||
	loader = rproc->loader;
 | 
			
		||||
	if (!loader) {
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG, "%s: check loader\r\n", __func__);
 | 
			
		||||
		if (img_data == NULL || offset != 0 || len == 0) {
 | 
			
		||||
			metal_log(METAL_LOG_ERROR,
 | 
			
		||||
				  "load failure, invalid inputs, not able to identify image.\r\n");
 | 
			
		||||
			metal_mutex_release(&rproc->lock);
 | 
			
		||||
			return -RPROC_EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		loader = remoteproc_check_fw_format(img_data, len);
 | 
			
		||||
		if (!loader) {
 | 
			
		||||
			metal_log(METAL_LOG_ERROR,
 | 
			
		||||
			       "load failure: failed to identify image.\n");
 | 
			
		||||
			ret = -RPROC_EINVAL;
 | 
			
		||||
			metal_mutex_release(&rproc->lock);
 | 
			
		||||
			return -RPROC_EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		rproc->loader = loader;
 | 
			
		||||
	}
 | 
			
		||||
	if (img_info == NULL || *img_info == NULL ) {
 | 
			
		||||
		last_load_state = 0;
 | 
			
		||||
	} else {
 | 
			
		||||
		limg_info = *img_info;
 | 
			
		||||
		last_load_state = loader->get_load_state(limg_info);
 | 
			
		||||
		if (last_load_state < 0) {
 | 
			
		||||
			metal_log(METAL_LOG_ERROR,
 | 
			
		||||
				  "load failure, not able get load state.\r\n");
 | 
			
		||||
			metal_mutex_release(&rproc->lock);
 | 
			
		||||
			return -RPROC_EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	da = RPROC_LOAD_ANYADDR;
 | 
			
		||||
	*nlen = 0;
 | 
			
		||||
	if ((last_load_state & RPROC_LOADER_READY_TO_LOAD) == 0 &&
 | 
			
		||||
	    (last_load_state & RPROC_LOADER_LOAD_COMPLETE) == 0) {
 | 
			
		||||
		/* Get the mandatory executable headers */
 | 
			
		||||
		ret = loader->load_header(img_data, offset, len,
 | 
			
		||||
					  &limg_info, last_load_state,
 | 
			
		||||
					  noffset, nlen);
 | 
			
		||||
		last_load_state = (unsigned int)ret;
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG,
 | 
			
		||||
			  "%s, load header 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n",
 | 
			
		||||
			  __func__, offset, len, *noffset, *nlen);
 | 
			
		||||
		if (ret < 0) {
 | 
			
		||||
			metal_log(METAL_LOG_ERROR,
 | 
			
		||||
				  "load header failed 0x%lx,%d.\r\n",
 | 
			
		||||
				  offset, len);
 | 
			
		||||
 | 
			
		||||
			goto error1;
 | 
			
		||||
		}
 | 
			
		||||
		last_load_state = loader->get_load_state(limg_info);
 | 
			
		||||
		if (*nlen != 0 &&
 | 
			
		||||
		    (last_load_state & RPROC_LOADER_READY_TO_LOAD) == 0)
 | 
			
		||||
			goto out;
 | 
			
		||||
	}
 | 
			
		||||
	if ((last_load_state & RPROC_LOADER_READY_TO_LOAD) != 0 ||
 | 
			
		||||
	    (last_load_state & RPROC_LOADER_POST_DATA_LOAD) != 0) {
 | 
			
		||||
		/* Enough information to know which target memory for
 | 
			
		||||
		 * which data.
 | 
			
		||||
		 */
 | 
			
		||||
		ret = loader->load_data(rproc, img_data, offset, len,
 | 
			
		||||
					&limg_info, last_load_state, &da,
 | 
			
		||||
					noffset, nlen, padding, nmlen);
 | 
			
		||||
		metal_log(METAL_LOG_DEBUG,
 | 
			
		||||
			  "%s, load data 0x%lx, 0x%x, next 0x%lx, 0x%x\r\n",
 | 
			
		||||
			  __func__, offset, len, *noffset, *nlen);
 | 
			
		||||
		if (ret < 0) {
 | 
			
		||||
			metal_log(METAL_LOG_ERROR,
 | 
			
		||||
				  "load data failed,0x%lx,%d\r\n",
 | 
			
		||||
				  offset, len);
 | 
			
		||||
			goto error1;
 | 
			
		||||
		}
 | 
			
		||||
		if (da != RPROC_LOAD_ANYADDR) {
 | 
			
		||||
			/* get the I/O region from remoteproc */
 | 
			
		||||
			*pa = METAL_BAD_PHYS;
 | 
			
		||||
			(void)remoteproc_mmap(rproc, pa, &da, *nmlen, 0, io);
 | 
			
		||||
			if (*pa == METAL_BAD_PHYS || io == NULL) {
 | 
			
		||||
				metal_log(METAL_LOG_ERROR,
 | 
			
		||||
					  "load failed, no mapping for 0x%llx.\r\n",
 | 
			
		||||
					  da);
 | 
			
		||||
				ret = -RPROC_EINVAL;
 | 
			
		||||
				goto error1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (*nlen != 0)
 | 
			
		||||
			goto out;
 | 
			
		||||
		else
 | 
			
		||||
			last_load_state = loader->get_load_state(limg_info);
 | 
			
		||||
	}
 | 
			
		||||
	if ((last_load_state & RPROC_LOADER_LOAD_COMPLETE) != 0) {
 | 
			
		||||
		/* Get resource table */
 | 
			
		||||
		size_t rsc_offset;
 | 
			
		||||
		size_t rsc_io_offset;
 | 
			
		||||
 | 
			
		||||
		ret = elf_locate_rsc_table(limg_info, &rsc_da,
 | 
			
		||||
					   &rsc_offset, &rsc_size);
 | 
			
		||||
		if (ret == 0 && rsc_size > 0) {
 | 
			
		||||
			lrsc_table = metal_allocate_memory(rsc_size);
 | 
			
		||||
			if (lrsc_table == NULL) {
 | 
			
		||||
				ret = -RPROC_ENOMEM;
 | 
			
		||||
				goto error1;
 | 
			
		||||
			}
 | 
			
		||||
			rsc_table = remoteproc_mmap(rproc, NULL, &rsc_da,
 | 
			
		||||
						    rsc_size, 0, io);
 | 
			
		||||
			if (*io == NULL) {
 | 
			
		||||
				metal_log(METAL_LOG_ERROR,
 | 
			
		||||
					  "load failed: failed to mmap rsc\r\n");
 | 
			
		||||
				metal_free_memory(lrsc_table);
 | 
			
		||||
				goto error1;
 | 
			
		||||
			}
 | 
			
		||||
			rsc_io_offset = metal_io_virt_to_offset(*io, rsc_table);
 | 
			
		||||
			ret = metal_io_block_read(*io, rsc_io_offset,
 | 
			
		||||
						  lrsc_table, (int)rsc_size);
 | 
			
		||||
			if (ret != (int)rsc_size) {
 | 
			
		||||
				metal_log(METAL_LOG_ERROR,
 | 
			
		||||
					  "load failed: failed to get rsc\r\n");
 | 
			
		||||
				metal_free_memory(lrsc_table);
 | 
			
		||||
				goto error1;
 | 
			
		||||
			}
 | 
			
		||||
			/* parse resource table */
 | 
			
		||||
			ret = remoteproc_parse_rsc_table(rproc, lrsc_table,
 | 
			
		||||
							 rsc_size);
 | 
			
		||||
			if (ret == (int)rsc_size) {
 | 
			
		||||
				metal_log(METAL_LOG_ERROR,
 | 
			
		||||
					  "load failed: failed to parse rsc\r\n");
 | 
			
		||||
				metal_free_memory(lrsc_table);
 | 
			
		||||
				goto error1;
 | 
			
		||||
			}
 | 
			
		||||
			/* Update resource table */
 | 
			
		||||
			ret = metal_io_block_write(*io, rsc_io_offset,
 | 
			
		||||
						  lrsc_table, (int)rsc_size);
 | 
			
		||||
			if (ret != (int)rsc_size) {
 | 
			
		||||
				metal_log(METAL_LOG_WARNING,
 | 
			
		||||
					  "load exectuable, failed to update rsc\r\n");
 | 
			
		||||
			}
 | 
			
		||||
			rproc->rsc_table = rsc_table;
 | 
			
		||||
			rproc->rsc_len = (int)rsc_size;
 | 
			
		||||
			metal_free_memory(lrsc_table);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
out:
 | 
			
		||||
	if (img_info != NULL)
 | 
			
		||||
		*img_info = limg_info;
 | 
			
		||||
	else
 | 
			
		||||
		loader->release(limg_info);
 | 
			
		||||
	metal_mutex_release(&rproc->lock);
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
error1:
 | 
			
		||||
	loader->release(limg_info);
 | 
			
		||||
	metal_mutex_release(&rproc->lock);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int remoteproc_allocate_id(struct remoteproc *rproc,
 | 
			
		||||
				    unsigned int start,
 | 
			
		||||
				    unsigned int end)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int notifyid;
 | 
			
		||||
 | 
			
		||||
	if (start == RSC_NOTIFY_ID_ANY)
 | 
			
		||||
		start = 0;
 | 
			
		||||
	if (end == RSC_NOTIFY_ID_ANY)
 | 
			
		||||
		end = METAL_BITS_PER_ULONG;
 | 
			
		||||
	notifyid = metal_bitmap_next_clear_bit(&rproc->bitmap,
 | 
			
		||||
					     start, end);
 | 
			
		||||
	if (notifyid != end)
 | 
			
		||||
		metal_bitmap_set_bit(&rproc->bitmap, notifyid);
 | 
			
		||||
	else
 | 
			
		||||
		notifyid = RSC_NOTIFY_ID_ANY;
 | 
			
		||||
	return notifyid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int remoteproc_virtio_notify(void *priv, uint32_t id)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc *rproc = priv;
 | 
			
		||||
 | 
			
		||||
	return rproc->ops->notify(rproc, id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct virtio_device *
 | 
			
		||||
remoteproc_create_virtio(struct remoteproc *rproc,
 | 
			
		||||
			 int vdev_id, unsigned int role,
 | 
			
		||||
			 void (*rst_cb)(struct virtio_device *vdev))
 | 
			
		||||
{
 | 
			
		||||
	char *rsc_table;
 | 
			
		||||
	struct fw_rsc_vdev *vdev_rsc;
 | 
			
		||||
	struct metal_io_region *vdev_rsc_io;
 | 
			
		||||
	struct virtio_device *vdev;
 | 
			
		||||
	struct remoteproc_virtio *rpvdev;
 | 
			
		||||
	size_t vdev_rsc_offset;
 | 
			
		||||
	unsigned int notifyid;
 | 
			
		||||
	unsigned int num_vrings, i;
 | 
			
		||||
	struct metal_list *node;
 | 
			
		||||
 | 
			
		||||
	metal_assert(rproc);
 | 
			
		||||
	metal_mutex_acquire(&rproc->lock);
 | 
			
		||||
	rsc_table = rproc->rsc_table;
 | 
			
		||||
	vdev_rsc_io = rproc->rsc_io;
 | 
			
		||||
	vdev_rsc_offset = find_rsc(rsc_table, RSC_VDEV, vdev_id);
 | 
			
		||||
	if (!vdev_rsc_offset) {
 | 
			
		||||
		metal_mutex_release(&rproc->lock);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	vdev_rsc = (struct fw_rsc_vdev *)(rsc_table + vdev_rsc_offset);
 | 
			
		||||
	notifyid = vdev_rsc->notifyid;
 | 
			
		||||
	/* Check if the virtio device is already created */
 | 
			
		||||
	metal_list_for_each(&rproc->vdevs, node) {
 | 
			
		||||
		rpvdev = metal_container_of(node, struct remoteproc_virtio,
 | 
			
		||||
					    node);
 | 
			
		||||
		if (rpvdev->vdev.index == notifyid)
 | 
			
		||||
			return &rpvdev->vdev;
 | 
			
		||||
	}
 | 
			
		||||
	vdev = rproc_virtio_create_vdev(role, notifyid,
 | 
			
		||||
					vdev_rsc, vdev_rsc_io, rproc,
 | 
			
		||||
					remoteproc_virtio_notify,
 | 
			
		||||
					rst_cb);
 | 
			
		||||
	rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev);
 | 
			
		||||
	metal_list_add_tail(&rproc->vdevs, &rpvdev->node);
 | 
			
		||||
	num_vrings = vdev_rsc->num_of_vrings;
 | 
			
		||||
	/* set the notification id for vrings */
 | 
			
		||||
	for (i = 0; i < num_vrings; i++) {
 | 
			
		||||
		struct fw_rsc_vdev_vring *vring_rsc;
 | 
			
		||||
		metal_phys_addr_t da;
 | 
			
		||||
		unsigned int num_descs, align;
 | 
			
		||||
		struct metal_io_region *io;
 | 
			
		||||
		void *va;
 | 
			
		||||
		size_t size;
 | 
			
		||||
		int ret;
 | 
			
		||||
 | 
			
		||||
		vring_rsc = &vdev_rsc->vring[i];
 | 
			
		||||
		notifyid = vring_rsc->notifyid;
 | 
			
		||||
		da = vring_rsc->da;
 | 
			
		||||
		num_descs = vring_rsc->num;
 | 
			
		||||
		align = vring_rsc->align;
 | 
			
		||||
		size = vring_size(num_descs, align);
 | 
			
		||||
		va = remoteproc_mmap(rproc, NULL, &da, size, 0, &io);
 | 
			
		||||
		if (!va)
 | 
			
		||||
			goto err1;
 | 
			
		||||
		ret = rproc_virtio_init_vring(vdev, i, notifyid,
 | 
			
		||||
					      va, io, num_descs, align);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			goto err1;
 | 
			
		||||
	}
 | 
			
		||||
	metal_mutex_release(&rproc->lock);
 | 
			
		||||
	return vdev;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	remoteproc_remove_virtio(rproc, vdev);
 | 
			
		||||
	metal_mutex_release(&rproc->lock);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void remoteproc_remove_virtio(struct remoteproc *rproc,
 | 
			
		||||
			      struct virtio_device *vdev)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc_virtio *rpvdev;
 | 
			
		||||
 | 
			
		||||
	(void)rproc;
 | 
			
		||||
	metal_assert(vdev);
 | 
			
		||||
	rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev);
 | 
			
		||||
	metal_list_del(&rpvdev->node);
 | 
			
		||||
	rproc_virtio_remove_vdev(&rpvdev->vdev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int remoteproc_get_notification(struct remoteproc *rproc, uint32_t notifyid)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc_virtio *rpvdev;
 | 
			
		||||
	struct metal_list *node;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	metal_list_for_each(&rproc->vdevs, node) {
 | 
			
		||||
		rpvdev = metal_container_of(node, struct remoteproc_virtio,
 | 
			
		||||
					    node);
 | 
			
		||||
		ret = rproc_virtio_notified(&rpvdev->vdev, notifyid);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,330 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Remoteproc Virtio Framework Implementation
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright(c) 2018 Xilinx Ltd.
 | 
			
		||||
 * Copyright(c) 2011 Texas Instruments, Inc.
 | 
			
		||||
 * Copyright(c) 2011 Google, Inc.
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 *
 | 
			
		||||
 * * Redistributions of source code must retain the above copyright
 | 
			
		||||
 *   notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * * Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *   notice, this list of conditions and the following disclaimer in
 | 
			
		||||
 *   the documentation and/or other materials provided with the
 | 
			
		||||
 *   distribution.
 | 
			
		||||
 * * Neither the name Texas Instruments nor the names of its
 | 
			
		||||
 *   contributors may be used to endorse or promote products derived
 | 
			
		||||
 *   from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
			
		||||
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
			
		||||
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | 
			
		||||
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | 
			
		||||
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | 
			
		||||
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <openamp/remoteproc.h>
 | 
			
		||||
#include <openamp/remoteproc_virtio.h>
 | 
			
		||||
#include <openamp/virtqueue.h>
 | 
			
		||||
#include <metal/utilities.h>
 | 
			
		||||
#include <metal/alloc.h>
 | 
			
		||||
 | 
			
		||||
static void rproc_virtio_virtqueue_notify(struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc_virtio *rpvdev;
 | 
			
		||||
	struct virtio_vring_info *vring_info;
 | 
			
		||||
	struct virtio_device *vdev;
 | 
			
		||||
	unsigned int vq_id = vq->vq_queue_index;
 | 
			
		||||
 | 
			
		||||
	vdev = vq->vq_dev;
 | 
			
		||||
	rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev);
 | 
			
		||||
	metal_assert(vq_id <= vdev->vrings_num);
 | 
			
		||||
	vring_info = &vdev->vrings_info[vq_id];
 | 
			
		||||
	rpvdev->notify(rpvdev->priv, vring_info->notifyid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned char rproc_virtio_get_status(struct virtio_device *vdev)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc_virtio *rpvdev;
 | 
			
		||||
	struct fw_rsc_vdev *vdev_rsc;
 | 
			
		||||
	struct metal_io_region *io;
 | 
			
		||||
	char status;
 | 
			
		||||
 | 
			
		||||
	rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev);
 | 
			
		||||
	vdev_rsc = rpvdev->vdev_rsc;
 | 
			
		||||
	io = rpvdev->vdev_rsc_io;
 | 
			
		||||
	status = metal_io_read8(io,
 | 
			
		||||
				metal_io_virt_to_offset(io, &vdev_rsc->status));
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
static void rproc_virtio_set_status(struct virtio_device *vdev,
 | 
			
		||||
				    unsigned char status)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc_virtio *rpvdev;
 | 
			
		||||
	struct fw_rsc_vdev *vdev_rsc;
 | 
			
		||||
	struct metal_io_region *io;
 | 
			
		||||
 | 
			
		||||
	rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev);
 | 
			
		||||
	vdev_rsc = rpvdev->vdev_rsc;
 | 
			
		||||
	io = rpvdev->vdev_rsc_io;
 | 
			
		||||
	metal_io_write8(io,
 | 
			
		||||
			metal_io_virt_to_offset(io, &vdev_rsc->status),
 | 
			
		||||
			status);
 | 
			
		||||
	rpvdev->notify(rpvdev->priv, vdev->index);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static uint32_t rproc_virtio_get_features(struct virtio_device *vdev)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc_virtio *rpvdev;
 | 
			
		||||
	struct fw_rsc_vdev *vdev_rsc;
 | 
			
		||||
	struct metal_io_region *io;
 | 
			
		||||
	uint32_t features;
 | 
			
		||||
 | 
			
		||||
	rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev);
 | 
			
		||||
	vdev_rsc = rpvdev->vdev_rsc;
 | 
			
		||||
	io = rpvdev->vdev_rsc_io;
 | 
			
		||||
	/* TODO: shall we get features based on the role ? */
 | 
			
		||||
	features = metal_io_read32(io,
 | 
			
		||||
			metal_io_virt_to_offset(io, &vdev_rsc->dfeatures));
 | 
			
		||||
 | 
			
		||||
	return features;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
static void rproc_virtio_set_features(struct virtio_device *vdev,
 | 
			
		||||
				      uint32_t features)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc_virtio *rpvdev;
 | 
			
		||||
	struct fw_rsc_vdev *vdev_rsc;
 | 
			
		||||
	struct metal_io_region *io;
 | 
			
		||||
 | 
			
		||||
	rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev);
 | 
			
		||||
	vdev_rsc = rpvdev->vdev_rsc;
 | 
			
		||||
	io = rpvdev->vdev_rsc_io;
 | 
			
		||||
	/* TODO: shall we set features based on the role ? */
 | 
			
		||||
	metal_io_write32(io,
 | 
			
		||||
			 metal_io_virt_to_offset(io, &vdev_rsc->dfeatures),
 | 
			
		||||
			 features);
 | 
			
		||||
	rpvdev->notify(rpvdev->priv, vdev->index);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static uint32_t rproc_virtio_negotiate_features(struct virtio_device *vdev,
 | 
			
		||||
						uint32_t features)
 | 
			
		||||
{
 | 
			
		||||
	(void)vdev;
 | 
			
		||||
	(void)features;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rproc_virtio_read_config(struct virtio_device *vdev,
 | 
			
		||||
				     uint32_t offset, void *dst, int length)
 | 
			
		||||
{
 | 
			
		||||
	(void)vdev;
 | 
			
		||||
	(void)offset;
 | 
			
		||||
	(void)dst;
 | 
			
		||||
	(void)length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
static void rproc_virtio_write_config(struct virtio_device *vdev,
 | 
			
		||||
				      uint32_t offset, void *src, int length)
 | 
			
		||||
{
 | 
			
		||||
	(void)vdev;
 | 
			
		||||
	(void)offset;
 | 
			
		||||
	(void)src;
 | 
			
		||||
	(void)length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rproc_virtio_reset_device(struct virtio_device *vdev)
 | 
			
		||||
{
 | 
			
		||||
	if (vdev->role == VIRTIO_DEV_MASTER)
 | 
			
		||||
		rproc_virtio_set_status(vdev,
 | 
			
		||||
					VIRTIO_CONFIG_STATUS_NEEDS_RESET);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
const struct virtio_dispatch remoteproc_virtio_dispatch_funcs = {
 | 
			
		||||
	.get_status =  rproc_virtio_get_status,
 | 
			
		||||
	.get_features = rproc_virtio_get_features,
 | 
			
		||||
	.read_config = rproc_virtio_read_config,
 | 
			
		||||
	.notify = rproc_virtio_virtqueue_notify,
 | 
			
		||||
	.negotiate_features = rproc_virtio_negotiate_features,
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
	/*
 | 
			
		||||
	 * We suppose here that the vdev is in a shared memory so that can
 | 
			
		||||
	 * be access only by one core: the master. In this case salve core has
 | 
			
		||||
	 * only read access right.
 | 
			
		||||
	 */
 | 
			
		||||
	.set_status = rproc_virtio_set_status,
 | 
			
		||||
	.set_features = rproc_virtio_set_features,
 | 
			
		||||
	.write_config = rproc_virtio_write_config,
 | 
			
		||||
	.reset_device = rproc_virtio_reset_device,
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct virtio_device *
 | 
			
		||||
rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid,
 | 
			
		||||
			 void *rsc, struct metal_io_region *rsc_io,
 | 
			
		||||
			 void *priv,
 | 
			
		||||
			 rpvdev_notify_func notify,
 | 
			
		||||
			 virtio_dev_reset_cb rst_cb)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc_virtio *rpvdev;
 | 
			
		||||
	struct virtio_vring_info *vrings_info;
 | 
			
		||||
	struct fw_rsc_vdev *vdev_rsc = rsc;
 | 
			
		||||
	struct virtio_device *vdev;
 | 
			
		||||
	unsigned int num_vrings = vdev_rsc->num_of_vrings;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	rpvdev = metal_allocate_memory(sizeof(*rpvdev));
 | 
			
		||||
	if (!rpvdev)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	vrings_info = metal_allocate_memory(sizeof(*vrings_info) * num_vrings);
 | 
			
		||||
	if (!vrings_info)
 | 
			
		||||
		goto err0;
 | 
			
		||||
	memset(rpvdev, 0, sizeof(*rpvdev));
 | 
			
		||||
	memset(vrings_info, 0, sizeof(*vrings_info));
 | 
			
		||||
	vdev = &rpvdev->vdev;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_vrings; i++) {
 | 
			
		||||
		struct virtqueue *vq;
 | 
			
		||||
		struct fw_rsc_vdev_vring *vring_rsc;
 | 
			
		||||
		unsigned int num_extra_desc = 0;
 | 
			
		||||
 | 
			
		||||
		vring_rsc = &vdev_rsc->vring[i];
 | 
			
		||||
		if (role == VIRTIO_DEV_MASTER) {
 | 
			
		||||
			num_extra_desc = vring_rsc->num;
 | 
			
		||||
		}
 | 
			
		||||
		vq = virtqueue_allocate(num_extra_desc);
 | 
			
		||||
		if (!vq)
 | 
			
		||||
			goto err1;
 | 
			
		||||
		vrings_info[i].vq = vq;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* FIXME commended as seems not nedded, already stored in vdev */
 | 
			
		||||
	//rpvdev->notifyid = notifyid;
 | 
			
		||||
	rpvdev->notify = notify;
 | 
			
		||||
	rpvdev->priv = priv;
 | 
			
		||||
	vdev->vrings_info = vrings_info;
 | 
			
		||||
	/* Assuming the shared memory has been mapped and registered if
 | 
			
		||||
	 * necessary
 | 
			
		||||
	 */
 | 
			
		||||
	rpvdev->vdev_rsc = vdev_rsc;
 | 
			
		||||
	rpvdev->vdev_rsc_io = rsc_io;
 | 
			
		||||
 | 
			
		||||
	vdev->index = notifyid;
 | 
			
		||||
	vdev->role = role;
 | 
			
		||||
	vdev->reset_cb = rst_cb;
 | 
			
		||||
	vdev->vrings_num = num_vrings;
 | 
			
		||||
	vdev->func = &remoteproc_virtio_dispatch_funcs;
 | 
			
		||||
	/* TODO: Shall we set features here ? */
 | 
			
		||||
 | 
			
		||||
	return &rpvdev->vdev;
 | 
			
		||||
 | 
			
		||||
err1:
 | 
			
		||||
	for (i = 0; i < num_vrings; i++) {
 | 
			
		||||
		if (vrings_info[i].vq)
 | 
			
		||||
			metal_free_memory(vrings_info[i].vq);
 | 
			
		||||
	}
 | 
			
		||||
	metal_free_memory(vrings_info);
 | 
			
		||||
err0:
 | 
			
		||||
	metal_free_memory(rpvdev);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rproc_virtio_remove_vdev(struct virtio_device *vdev)
 | 
			
		||||
{
 | 
			
		||||
	struct remoteproc_virtio *rpvdev;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
 | 
			
		||||
	if (!vdev)
 | 
			
		||||
		return;
 | 
			
		||||
	rpvdev = metal_container_of(vdev, struct remoteproc_virtio, vdev);
 | 
			
		||||
	for (i = 0; i < vdev->vrings_num; i++) {
 | 
			
		||||
		struct virtqueue *vq;
 | 
			
		||||
 | 
			
		||||
		vq = vdev->vrings_info[i].vq;
 | 
			
		||||
		if (vq)
 | 
			
		||||
			metal_free_memory(vq);
 | 
			
		||||
	}
 | 
			
		||||
	metal_free_memory(vdev->vrings_info);
 | 
			
		||||
	metal_free_memory(rpvdev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rproc_virtio_init_vring(struct virtio_device *vdev, unsigned int index,
 | 
			
		||||
			    unsigned int notifyid, void *va,
 | 
			
		||||
			    struct metal_io_region *io,
 | 
			
		||||
			    unsigned int num_descs, unsigned int align)
 | 
			
		||||
{
 | 
			
		||||
	struct virtio_vring_info *vring_info;
 | 
			
		||||
	unsigned int num_vrings;
 | 
			
		||||
 | 
			
		||||
	num_vrings = vdev->vrings_num;
 | 
			
		||||
	if (index >= num_vrings)
 | 
			
		||||
		return -RPROC_EINVAL;
 | 
			
		||||
	vring_info = &vdev->vrings_info[index];
 | 
			
		||||
	vring_info->io = io;
 | 
			
		||||
	vring_info->notifyid = notifyid;
 | 
			
		||||
	vring_info->info.vaddr = va;
 | 
			
		||||
	vring_info->info.num_descs = num_descs;
 | 
			
		||||
	vring_info->info.align = align;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rproc_virtio_notified(struct virtio_device *vdev, uint32_t notifyid)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int num_vrings, i;
 | 
			
		||||
	struct virtio_vring_info *vring_info;
 | 
			
		||||
	struct virtqueue *vq;
 | 
			
		||||
 | 
			
		||||
	if (!vdev)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	/* We do nothing for vdev notification in this implementation */
 | 
			
		||||
	if (vdev->index == notifyid)
 | 
			
		||||
		return 0;
 | 
			
		||||
	num_vrings = vdev->vrings_num;
 | 
			
		||||
	for (i = 0; i < num_vrings; i++) {
 | 
			
		||||
		vring_info = &vdev->vrings_info[i];
 | 
			
		||||
		if (vring_info->notifyid == notifyid ||
 | 
			
		||||
		    notifyid == RSC_NOTIFY_ID_ANY) {
 | 
			
		||||
			vq = vring_info->vq;
 | 
			
		||||
			virtqueue_notification(vq);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rproc_virtio_wait_remote_ready(struct virtio_device *vdev)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t status;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * No status available for slave. As Master has not to wait
 | 
			
		||||
	 * slave action, we can return. Behavior should be updated
 | 
			
		||||
	 * in future if a slave status is added.
 | 
			
		||||
	 */
 | 
			
		||||
	if (vdev->role == VIRTIO_DEV_MASTER)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		status = rproc_virtio_get_status(vdev);
 | 
			
		||||
		if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK)
 | 
			
		||||
			return;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,223 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2014, Mentor Graphics Corporation
 | 
			
		||||
 * Copyright (c) 2018, Xilinx Inc.
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <metal/io.h>
 | 
			
		||||
#include <openamp/rsc_table_parser.h>
 | 
			
		||||
 | 
			
		||||
static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc);
 | 
			
		||||
 | 
			
		||||
/* Resources handler */
 | 
			
		||||
rsc_handler rsc_handler_table[] = {
 | 
			
		||||
	handle_carve_out_rsc, /**< carved out resource */
 | 
			
		||||
	handle_dummy_rsc, /**< IOMMU dev mem resource */
 | 
			
		||||
	handle_trace_rsc, /**< trace buffer resource */
 | 
			
		||||
	handle_vdev_rsc, /**< virtio resource */
 | 
			
		||||
	handle_dummy_rsc, /**< rproc shared memory resource */
 | 
			
		||||
	handle_dummy_rsc, /**< firmware checksum resource */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int handle_rsc_table(struct remoteproc *rproc,
 | 
			
		||||
		     struct resource_table *rsc_table, int size,
 | 
			
		||||
		     struct metal_io_region *io)
 | 
			
		||||
{
 | 
			
		||||
	char *rsc_start;
 | 
			
		||||
	unsigned int rsc_type;
 | 
			
		||||
	unsigned int idx, offset;
 | 
			
		||||
	int status = 0;
 | 
			
		||||
 | 
			
		||||
	/* Validate rsc table header fields */
 | 
			
		||||
 | 
			
		||||
	/* Minimum rsc table size */
 | 
			
		||||
	if (sizeof(struct resource_table) > (unsigned int)size) {
 | 
			
		||||
		return -RPROC_ERR_RSC_TAB_TRUNC;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Supported version */
 | 
			
		||||
	if (rsc_table->ver != RSC_TAB_SUPPORTED_VERSION) {
 | 
			
		||||
		return -RPROC_ERR_RSC_TAB_VER;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Offset array */
 | 
			
		||||
	offset = sizeof(struct resource_table)
 | 
			
		||||
		 + rsc_table->num * sizeof(rsc_table->offset[0]);
 | 
			
		||||
 | 
			
		||||
	if (offset > (unsigned int)size) {
 | 
			
		||||
		return -RPROC_ERR_RSC_TAB_TRUNC;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Reserved fields - must be zero */
 | 
			
		||||
	if ((rsc_table->reserved[0] != 0 || rsc_table->reserved[1]) != 0) {
 | 
			
		||||
		return -RPROC_ERR_RSC_TAB_RSVD;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Loop through the offset array and parse each resource entry */
 | 
			
		||||
	for (idx = 0; idx < rsc_table->num; idx++) {
 | 
			
		||||
		rsc_start = (char *)rsc_table;
 | 
			
		||||
		rsc_start += rsc_table->offset[idx];
 | 
			
		||||
		if (io &&
 | 
			
		||||
		    metal_io_virt_to_offset(io, rsc_start) == METAL_BAD_OFFSET)
 | 
			
		||||
			return -RPROC_ERR_RSC_TAB_TRUNC;
 | 
			
		||||
		rsc_type = *((uint32_t *)rsc_start);
 | 
			
		||||
		if (rsc_type < RSC_LAST)
 | 
			
		||||
			status = rsc_handler_table[rsc_type](rproc,
 | 
			
		||||
							     rsc_start);
 | 
			
		||||
		else if (rsc_type >= RSC_VENDOR_START &&
 | 
			
		||||
			 rsc_type <= RSC_VENDOR_END)
 | 
			
		||||
			status = handle_vendor_rsc(rproc, rsc_start);
 | 
			
		||||
		if (status == -RPROC_ERR_RSC_TAB_NS) {
 | 
			
		||||
			status = 0;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		else if (status)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * handle_carve_out_rsc
 | 
			
		||||
 *
 | 
			
		||||
 * Carveout resource handler.
 | 
			
		||||
 *
 | 
			
		||||
 * @param rproc - pointer to remote remoteproc
 | 
			
		||||
 * @param rsc   - pointer to carveout resource
 | 
			
		||||
 *
 | 
			
		||||
 * @returns - 0 for success, or negative value for failure
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc)
 | 
			
		||||
{
 | 
			
		||||
	struct fw_rsc_carveout *carve_rsc = (struct fw_rsc_carveout *)rsc;
 | 
			
		||||
	metal_phys_addr_t da;
 | 
			
		||||
	metal_phys_addr_t pa;
 | 
			
		||||
	size_t size;
 | 
			
		||||
	unsigned int attribute;
 | 
			
		||||
 | 
			
		||||
	/* Validate resource fields */
 | 
			
		||||
	if (!carve_rsc) {
 | 
			
		||||
		return -RPROC_ERR_RSC_TAB_NP;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (carve_rsc->reserved) {
 | 
			
		||||
		return -RPROC_ERR_RSC_TAB_RSVD;
 | 
			
		||||
	}
 | 
			
		||||
	pa = carve_rsc->pa;
 | 
			
		||||
	da = carve_rsc->da;
 | 
			
		||||
	size = carve_rsc->len;
 | 
			
		||||
	attribute = carve_rsc->flags;
 | 
			
		||||
	if (remoteproc_mmap(rproc, &pa, &da, size, attribute, NULL))
 | 
			
		||||
		return 0;
 | 
			
		||||
	else
 | 
			
		||||
		return -RPROC_EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int handle_vendor_rsc(struct remoteproc *rproc, void *rsc)
 | 
			
		||||
{
 | 
			
		||||
	if (rproc && rproc->ops->handle_rsc) {
 | 
			
		||||
		struct fw_rsc_vendor *vend_rsc = rsc;
 | 
			
		||||
		size_t len = vend_rsc->len;
 | 
			
		||||
 | 
			
		||||
		return rproc->ops->handle_rsc(rproc, rsc, len);
 | 
			
		||||
	}
 | 
			
		||||
	return -RPROC_ERR_RSC_TAB_NS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int handle_vdev_rsc(struct remoteproc *rproc, void *rsc)
 | 
			
		||||
{
 | 
			
		||||
	struct fw_rsc_vdev *vdev_rsc = (struct fw_rsc_vdev *)rsc;
 | 
			
		||||
	unsigned int notifyid, i, num_vrings;
 | 
			
		||||
 | 
			
		||||
	/* only assign notification IDs but do not initialize vdev */
 | 
			
		||||
	notifyid = vdev_rsc->notifyid;
 | 
			
		||||
	notifyid = remoteproc_allocate_id(rproc,
 | 
			
		||||
					  notifyid, notifyid + 1);
 | 
			
		||||
	if (notifyid != RSC_NOTIFY_ID_ANY) {
 | 
			
		||||
		vdev_rsc->notifyid = notifyid;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	num_vrings = vdev_rsc->num_of_vrings;
 | 
			
		||||
	for (i = 0; i < num_vrings; i++) {
 | 
			
		||||
		struct fw_rsc_vdev_vring *vring_rsc;
 | 
			
		||||
 | 
			
		||||
		vring_rsc = &vdev_rsc->vring[i];
 | 
			
		||||
		notifyid = vring_rsc->notifyid;
 | 
			
		||||
		notifyid = remoteproc_allocate_id(rproc,
 | 
			
		||||
						  notifyid,
 | 
			
		||||
						  notifyid + 1);
 | 
			
		||||
		if (notifyid != RSC_NOTIFY_ID_ANY) {
 | 
			
		||||
			vdev_rsc->notifyid = notifyid;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * handle_trace_rsc
 | 
			
		||||
 *
 | 
			
		||||
 * trace resource handler.
 | 
			
		||||
 *
 | 
			
		||||
 * @param rproc - pointer to remote remoteproc
 | 
			
		||||
 * @param rsc   - pointer to trace resource
 | 
			
		||||
 *
 | 
			
		||||
 * @returns - no service error
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
int handle_trace_rsc(struct remoteproc *rproc, void *rsc)
 | 
			
		||||
{
 | 
			
		||||
	struct fw_rsc_trace *vdev_rsc = (struct fw_rsc_trace *)rsc;
 | 
			
		||||
	(void)rproc;
 | 
			
		||||
 | 
			
		||||
	if (vdev_rsc->da != FW_RSC_U32_ADDR_ANY && vdev_rsc->len != 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
	/* FIXME: master should allocated a memory used by slave */
 | 
			
		||||
 | 
			
		||||
	return -RPROC_ERR_RSC_TAB_NS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * handle_dummy_rsc
 | 
			
		||||
 *
 | 
			
		||||
 * dummy resource handler.
 | 
			
		||||
 *
 | 
			
		||||
 * @param rproc - pointer to remote remoteproc
 | 
			
		||||
 * @param rsc   - pointer to trace resource
 | 
			
		||||
 *
 | 
			
		||||
 * @returns - no service error
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc)
 | 
			
		||||
{
 | 
			
		||||
	(void)rproc;
 | 
			
		||||
	(void)rsc;
 | 
			
		||||
 | 
			
		||||
	return -RPROC_ERR_RSC_TAB_NS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index)
 | 
			
		||||
{
 | 
			
		||||
	struct resource_table *r_table = rsc_table;
 | 
			
		||||
	unsigned int i, rsc_index;
 | 
			
		||||
	unsigned int lrsc_type;
 | 
			
		||||
	char *rsc_start;
 | 
			
		||||
 | 
			
		||||
	metal_assert(r_table);
 | 
			
		||||
	/* Loop through the offset array and parse each resource entry */
 | 
			
		||||
	rsc_index = 0;
 | 
			
		||||
	for (i = 0; i < r_table->num; i++) {
 | 
			
		||||
		rsc_start = (char *)r_table;
 | 
			
		||||
		rsc_start += r_table->offset[i];
 | 
			
		||||
		lrsc_type = *((uint32_t *)rsc_start);
 | 
			
		||||
		if (lrsc_type == rsc_type) {
 | 
			
		||||
			if (rsc_index++ == index)
 | 
			
		||||
				return r_table->offset[i];
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
SRC_DIR := 
 | 
			
		||||
 | 
			
		||||
SRC_FILES := $(wildcard *.c)
 | 
			
		||||
 | 
			
		||||
include $(KERNEL_ROOT)/compiler.mk
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,271 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2014, Mentor Graphics Corporation
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2018 Linaro, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <openamp/rpmsg.h>
 | 
			
		||||
#include <metal/alloc.h>
 | 
			
		||||
#include <metal/utilities.h>
 | 
			
		||||
 | 
			
		||||
#include "rpmsg_internal.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_get_address
 | 
			
		||||
 *
 | 
			
		||||
 * This function provides unique 32 bit address.
 | 
			
		||||
 *
 | 
			
		||||
 * @param bitmap - bit map for addresses
 | 
			
		||||
 * @param size   - size of bitmap
 | 
			
		||||
 *
 | 
			
		||||
 * return - a unique address
 | 
			
		||||
 */
 | 
			
		||||
static uint32_t rpmsg_get_address(unsigned long *bitmap, int size)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int addr = RPMSG_ADDR_ANY;
 | 
			
		||||
	unsigned int nextbit;
 | 
			
		||||
 | 
			
		||||
	nextbit = metal_bitmap_next_clear_bit(bitmap, 0, size);
 | 
			
		||||
	if (nextbit < (uint32_t)size) {
 | 
			
		||||
		addr = nextbit;
 | 
			
		||||
		metal_bitmap_set_bit(bitmap, nextbit);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return addr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_release_address
 | 
			
		||||
 *
 | 
			
		||||
 * Frees the given address.
 | 
			
		||||
 *
 | 
			
		||||
 * @param bitmap - bit map for addresses
 | 
			
		||||
 * @param size   - size of bitmap
 | 
			
		||||
 * @param addr   - address to free
 | 
			
		||||
 */
 | 
			
		||||
static void rpmsg_release_address(unsigned long *bitmap, int size,
 | 
			
		||||
				  int addr)
 | 
			
		||||
{
 | 
			
		||||
	if (addr < size)
 | 
			
		||||
		metal_bitmap_clear_bit(bitmap, addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_is_address_set
 | 
			
		||||
 *
 | 
			
		||||
 * Checks whether address is used or free.
 | 
			
		||||
 *
 | 
			
		||||
 * @param bitmap - bit map for addresses
 | 
			
		||||
 * @param size   - size of bitmap
 | 
			
		||||
 * @param addr   - address to free
 | 
			
		||||
 *
 | 
			
		||||
 * return - TRUE/FALSE
 | 
			
		||||
 */
 | 
			
		||||
static int rpmsg_is_address_set(unsigned long *bitmap, int size, int addr)
 | 
			
		||||
{
 | 
			
		||||
	if (addr < size)
 | 
			
		||||
		return metal_bitmap_is_bit_set(bitmap, addr);
 | 
			
		||||
	else
 | 
			
		||||
		return RPMSG_ERR_PARAM;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_set_address
 | 
			
		||||
 *
 | 
			
		||||
 * Marks the address as consumed.
 | 
			
		||||
 *
 | 
			
		||||
 * @param bitmap - bit map for addresses
 | 
			
		||||
 * @param size   - size of bitmap
 | 
			
		||||
 * @param addr   - address to free
 | 
			
		||||
 *
 | 
			
		||||
 * return - none
 | 
			
		||||
 */
 | 
			
		||||
static int rpmsg_set_address(unsigned long *bitmap, int size, int addr)
 | 
			
		||||
{
 | 
			
		||||
	if (addr < size) {
 | 
			
		||||
		metal_bitmap_set_bit(bitmap, addr);
 | 
			
		||||
		return RPMSG_SUCCESS;
 | 
			
		||||
	} else {
 | 
			
		||||
		return RPMSG_ERR_PARAM;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This function sends rpmsg "message" to remote device.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ept     - pointer to end point
 | 
			
		||||
 * @param src     - source address of channel
 | 
			
		||||
 * @param dst     - destination address of channel
 | 
			
		||||
 * @param data    - data to transmit
 | 
			
		||||
 * @param size    - size of data
 | 
			
		||||
 * @param wait    - boolean, wait or not for buffer to become
 | 
			
		||||
 *                  available
 | 
			
		||||
 *
 | 
			
		||||
 * @return - size of data sent or negative value for failure.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src,
 | 
			
		||||
			      uint32_t dst, const void *data, int size,
 | 
			
		||||
			      int wait)
 | 
			
		||||
{
 | 
			
		||||
	struct rpmsg_device *rdev;
 | 
			
		||||
 | 
			
		||||
	if (!ept || !ept->rdev || !data || dst == RPMSG_ADDR_ANY)
 | 
			
		||||
		return RPMSG_ERR_PARAM;
 | 
			
		||||
 | 
			
		||||
	rdev = ept->rdev;
 | 
			
		||||
 | 
			
		||||
	if (rdev->ops.send_offchannel_raw)
 | 
			
		||||
		return rdev->ops.send_offchannel_raw(rdev, src, dst, data,
 | 
			
		||||
						      size, wait);
 | 
			
		||||
 | 
			
		||||
	return RPMSG_ERR_PARAM;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags)
 | 
			
		||||
{
 | 
			
		||||
	struct rpmsg_ns_msg ns_msg;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ns_msg.flags = flags;
 | 
			
		||||
	ns_msg.addr = ept->addr;
 | 
			
		||||
	strncpy(ns_msg.name, ept->name, sizeof(ns_msg.name));
 | 
			
		||||
	ret = rpmsg_send_offchannel_raw(ept, ept->addr,
 | 
			
		||||
					RPMSG_NS_EPT_ADDR,
 | 
			
		||||
					&ns_msg, sizeof(ns_msg), true);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
	else
 | 
			
		||||
		return RPMSG_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rdev,
 | 
			
		||||
					  const char *name, uint32_t addr,
 | 
			
		||||
					  uint32_t dest_addr)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_list *node;
 | 
			
		||||
	struct rpmsg_endpoint *ept;
 | 
			
		||||
 | 
			
		||||
	metal_list_for_each(&rdev->endpoints, node) {
 | 
			
		||||
		int name_match = 0;
 | 
			
		||||
 | 
			
		||||
		ept = metal_container_of(node, struct rpmsg_endpoint, node);
 | 
			
		||||
		/* try to get by local address only */
 | 
			
		||||
		if (addr != RPMSG_ADDR_ANY && ept->addr == addr)
 | 
			
		||||
			return ept;
 | 
			
		||||
		/* try to find match on local end remote address */
 | 
			
		||||
		if (addr == ept->addr && dest_addr == ept->dest_addr)
 | 
			
		||||
			return ept;
 | 
			
		||||
		/* else use name service and destination address */
 | 
			
		||||
		if (name)
 | 
			
		||||
			name_match = !strncmp(ept->name, name,
 | 
			
		||||
					      sizeof(ept->name));
 | 
			
		||||
		if (!name || !name_match)
 | 
			
		||||
			continue;
 | 
			
		||||
		/* destination address is known, equal to ept remote address*/
 | 
			
		||||
		if (dest_addr != RPMSG_ADDR_ANY && ept->dest_addr == dest_addr)
 | 
			
		||||
			return ept;
 | 
			
		||||
		/* ept is registered but not associated to remote ept*/
 | 
			
		||||
		if (addr == RPMSG_ADDR_ANY && ept->dest_addr == RPMSG_ADDR_ANY)
 | 
			
		||||
			return ept;
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rpmsg_unregister_endpoint(struct rpmsg_endpoint *ept)
 | 
			
		||||
{
 | 
			
		||||
	struct rpmsg_device *rdev;
 | 
			
		||||
 | 
			
		||||
	if (!ept)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	rdev = ept->rdev;
 | 
			
		||||
 | 
			
		||||
	if (ept->addr != RPMSG_ADDR_ANY)
 | 
			
		||||
		rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE,
 | 
			
		||||
				      ept->addr);
 | 
			
		||||
	metal_list_del(&ept->node);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rpmsg_register_endpoint(struct rpmsg_device *rdev,
 | 
			
		||||
			    struct rpmsg_endpoint *ept)
 | 
			
		||||
{
 | 
			
		||||
	ept->rdev = rdev;
 | 
			
		||||
 | 
			
		||||
	metal_list_add_tail(&rdev->endpoints, &ept->node);
 | 
			
		||||
	return RPMSG_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev,
 | 
			
		||||
		     const char *name, uint32_t src, uint32_t dest,
 | 
			
		||||
		     rpmsg_ept_cb cb, rpmsg_ns_unbind_cb unbind_cb)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
	uint32_t addr = src;
 | 
			
		||||
 | 
			
		||||
	if (!ept)
 | 
			
		||||
		return RPMSG_ERR_PARAM;
 | 
			
		||||
 | 
			
		||||
	metal_mutex_acquire(&rdev->lock);
 | 
			
		||||
	if (src != RPMSG_ADDR_ANY) {
 | 
			
		||||
		status = rpmsg_is_address_set(rdev->bitmap,
 | 
			
		||||
					      RPMSG_ADDR_BMP_SIZE, src);
 | 
			
		||||
		if (!status) {
 | 
			
		||||
			/* Mark the address as used in the address bitmap. */
 | 
			
		||||
			rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE,
 | 
			
		||||
					  src);
 | 
			
		||||
		} else if (status > 0) {
 | 
			
		||||
			status = RPMSG_SUCCESS;
 | 
			
		||||
			goto ret_status;
 | 
			
		||||
		} else {
 | 
			
		||||
			goto ret_status;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rpmsg_init_ept(ept, name, addr, dest, cb, unbind_cb);
 | 
			
		||||
 | 
			
		||||
	status = rpmsg_register_endpoint(rdev, ept);
 | 
			
		||||
	if (status < 0)
 | 
			
		||||
		rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr);
 | 
			
		||||
 | 
			
		||||
	if (!status  && ept->dest_addr == RPMSG_ADDR_ANY) {
 | 
			
		||||
		/* Send NS announcement to remote processor */
 | 
			
		||||
		metal_mutex_release(&rdev->lock);
 | 
			
		||||
		status = rpmsg_send_ns_message(ept, RPMSG_NS_CREATE);
 | 
			
		||||
		metal_mutex_acquire(&rdev->lock);
 | 
			
		||||
		if (status)
 | 
			
		||||
			rpmsg_unregister_endpoint(ept);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
ret_status:
 | 
			
		||||
	metal_mutex_release(&rdev->lock);
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_destroy_ept
 | 
			
		||||
 *
 | 
			
		||||
 * This function deletes rpmsg endpoint and performs cleanup.
 | 
			
		||||
 *
 | 
			
		||||
 * @param ept - pointer to endpoint to destroy
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
 | 
			
		||||
{
 | 
			
		||||
	struct rpmsg_device *rdev;
 | 
			
		||||
 | 
			
		||||
	if (!ept)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	rdev = ept->rdev;
 | 
			
		||||
	if (ept->addr != RPMSG_NS_EPT_ADDR)
 | 
			
		||||
		(void)rpmsg_send_ns_message(ept, RPMSG_NS_DESTROY);
 | 
			
		||||
	metal_mutex_acquire(&rdev->lock);
 | 
			
		||||
	rpmsg_unregister_endpoint(ept);
 | 
			
		||||
	metal_mutex_release(&rdev->lock);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,105 @@
 | 
			
		|||
/*
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 *
 | 
			
		||||
 * $FreeBSD$
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _RPMSG_INTERNAL_H_
 | 
			
		||||
#define _RPMSG_INTERNAL_H_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <openamp/rpmsg.h>
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef RPMSG_DEBUG
 | 
			
		||||
#define RPMSG_ASSERT(_exp, _msg) do { \
 | 
			
		||||
		if (!(_exp)) { \
 | 
			
		||||
			openamp_print("FATAL: %s - _msg", __func__); \
 | 
			
		||||
			while (1) { \
 | 
			
		||||
				; \
 | 
			
		||||
			} \
 | 
			
		||||
		} \
 | 
			
		||||
	} while (0)
 | 
			
		||||
#else
 | 
			
		||||
#define RPMSG_ASSERT(_exp, _msg) do { \
 | 
			
		||||
		if (!(_exp)) \
 | 
			
		||||
			while (1) { \
 | 
			
		||||
				; \
 | 
			
		||||
			} \
 | 
			
		||||
	} while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define RPMSG_LOCATE_DATA(p) ((unsigned char *)(p) + sizeof(struct rpmsg_hdr))
 | 
			
		||||
/**
 | 
			
		||||
 * enum rpmsg_ns_flags - dynamic name service announcement flags
 | 
			
		||||
 *
 | 
			
		||||
 * @RPMSG_NS_CREATE: a new remote service was just created
 | 
			
		||||
 * @RPMSG_NS_DESTROY: a known remote service was just destroyed
 | 
			
		||||
 * @RPMSG_NS_CREATE_WITH_ACK: a new remote service was just created waiting
 | 
			
		||||
 *                            acknowledgment.
 | 
			
		||||
 */
 | 
			
		||||
enum rpmsg_ns_flags {
 | 
			
		||||
	RPMSG_NS_CREATE = 0,
 | 
			
		||||
	RPMSG_NS_DESTROY = 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct rpmsg_hdr - common header for all rpmsg messages
 | 
			
		||||
 * @src: source address
 | 
			
		||||
 * @dst: destination address
 | 
			
		||||
 * @reserved: reserved for future use
 | 
			
		||||
 * @len: length of payload (in bytes)
 | 
			
		||||
 * @flags: message flags
 | 
			
		||||
 *
 | 
			
		||||
 * Every message sent(/received) on the rpmsg bus begins with this header.
 | 
			
		||||
 */
 | 
			
		||||
OPENAMP_PACKED_BEGIN
 | 
			
		||||
struct rpmsg_hdr {
 | 
			
		||||
	uint32_t src;
 | 
			
		||||
	uint32_t dst;
 | 
			
		||||
	uint32_t reserved;
 | 
			
		||||
	uint16_t len;
 | 
			
		||||
	uint16_t flags;
 | 
			
		||||
} OPENAMP_PACKED_END;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct rpmsg_ns_msg - dynamic name service announcement message
 | 
			
		||||
 * @name: name of remote service that is published
 | 
			
		||||
 * @addr: address of remote service that is published
 | 
			
		||||
 * @flags: indicates whether service is created or destroyed
 | 
			
		||||
 *
 | 
			
		||||
 * This message is sent across to publish a new service, or announce
 | 
			
		||||
 * about its removal. When we receive these messages, an appropriate
 | 
			
		||||
 * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe()
 | 
			
		||||
 * or ->remove() handler of the appropriate rpmsg driver will be invoked
 | 
			
		||||
 * (if/as-soon-as one is registered).
 | 
			
		||||
 */
 | 
			
		||||
OPENAMP_PACKED_BEGIN
 | 
			
		||||
struct rpmsg_ns_msg {
 | 
			
		||||
	char name[RPMSG_NAME_SIZE];
 | 
			
		||||
	uint32_t addr;
 | 
			
		||||
	uint32_t flags;
 | 
			
		||||
} OPENAMP_PACKED_END;
 | 
			
		||||
 | 
			
		||||
int rpmsg_send_ns_message(struct rpmsg_endpoint *ept, unsigned long flags);
 | 
			
		||||
 | 
			
		||||
struct rpmsg_endpoint *rpmsg_get_endpoint(struct rpmsg_device *rvdev,
 | 
			
		||||
					  const char *name, uint32_t addr,
 | 
			
		||||
					  uint32_t dest_addr);
 | 
			
		||||
int rpmsg_register_endpoint(struct rpmsg_device *rdev,
 | 
			
		||||
			    struct rpmsg_endpoint *ept);
 | 
			
		||||
 | 
			
		||||
static inline struct rpmsg_endpoint *
 | 
			
		||||
rpmsg_get_ept_from_addr(struct rpmsg_device *rdev, uint32_t addr)
 | 
			
		||||
{
 | 
			
		||||
	return rpmsg_get_endpoint(rdev, NULL, addr, RPMSG_ADDR_ANY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* _RPMSG_INTERNAL_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,681 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (c) 2014, Mentor Graphics Corporation
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
 | 
			
		||||
 * Copyright (c) 2018 Linaro, Inc. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <metal/alloc.h>
 | 
			
		||||
#include <metal/cache.h>
 | 
			
		||||
#include <metal/sleep.h>
 | 
			
		||||
#include <metal/utilities.h>
 | 
			
		||||
#include <openamp/rpmsg_virtio.h>
 | 
			
		||||
#include <openamp/virtqueue.h>
 | 
			
		||||
 | 
			
		||||
#include "rpmsg_internal.h"
 | 
			
		||||
 | 
			
		||||
#include <xizi.h>
 | 
			
		||||
 | 
			
		||||
#define RPMSG_NUM_VRINGS (2)
 | 
			
		||||
 | 
			
		||||
/* Total tick count for 15secs - 1msec tick. */
 | 
			
		||||
#define RPMSG_TICK_COUNT                        15000
 | 
			
		||||
 | 
			
		||||
/* Time to wait - In multiple of 10 msecs. */
 | 
			
		||||
#define RPMSG_TICKS_PER_INTERVAL                10
 | 
			
		||||
 | 
			
		||||
#define WORD_SIZE	sizeof(unsigned long)
 | 
			
		||||
#define WORD_ALIGN(a)	((((a) & (WORD_SIZE - 1)) != 0) ? \
 | 
			
		||||
			(((a) & (~(WORD_SIZE - 1))) + WORD_SIZE) : (a))
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
metal_weak void *
 | 
			
		||||
rpmsg_virtio_shm_pool_get_buffer(struct rpmsg_virtio_shm_pool *shpool,
 | 
			
		||||
				 size_t size)
 | 
			
		||||
{
 | 
			
		||||
	void *buffer;
 | 
			
		||||
 | 
			
		||||
	if (shpool->avail < size)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	buffer =  (void *)((char *)shpool->base + shpool->size - shpool->avail);
 | 
			
		||||
	shpool->avail -= size;
 | 
			
		||||
 | 
			
		||||
	return buffer;
 | 
			
		||||
}
 | 
			
		||||
#endif /*!VIRTIO_SLAVE_ONLY*/
 | 
			
		||||
 | 
			
		||||
void rpmsg_virtio_init_shm_pool(struct rpmsg_virtio_shm_pool *shpool,
 | 
			
		||||
				void *shb, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	if (!shpool)
 | 
			
		||||
		return;
 | 
			
		||||
	shpool->base = shb;
 | 
			
		||||
	shpool->size = WORD_ALIGN(size);
 | 
			
		||||
	shpool->avail = WORD_ALIGN(size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_virtio_return_buffer
 | 
			
		||||
 *
 | 
			
		||||
 * Places the used buffer back on the virtqueue.
 | 
			
		||||
 *
 | 
			
		||||
 * @param rvdev  - pointer to remote core
 | 
			
		||||
 * @param buffer - buffer pointer
 | 
			
		||||
 * @param len    - buffer length
 | 
			
		||||
 * @param idx    - buffer index
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static void rpmsg_virtio_return_buffer(struct rpmsg_virtio_device *rvdev,
 | 
			
		||||
				       void *buffer, unsigned long len,
 | 
			
		||||
				       unsigned short idx)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int role = rpmsg_virtio_get_role(rvdev);
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
	if (role == RPMSG_MASTER) {
 | 
			
		||||
		struct virtqueue_buf vqbuf;
 | 
			
		||||
 | 
			
		||||
		(void)idx;
 | 
			
		||||
		/* Initialize buffer node */
 | 
			
		||||
		vqbuf.buf = buffer;
 | 
			
		||||
		vqbuf.len = len;
 | 
			
		||||
		virtqueue_add_buffer(rvdev->rvq, &vqbuf, 0, 1, buffer);
 | 
			
		||||
	}
 | 
			
		||||
#endif /*VIRTIO_SLAVE_ONLY*/
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_MASTER_ONLY
 | 
			
		||||
	if (role == RPMSG_REMOTE) {
 | 
			
		||||
		(void)buffer;
 | 
			
		||||
		virtqueue_add_consumed_buffer(rvdev->rvq, idx, len);
 | 
			
		||||
	}
 | 
			
		||||
#endif /*VIRTIO_MASTER_ONLY*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_virtio_enqueue_buffer
 | 
			
		||||
 *
 | 
			
		||||
 * Places buffer on the virtqueue for consumption by the other side.
 | 
			
		||||
 *
 | 
			
		||||
 * @param rvdev  - pointer to rpmsg virtio
 | 
			
		||||
 * @param buffer - buffer pointer
 | 
			
		||||
 * @param len    - buffer length
 | 
			
		||||
 * @param idx    - buffer index
 | 
			
		||||
 *
 | 
			
		||||
 * @return - status of function execution
 | 
			
		||||
 */
 | 
			
		||||
static int rpmsg_virtio_enqueue_buffer(struct rpmsg_virtio_device *rvdev,
 | 
			
		||||
				       void *buffer, unsigned long len,
 | 
			
		||||
				       unsigned short idx)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int role = rpmsg_virtio_get_role(rvdev);
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
	if (role == RPMSG_MASTER) {
 | 
			
		||||
		struct virtqueue_buf vqbuf;
 | 
			
		||||
		(void)idx;
 | 
			
		||||
 | 
			
		||||
		/* Initialize buffer node */
 | 
			
		||||
		vqbuf.buf = buffer;
 | 
			
		||||
		vqbuf.len = len;
 | 
			
		||||
		return virtqueue_add_buffer(rvdev->svq, &vqbuf, 0, 1, buffer);
 | 
			
		||||
	}
 | 
			
		||||
#endif /*!VIRTIO_SLAVE_ONLY*/
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_MASTER_ONLY
 | 
			
		||||
	if (role == RPMSG_REMOTE) {
 | 
			
		||||
		(void)buffer;
 | 
			
		||||
		return virtqueue_add_consumed_buffer(rvdev->svq, idx, len);
 | 
			
		||||
	}
 | 
			
		||||
#endif /*!VIRTIO_MASTER_ONLY*/
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_virtio_get_tx_buffer
 | 
			
		||||
 *
 | 
			
		||||
 * Provides buffer to transmit messages.
 | 
			
		||||
 *
 | 
			
		||||
 * @param rvdev - pointer to rpmsg device
 | 
			
		||||
 * @param len  - length of returned buffer
 | 
			
		||||
 * @param idx  - buffer index
 | 
			
		||||
 *
 | 
			
		||||
 * return - pointer to buffer.
 | 
			
		||||
 */
 | 
			
		||||
static void *rpmsg_virtio_get_tx_buffer(struct rpmsg_virtio_device *rvdev,
 | 
			
		||||
					unsigned long *len,
 | 
			
		||||
					unsigned short *idx)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int role = rpmsg_virtio_get_role(rvdev);
 | 
			
		||||
	void *data = NULL;
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
	if (role == RPMSG_MASTER) {
 | 
			
		||||
		data = virtqueue_get_buffer(rvdev->svq, (uint32_t *)len, idx);
 | 
			
		||||
		if (!data && rvdev->svq->vq_free_cnt) {
 | 
			
		||||
			data = rpmsg_virtio_shm_pool_get_buffer(rvdev->shpool,
 | 
			
		||||
							RPMSG_BUFFER_SIZE);
 | 
			
		||||
			*len = RPMSG_BUFFER_SIZE;
 | 
			
		||||
			*idx = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif /*!VIRTIO_SLAVE_ONLY*/
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_MASTER_ONLY
 | 
			
		||||
	if (role == RPMSG_REMOTE) {
 | 
			
		||||
		data = virtqueue_get_available_buffer(rvdev->svq, idx,
 | 
			
		||||
						      (uint32_t *)len);
 | 
			
		||||
	}
 | 
			
		||||
#endif /*!VIRTIO_MASTER_ONLY*/
 | 
			
		||||
 | 
			
		||||
	return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_virtio_get_rx_buffer
 | 
			
		||||
 *
 | 
			
		||||
 * Retrieves the received buffer from the virtqueue.
 | 
			
		||||
 *
 | 
			
		||||
 * @param rvdev - pointer to rpmsg device
 | 
			
		||||
 * @param len  - size of received buffer
 | 
			
		||||
 * @param idx  - index of buffer
 | 
			
		||||
 *
 | 
			
		||||
 * @return - pointer to received buffer
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static void *rpmsg_virtio_get_rx_buffer(struct rpmsg_virtio_device *rvdev,
 | 
			
		||||
					unsigned long *len,
 | 
			
		||||
					unsigned short *idx)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int role = rpmsg_virtio_get_role(rvdev);
 | 
			
		||||
	void *data = NULL;
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
	if (role == RPMSG_MASTER) {
 | 
			
		||||
		data = virtqueue_get_buffer(rvdev->rvq, (uint32_t *)len, idx);
 | 
			
		||||
	}
 | 
			
		||||
#endif /*!VIRTIO_SLAVE_ONLY*/
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_MASTER_ONLY
 | 
			
		||||
	if (role == RPMSG_REMOTE) {
 | 
			
		||||
		data =
 | 
			
		||||
		    virtqueue_get_available_buffer(rvdev->rvq, idx,
 | 
			
		||||
						   (uint32_t *)len);
 | 
			
		||||
	}
 | 
			
		||||
#endif /*!VIRTIO_MASTER_ONLY*/
 | 
			
		||||
 | 
			
		||||
	if (data) {
 | 
			
		||||
		/* FIX ME: library should not worry about if it needs
 | 
			
		||||
		 * to flush/invalidate cache, it is shared memory.
 | 
			
		||||
		 * The shared memory should be mapped properly before
 | 
			
		||||
		 * using it.
 | 
			
		||||
		 */
 | 
			
		||||
		metal_cache_invalidate(data, (unsigned int)(*len));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_MASTER_ONLY
 | 
			
		||||
/**
 | 
			
		||||
 * check if the remote is ready to start RPMsg communication
 | 
			
		||||
 */
 | 
			
		||||
static int rpmsg_virtio_wait_remote_ready(struct rpmsg_virtio_device *rvdev)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t status;
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		status = rpmsg_virtio_get_status(rvdev);
 | 
			
		||||
		/* Busy wait until the remote is ready */
 | 
			
		||||
		if (status & VIRTIO_CONFIG_STATUS_NEEDS_RESET) {
 | 
			
		||||
			rpmsg_virtio_set_status(rvdev, 0);
 | 
			
		||||
			/* TODO notify remote processor */
 | 
			
		||||
		} else if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK) {
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		/* TODO: clarify metal_cpu_yield usage*/
 | 
			
		||||
		metal_cpu_yield();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
#endif /*!VIRTIO_MASTER_ONLY*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * _rpmsg_virtio_get_buffer_size
 | 
			
		||||
 *
 | 
			
		||||
 * Returns buffer size available for sending messages.
 | 
			
		||||
 *
 | 
			
		||||
 * @param channel - pointer to rpmsg channel
 | 
			
		||||
 *
 | 
			
		||||
 * @return - buffer size
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static int _rpmsg_virtio_get_buffer_size(struct rpmsg_virtio_device *rvdev)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int role = rpmsg_virtio_get_role(rvdev);
 | 
			
		||||
	int length = 0;
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
	if (role == RPMSG_MASTER) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * If device role is Remote then buffers are provided by us
 | 
			
		||||
		 * (RPMSG Master), so just provide the macro.
 | 
			
		||||
		 */
 | 
			
		||||
		length = RPMSG_BUFFER_SIZE - sizeof(struct rpmsg_hdr);
 | 
			
		||||
	}
 | 
			
		||||
#endif /*!VIRTIO_SLAVE_ONLY*/
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_MASTER_ONLY
 | 
			
		||||
	if (role == RPMSG_REMOTE) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * If other core is Master then buffers are provided by it,
 | 
			
		||||
		 * so get the buffer size from the virtqueue.
 | 
			
		||||
		 */
 | 
			
		||||
		length =
 | 
			
		||||
		    (int)virtqueue_get_desc_size(rvdev->svq) -
 | 
			
		||||
		    sizeof(struct rpmsg_hdr);
 | 
			
		||||
		if (length < 0) {
 | 
			
		||||
		    length = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif /*!VIRTIO_MASTER_ONLY*/
 | 
			
		||||
 | 
			
		||||
	return length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This function sends rpmsg "message" to remote device.
 | 
			
		||||
 *
 | 
			
		||||
 * @param rdev    - pointer to rpmsg device
 | 
			
		||||
 * @param src     - source address of channel
 | 
			
		||||
 * @param dst     - destination address of channel
 | 
			
		||||
 * @param data    - data to transmit
 | 
			
		||||
 * @param size    - size of data
 | 
			
		||||
 * @param wait    - boolean, wait or not for buffer to become
 | 
			
		||||
 *                  available
 | 
			
		||||
 *
 | 
			
		||||
 * @return - size of data sent or negative value for failure.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static int rpmsg_virtio_send_offchannel_raw(struct rpmsg_device *rdev,
 | 
			
		||||
					    uint32_t src, uint32_t dst,
 | 
			
		||||
					    const void *data,
 | 
			
		||||
					    int size, int wait)
 | 
			
		||||
{
 | 
			
		||||
	struct rpmsg_virtio_device *rvdev;
 | 
			
		||||
	struct rpmsg_hdr rp_hdr;
 | 
			
		||||
	void *buffer = NULL;
 | 
			
		||||
	unsigned short idx;
 | 
			
		||||
	int tick_count = 0;
 | 
			
		||||
	unsigned long buff_len;
 | 
			
		||||
	int status;
 | 
			
		||||
	struct metal_io_region *io;
 | 
			
		||||
 | 
			
		||||
	/* Get the associated remote device for channel. */
 | 
			
		||||
	rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev);
 | 
			
		||||
 | 
			
		||||
	status = rpmsg_virtio_get_status(rvdev);
 | 
			
		||||
	/* Validate device state */
 | 
			
		||||
	if (!(status & VIRTIO_CONFIG_STATUS_DRIVER_OK)) {
 | 
			
		||||
		return RPMSG_ERR_DEV_STATE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (wait)
 | 
			
		||||
		tick_count = RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL;
 | 
			
		||||
	else
 | 
			
		||||
		tick_count = 0;
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		int avail_size;
 | 
			
		||||
 | 
			
		||||
		/* Lock the device to enable exclusive access to virtqueues */
 | 
			
		||||
		metal_mutex_acquire(&rdev->lock);
 | 
			
		||||
		avail_size = _rpmsg_virtio_get_buffer_size(rvdev);
 | 
			
		||||
		if (size <= avail_size)
 | 
			
		||||
			buffer = rpmsg_virtio_get_tx_buffer(rvdev, &buff_len,
 | 
			
		||||
							    &idx);
 | 
			
		||||
		metal_mutex_release(&rdev->lock);
 | 
			
		||||
		if (buffer || !tick_count)
 | 
			
		||||
			break;
 | 
			
		||||
		metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL);
 | 
			
		||||
		tick_count--;
 | 
			
		||||
	}
 | 
			
		||||
	if (!buffer)
 | 
			
		||||
		return RPMSG_ERR_NO_BUFF;
 | 
			
		||||
 | 
			
		||||
	/* Initialize RPMSG header. */
 | 
			
		||||
	rp_hdr.dst = dst;
 | 
			
		||||
	rp_hdr.src = src;
 | 
			
		||||
	rp_hdr.len = size;
 | 
			
		||||
	rp_hdr.reserved = 0;
 | 
			
		||||
 | 
			
		||||
	/* Copy data to rpmsg buffer. */
 | 
			
		||||
	io = rvdev->shbuf_io;
 | 
			
		||||
	status = metal_io_block_write(io, metal_io_virt_to_offset(io, buffer),
 | 
			
		||||
				      &rp_hdr, sizeof(rp_hdr));
 | 
			
		||||
	RPMSG_ASSERT(status == sizeof(rp_hdr), "failed to write header\n");
 | 
			
		||||
 | 
			
		||||
	status = metal_io_block_write(io,
 | 
			
		||||
				      metal_io_virt_to_offset(io,
 | 
			
		||||
				      RPMSG_LOCATE_DATA(buffer)),
 | 
			
		||||
				      data, size);
 | 
			
		||||
	RPMSG_ASSERT(status == size, "failed to write buffer\n");
 | 
			
		||||
	metal_mutex_acquire(&rdev->lock);
 | 
			
		||||
 | 
			
		||||
	/* Enqueue buffer on virtqueue. */
 | 
			
		||||
	status = rpmsg_virtio_enqueue_buffer(rvdev, buffer, buff_len, idx);
 | 
			
		||||
	RPMSG_ASSERT(status == VQUEUE_SUCCESS, "failed to enqueue buffer\n");
 | 
			
		||||
	/* Let the other side know that there is a job to process. */
 | 
			
		||||
	virtqueue_kick(rvdev->svq);
 | 
			
		||||
 | 
			
		||||
	metal_mutex_release(&rdev->lock);
 | 
			
		||||
 | 
			
		||||
	return size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_virtio_tx_callback
 | 
			
		||||
 *
 | 
			
		||||
 * Tx callback function.
 | 
			
		||||
 *
 | 
			
		||||
 * @param vq - pointer to virtqueue on which Tx is has been
 | 
			
		||||
 *             completed.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static void rpmsg_virtio_tx_callback(struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	(void)vq;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_virtio_rx_callback
 | 
			
		||||
 *
 | 
			
		||||
 * Rx callback function.
 | 
			
		||||
 *
 | 
			
		||||
 * @param vq - pointer to virtqueue on which messages is received
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static void rpmsg_virtio_rx_callback(struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	struct virtio_device *vdev = vq->vq_dev;
 | 
			
		||||
	struct rpmsg_virtio_device *rvdev = vdev->priv;
 | 
			
		||||
	struct rpmsg_device *rdev = &rvdev->rdev;
 | 
			
		||||
	struct rpmsg_endpoint *ept;
 | 
			
		||||
	struct rpmsg_hdr *rp_hdr;
 | 
			
		||||
	unsigned long len;
 | 
			
		||||
	unsigned short idx;
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
	metal_mutex_acquire(&rdev->lock);
 | 
			
		||||
 | 
			
		||||
	/* Process the received data from remote node */
 | 
			
		||||
	rp_hdr = (struct rpmsg_hdr *)rpmsg_virtio_get_rx_buffer(rvdev,
 | 
			
		||||
								&len, &idx);
 | 
			
		||||
 | 
			
		||||
	metal_mutex_release(&rdev->lock);
 | 
			
		||||
 | 
			
		||||
	while (rp_hdr) {
 | 
			
		||||
		/* Get the channel node from the remote device channels list. */
 | 
			
		||||
		metal_mutex_acquire(&rdev->lock);
 | 
			
		||||
		ept = rpmsg_get_ept_from_addr(rdev, rp_hdr->dst);
 | 
			
		||||
		metal_mutex_release(&rdev->lock);
 | 
			
		||||
 | 
			
		||||
		if (!ept)
 | 
			
		||||
			/* Fatal error no endpoint for the given dst addr. */
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if (ept->dest_addr == RPMSG_ADDR_ANY) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * First message received from the remote side,
 | 
			
		||||
			 * update channel destination address
 | 
			
		||||
			 */
 | 
			
		||||
			ept->dest_addr = rp_hdr->src;
 | 
			
		||||
		}
 | 
			
		||||
		status = ept->cb(ept, (void *)RPMSG_LOCATE_DATA(rp_hdr),
 | 
			
		||||
				   rp_hdr->len, ept->addr, ept->priv);
 | 
			
		||||
 | 
			
		||||
		RPMSG_ASSERT(status == RPMSG_SUCCESS,
 | 
			
		||||
			     "unexpected callback status\n");
 | 
			
		||||
		metal_mutex_acquire(&rdev->lock);
 | 
			
		||||
 | 
			
		||||
		/* Return used buffers. */
 | 
			
		||||
		rpmsg_virtio_return_buffer(rvdev, rp_hdr, len, idx);
 | 
			
		||||
 | 
			
		||||
		rp_hdr = (struct rpmsg_hdr *)
 | 
			
		||||
			 rpmsg_virtio_get_rx_buffer(rvdev, &len, &idx);
 | 
			
		||||
		metal_mutex_release(&rdev->lock);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * rpmsg_virtio_ns_callback
 | 
			
		||||
 *
 | 
			
		||||
 * This callback handles name service announcement from the remote device
 | 
			
		||||
 * and creates/deletes rpmsg channels.
 | 
			
		||||
 *
 | 
			
		||||
 * @param server_chnl - pointer to server channel control block.
 | 
			
		||||
 * @param data        - pointer to received messages
 | 
			
		||||
 * @param len         - length of received data
 | 
			
		||||
 * @param priv        - any private data
 | 
			
		||||
 * @param src         - source address
 | 
			
		||||
 *
 | 
			
		||||
 * @return - rpmag endpoint callback handled
 | 
			
		||||
 */
 | 
			
		||||
static int rpmsg_virtio_ns_callback(struct rpmsg_endpoint *ept, void *data,
 | 
			
		||||
				    size_t len, uint32_t src, void *priv)
 | 
			
		||||
{
 | 
			
		||||
	struct rpmsg_device *rdev = ept->rdev;
 | 
			
		||||
	struct rpmsg_virtio_device *rvdev = (struct rpmsg_virtio_device *)rdev;
 | 
			
		||||
	struct metal_io_region *io = rvdev->shbuf_io;
 | 
			
		||||
	struct rpmsg_endpoint *_ept;
 | 
			
		||||
	struct rpmsg_ns_msg *ns_msg;
 | 
			
		||||
	uint32_t dest;
 | 
			
		||||
	char name[RPMSG_NAME_SIZE];
 | 
			
		||||
 | 
			
		||||
	(void)priv;
 | 
			
		||||
	(void)src;
 | 
			
		||||
 | 
			
		||||
	ns_msg = (struct rpmsg_ns_msg *)data;
 | 
			
		||||
	if (len != sizeof(*ns_msg))
 | 
			
		||||
		/* Returns as the message is corrupted */
 | 
			
		||||
		return RPMSG_SUCCESS;
 | 
			
		||||
	metal_io_block_read(io,
 | 
			
		||||
			    metal_io_virt_to_offset(io, ns_msg->name),
 | 
			
		||||
			    &name, sizeof(name));
 | 
			
		||||
	dest = ns_msg->addr;
 | 
			
		||||
 | 
			
		||||
	/* check if a Ept has been locally registered */
 | 
			
		||||
	metal_mutex_acquire(&rdev->lock);
 | 
			
		||||
	_ept = rpmsg_get_endpoint(rdev, name, RPMSG_ADDR_ANY, dest);
 | 
			
		||||
 | 
			
		||||
	if (ns_msg->flags & RPMSG_NS_DESTROY) {
 | 
			
		||||
		if (_ept)
 | 
			
		||||
			_ept->dest_addr = RPMSG_ADDR_ANY;
 | 
			
		||||
		metal_mutex_release(&rdev->lock);
 | 
			
		||||
		if (_ept && _ept->ns_unbind_cb)
 | 
			
		||||
			_ept->ns_unbind_cb(ept);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (!_ept) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * send callback to application, that can
 | 
			
		||||
			 * - create the associated endpoints.
 | 
			
		||||
			 * - store information for future use.
 | 
			
		||||
			 * - just ignore the request as service not supported.
 | 
			
		||||
			 */
 | 
			
		||||
			metal_mutex_release(&rdev->lock);
 | 
			
		||||
			if (rdev->ns_bind_cb)
 | 
			
		||||
				rdev->ns_bind_cb(rdev, name, dest);
 | 
			
		||||
		} else {
 | 
			
		||||
			_ept->dest_addr = dest;
 | 
			
		||||
			metal_mutex_release(&rdev->lock);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return RPMSG_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev)
 | 
			
		||||
{
 | 
			
		||||
	int size;
 | 
			
		||||
	struct rpmsg_virtio_device *rvdev;
 | 
			
		||||
 | 
			
		||||
	if (!rdev)
 | 
			
		||||
		return RPMSG_ERR_PARAM;
 | 
			
		||||
	metal_mutex_acquire(&rdev->lock);
 | 
			
		||||
	rvdev = (struct rpmsg_virtio_device *)rdev;
 | 
			
		||||
	size = _rpmsg_virtio_get_buffer_size(rvdev);
 | 
			
		||||
	metal_mutex_release(&rdev->lock);
 | 
			
		||||
	return size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev,
 | 
			
		||||
		    struct virtio_device *vdev,
 | 
			
		||||
		    rpmsg_ns_bind_cb ns_bind_cb,
 | 
			
		||||
		    struct metal_io_region *shm_io,
 | 
			
		||||
		    struct rpmsg_virtio_shm_pool *shpool)
 | 
			
		||||
{
 | 
			
		||||
	struct rpmsg_device *rdev;
 | 
			
		||||
	const char *vq_names[RPMSG_NUM_VRINGS];
 | 
			
		||||
	typedef void (*vqcallback)(struct virtqueue *vq);
 | 
			
		||||
	vqcallback callback[RPMSG_NUM_VRINGS];
 | 
			
		||||
	unsigned long dev_features;
 | 
			
		||||
	int status;
 | 
			
		||||
	unsigned int i, role;
 | 
			
		||||
 | 
			
		||||
	rdev = &rvdev->rdev;
 | 
			
		||||
	memset(rdev, 0, sizeof(*rdev));
 | 
			
		||||
	metal_mutex_init(&rdev->lock);
 | 
			
		||||
	rvdev->vdev = vdev;
 | 
			
		||||
	rdev->ns_bind_cb = ns_bind_cb;
 | 
			
		||||
	vdev->priv = rvdev;
 | 
			
		||||
	rdev->ops.send_offchannel_raw = rpmsg_virtio_send_offchannel_raw;
 | 
			
		||||
	role = rpmsg_virtio_get_role(rvdev);
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
	if (role == RPMSG_MASTER) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Since device is RPMSG Remote so we need to manage the
 | 
			
		||||
		 * shared buffers. Create shared memory pool to handle buffers.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!shpool)
 | 
			
		||||
			return RPMSG_ERR_PARAM;
 | 
			
		||||
		if (!shpool->size)
 | 
			
		||||
			return RPMSG_ERR_NO_BUFF;
 | 
			
		||||
		rvdev->shpool = shpool;
 | 
			
		||||
 | 
			
		||||
		vq_names[0] = "rx_vq";
 | 
			
		||||
		vq_names[1] = "tx_vq";
 | 
			
		||||
		callback[0] = rpmsg_virtio_rx_callback;
 | 
			
		||||
		callback[1] = rpmsg_virtio_tx_callback;
 | 
			
		||||
		rvdev->rvq  = vdev->vrings_info[0].vq;
 | 
			
		||||
		rvdev->svq  = vdev->vrings_info[1].vq;
 | 
			
		||||
	}
 | 
			
		||||
#endif /*!VIRTIO_SLAVE_ONLY*/
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_MASTER_ONLY
 | 
			
		||||
	(void)shpool;
 | 
			
		||||
	if (role == RPMSG_REMOTE) {
 | 
			
		||||
		vq_names[0] = "tx_vq";
 | 
			
		||||
		vq_names[1] = "rx_vq";
 | 
			
		||||
		callback[0] = rpmsg_virtio_tx_callback;
 | 
			
		||||
		callback[1] = rpmsg_virtio_rx_callback;
 | 
			
		||||
		rvdev->rvq  = vdev->vrings_info[1].vq;
 | 
			
		||||
		rvdev->svq  = vdev->vrings_info[0].vq;
 | 
			
		||||
	}
 | 
			
		||||
#endif /*!VIRTIO_MASTER_ONLY*/
 | 
			
		||||
	rvdev->shbuf_io = shm_io;
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_MASTER_ONLY
 | 
			
		||||
	if (role == RPMSG_REMOTE) {
 | 
			
		||||
		/* wait synchro with the master */
 | 
			
		||||
		rpmsg_virtio_wait_remote_ready(rvdev);
 | 
			
		||||
	}
 | 
			
		||||
#endif /*!VIRTIO_MASTER_ONLY*/
 | 
			
		||||
 | 
			
		||||
	/* Create virtqueues for remote device */
 | 
			
		||||
	status = rpmsg_virtio_create_virtqueues(rvdev, 0, RPMSG_NUM_VRINGS,
 | 
			
		||||
						vq_names, callback);
 | 
			
		||||
	if (status != RPMSG_SUCCESS)
 | 
			
		||||
		return status;
 | 
			
		||||
 | 
			
		||||
	/* TODO: can have a virtio function to set the shared memory I/O */
 | 
			
		||||
	for (i = 0; i < RPMSG_NUM_VRINGS; i++) {
 | 
			
		||||
		struct virtqueue *vq;
 | 
			
		||||
 | 
			
		||||
		vq = vdev->vrings_info[i].vq;
 | 
			
		||||
		vq->shm_io = shm_io;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
	if (role == RPMSG_MASTER) {
 | 
			
		||||
		struct virtqueue_buf vqbuf;
 | 
			
		||||
		unsigned int idx;
 | 
			
		||||
		void *buffer;
 | 
			
		||||
 | 
			
		||||
		vqbuf.len = RPMSG_BUFFER_SIZE;
 | 
			
		||||
		for (idx = 0; idx < rvdev->rvq->vq_nentries; idx++) {
 | 
			
		||||
			/* Initialize TX virtqueue buffers for remote device */
 | 
			
		||||
			buffer = rpmsg_virtio_shm_pool_get_buffer(shpool,
 | 
			
		||||
							RPMSG_BUFFER_SIZE);
 | 
			
		||||
 | 
			
		||||
			if (!buffer) {
 | 
			
		||||
				return RPMSG_ERR_NO_BUFF;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			vqbuf.buf = buffer;
 | 
			
		||||
 | 
			
		||||
			metal_io_block_set(shm_io,
 | 
			
		||||
					   metal_io_virt_to_offset(shm_io,
 | 
			
		||||
								   buffer),
 | 
			
		||||
					   0x00, RPMSG_BUFFER_SIZE);
 | 
			
		||||
			status =
 | 
			
		||||
				virtqueue_add_buffer(rvdev->rvq, &vqbuf, 0, 1,
 | 
			
		||||
						     buffer);
 | 
			
		||||
 | 
			
		||||
			if (status != RPMSG_SUCCESS) {
 | 
			
		||||
				return status;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif /*!VIRTIO_SLAVE_ONLY*/
 | 
			
		||||
	/* Initialize channels and endpoints list */
 | 
			
		||||
	metal_list_init(&rdev->endpoints);
 | 
			
		||||
 | 
			
		||||
	dev_features = rpmsg_virtio_get_features(rvdev);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Create name service announcement endpoint if device supports name
 | 
			
		||||
	 * service announcement feature.
 | 
			
		||||
	 */
 | 
			
		||||
	if ((dev_features & (1 << VIRTIO_RPMSG_F_NS))) {
 | 
			
		||||
		rpmsg_init_ept(&rdev->ns_ept, "NS",
 | 
			
		||||
			       RPMSG_NS_EPT_ADDR, RPMSG_NS_EPT_ADDR,
 | 
			
		||||
			       rpmsg_virtio_ns_callback, NULL);
 | 
			
		||||
		(void)rpmsg_register_endpoint(rdev, &rdev->ns_ept);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
	if (role == RPMSG_MASTER)
 | 
			
		||||
		rpmsg_virtio_set_status(rvdev, VIRTIO_CONFIG_STATUS_DRIVER_OK);
 | 
			
		||||
#endif /*!VIRTIO_SLAVE_ONLY*/
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_list *node;
 | 
			
		||||
	struct rpmsg_device *rdev;
 | 
			
		||||
	struct rpmsg_endpoint *ept;
 | 
			
		||||
 | 
			
		||||
	rdev = &rvdev->rdev;
 | 
			
		||||
	while (!metal_list_is_empty(&rdev->endpoints)) {
 | 
			
		||||
		node = rdev->endpoints.next;
 | 
			
		||||
		ept = metal_container_of(node, struct rpmsg_endpoint, node);
 | 
			
		||||
		rpmsg_destroy_ept(ept);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rvdev->rvq = 0;
 | 
			
		||||
	rvdev->svq = 0;
 | 
			
		||||
 | 
			
		||||
	metal_mutex_deinit(&rdev->lock);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
SRC_DIR := 
 | 
			
		||||
 | 
			
		||||
SRC_FILES := $(wildcard *.c)
 | 
			
		||||
 | 
			
		||||
include $(KERNEL_ROOT)/compiler.mk
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,121 @@
 | 
			
		|||
/*-
 | 
			
		||||
 * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-2-Clause
 | 
			
		||||
 */
 | 
			
		||||
#include <openamp/virtio.h>
 | 
			
		||||
 | 
			
		||||
static const char *virtio_feature_name(unsigned long feature,
 | 
			
		||||
				       const struct virtio_feature_desc *);
 | 
			
		||||
 | 
			
		||||
//TODO : This structure may change depending on the types of devices we support.
 | 
			
		||||
static const struct virtio_ident {
 | 
			
		||||
	unsigned short devid;
 | 
			
		||||
	const char *name;
 | 
			
		||||
} virtio_ident_table[] = {
 | 
			
		||||
	{
 | 
			
		||||
	VIRTIO_ID_NETWORK, "Network"}, {
 | 
			
		||||
	VIRTIO_ID_BLOCK, "Block"}, {
 | 
			
		||||
	VIRTIO_ID_CONSOLE, "Console"}, {
 | 
			
		||||
	VIRTIO_ID_ENTROPY, "Entropy"}, {
 | 
			
		||||
	VIRTIO_ID_BALLOON, "Balloon"}, {
 | 
			
		||||
	VIRTIO_ID_IOMEMORY, "IOMemory"}, {
 | 
			
		||||
	VIRTIO_ID_SCSI, "SCSI"}, {
 | 
			
		||||
	VIRTIO_ID_9P, "9P Transport"}, {
 | 
			
		||||
	0, NULL}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Device independent features. */
 | 
			
		||||
static const struct virtio_feature_desc virtio_common_feature_desc[] = {
 | 
			
		||||
	{VIRTIO_F_NOTIFY_ON_EMPTY, "NotifyOnEmpty"},
 | 
			
		||||
	{VIRTIO_RING_F_INDIRECT_DESC, "RingIndirect"},
 | 
			
		||||
	{VIRTIO_RING_F_EVENT_IDX, "EventIdx"},
 | 
			
		||||
	{VIRTIO_F_BAD_FEATURE, "BadFeature"},
 | 
			
		||||
 | 
			
		||||
	{0, NULL}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const char *virtio_dev_name(unsigned short devid)
 | 
			
		||||
{
 | 
			
		||||
	const struct virtio_ident *ident;
 | 
			
		||||
 | 
			
		||||
	for (ident = virtio_ident_table; ident->name != NULL; ident++) {
 | 
			
		||||
		if (ident->devid == devid)
 | 
			
		||||
			return (ident->name);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *virtio_feature_name(unsigned long val,
 | 
			
		||||
				       const struct virtio_feature_desc *desc)
 | 
			
		||||
{
 | 
			
		||||
	int i, j;
 | 
			
		||||
	const struct virtio_feature_desc *descs[2] = { desc,
 | 
			
		||||
		virtio_common_feature_desc
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 2; i++) {
 | 
			
		||||
		if (!descs[i])
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		for (j = 0; descs[i][j].vfd_val != 0; j++) {
 | 
			
		||||
			if (val == descs[i][j].vfd_val)
 | 
			
		||||
				return (descs[i][j].vfd_str);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void virtio_describe(struct virtio_device *dev, const char *msg,
 | 
			
		||||
		     uint32_t features, struct virtio_feature_desc *desc)
 | 
			
		||||
{
 | 
			
		||||
	(void)dev;
 | 
			
		||||
	(void)msg;
 | 
			
		||||
	(void)features;
 | 
			
		||||
 | 
			
		||||
	// TODO: Not used currently - keeping it for future use
 | 
			
		||||
	virtio_feature_name(0, desc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags,
 | 
			
		||||
			     unsigned int nvqs, const char *names[],
 | 
			
		||||
			     vq_callback *callbacks[])
 | 
			
		||||
{
 | 
			
		||||
	struct virtio_vring_info *vring_info;
 | 
			
		||||
	struct vring_alloc_info *vring_alloc;
 | 
			
		||||
	unsigned int num_vrings, i;
 | 
			
		||||
	int ret;
 | 
			
		||||
	(void)flags;
 | 
			
		||||
 | 
			
		||||
	num_vrings = vdev->vrings_num;
 | 
			
		||||
	if (nvqs > num_vrings)
 | 
			
		||||
		return ERROR_VQUEUE_INVLD_PARAM;
 | 
			
		||||
	/* Initialize virtqueue for each vring */
 | 
			
		||||
	for (i = 0; i < nvqs; i++) {
 | 
			
		||||
		vring_info = &vdev->vrings_info[i];
 | 
			
		||||
 | 
			
		||||
		vring_alloc = &vring_info->info;
 | 
			
		||||
#ifndef VIRTIO_SLAVE_ONLY
 | 
			
		||||
		if (vdev->role == VIRTIO_DEV_MASTER) {
 | 
			
		||||
			size_t offset;
 | 
			
		||||
			struct metal_io_region *io = vring_info->io;
 | 
			
		||||
 | 
			
		||||
			offset = metal_io_virt_to_offset(io,
 | 
			
		||||
							 vring_alloc->vaddr);
 | 
			
		||||
			metal_io_block_set(io, offset, 0,
 | 
			
		||||
					   vring_size(vring_alloc->num_descs,
 | 
			
		||||
						      vring_alloc->align));
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
		ret = virtqueue_create(vdev, i, names[i], vring_alloc,
 | 
			
		||||
				       callbacks[i], vdev->func->notify,
 | 
			
		||||
				       vring_info->vq);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,618 @@
 | 
			
		|||
/*-
 | 
			
		||||
 * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-2-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <openamp/virtqueue.h>
 | 
			
		||||
#include <metal/atomic.h>
 | 
			
		||||
#include <metal/log.h>
 | 
			
		||||
#include <metal/alloc.h>
 | 
			
		||||
 | 
			
		||||
/* Prototype for internal functions. */
 | 
			
		||||
static void vq_ring_init(struct virtqueue *, void *, int);
 | 
			
		||||
static void vq_ring_update_avail(struct virtqueue *, uint16_t);
 | 
			
		||||
static uint16_t vq_ring_add_buffer(struct virtqueue *, struct vring_desc *,
 | 
			
		||||
				   uint16_t, struct virtqueue_buf *, int, int);
 | 
			
		||||
static int vq_ring_enable_interrupt(struct virtqueue *, uint16_t);
 | 
			
		||||
static void vq_ring_free_chain(struct virtqueue *, uint16_t);
 | 
			
		||||
static int vq_ring_must_notify_host(struct virtqueue *vq);
 | 
			
		||||
static void vq_ring_notify_host(struct virtqueue *vq);
 | 
			
		||||
static int virtqueue_nused(struct virtqueue *vq);
 | 
			
		||||
 | 
			
		||||
/* Default implementation of P2V based on libmetal */
 | 
			
		||||
static inline void *virtqueue_phys_to_virt(struct virtqueue *vq,
 | 
			
		||||
					   metal_phys_addr_t phys)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_io_region *io = vq->shm_io;
 | 
			
		||||
 | 
			
		||||
	return metal_io_phys_to_virt(io, phys);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Default implementation of V2P based on libmetal */
 | 
			
		||||
static inline metal_phys_addr_t virtqueue_virt_to_phys(struct virtqueue *vq,
 | 
			
		||||
						       void *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct metal_io_region *io = vq->shm_io;
 | 
			
		||||
 | 
			
		||||
	return metal_io_virt_to_phys(io, buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * virtqueue_create - Creates new VirtIO queue
 | 
			
		||||
 *
 | 
			
		||||
 * @param device    - Pointer to VirtIO device
 | 
			
		||||
 * @param id        - VirtIO queue ID , must be unique
 | 
			
		||||
 * @param name      - Name of VirtIO queue
 | 
			
		||||
 * @param ring      - Pointer to vring_alloc_info control block
 | 
			
		||||
 * @param callback  - Pointer to callback function, invoked
 | 
			
		||||
 *                    when message is available on VirtIO queue
 | 
			
		||||
 * @param notify    - Pointer to notify function, used to notify
 | 
			
		||||
 *                    other side that there is job available for it
 | 
			
		||||
 * @param vq        - Created VirtIO queue.
 | 
			
		||||
 *
 | 
			
		||||
 * @return          - Function status
 | 
			
		||||
 */
 | 
			
		||||
int virtqueue_create(struct virtio_device *virt_dev, unsigned short id,
 | 
			
		||||
		     const char *name, struct vring_alloc_info *ring,
 | 
			
		||||
		     void (*callback)(struct virtqueue *vq),
 | 
			
		||||
		     void (*notify)(struct virtqueue *vq),
 | 
			
		||||
		     struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	int status = VQUEUE_SUCCESS;
 | 
			
		||||
 | 
			
		||||
	VQ_PARAM_CHK(ring == NULL, status, ERROR_VQUEUE_INVLD_PARAM);
 | 
			
		||||
	VQ_PARAM_CHK(ring->num_descs == 0, status, ERROR_VQUEUE_INVLD_PARAM);
 | 
			
		||||
	VQ_PARAM_CHK(ring->num_descs & (ring->num_descs - 1), status,
 | 
			
		||||
		     ERROR_VRING_ALIGN);
 | 
			
		||||
	VQ_PARAM_CHK(vq == NULL, status, ERROR_NO_MEM);
 | 
			
		||||
 | 
			
		||||
	if (status == VQUEUE_SUCCESS) {
 | 
			
		||||
		vq->vq_dev = virt_dev;
 | 
			
		||||
		vq->vq_name =  name;
 | 
			
		||||
		vq->vq_queue_index = id;
 | 
			
		||||
		vq->vq_nentries = ring->num_descs;
 | 
			
		||||
		vq->vq_free_cnt = vq->vq_nentries;
 | 
			
		||||
		vq->callback = callback;
 | 
			
		||||
		vq->notify = notify;
 | 
			
		||||
 | 
			
		||||
		/* Initialize vring control block in virtqueue. */
 | 
			
		||||
		vq_ring_init(vq, (void *)ring->vaddr, ring->align);
 | 
			
		||||
 | 
			
		||||
		/* Disable callbacks - will be enabled by the application
 | 
			
		||||
		 * once initialization is completed.
 | 
			
		||||
		 */
 | 
			
		||||
		virtqueue_disable_cb(vq);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * virtqueue_add_buffer()   - Enqueues new buffer in vring for consumption
 | 
			
		||||
 *                            by other side. Readable buffers are always
 | 
			
		||||
 *                            inserted before writable buffers
 | 
			
		||||
 *
 | 
			
		||||
 * @param vq                - Pointer to VirtIO queue control block.
 | 
			
		||||
 * @param buf_list          - Pointer to a list of virtqueue buffers.
 | 
			
		||||
 * @param readable          - Number of readable buffers
 | 
			
		||||
 * @param writable          - Number of writable buffers
 | 
			
		||||
 * @param cookie            - Pointer to hold call back data
 | 
			
		||||
 *
 | 
			
		||||
 * @return                  - Function status
 | 
			
		||||
 */
 | 
			
		||||
int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list,
 | 
			
		||||
			 int readable, int writable, void *cookie)
 | 
			
		||||
{
 | 
			
		||||
	struct vq_desc_extra *dxp = NULL;
 | 
			
		||||
	int status = VQUEUE_SUCCESS;
 | 
			
		||||
	uint16_t head_idx;
 | 
			
		||||
	uint16_t idx;
 | 
			
		||||
	int needed;
 | 
			
		||||
 | 
			
		||||
	needed = readable + writable;
 | 
			
		||||
 | 
			
		||||
	VQ_PARAM_CHK(vq == NULL, status, ERROR_VQUEUE_INVLD_PARAM);
 | 
			
		||||
	VQ_PARAM_CHK(needed < 1, status, ERROR_VQUEUE_INVLD_PARAM);
 | 
			
		||||
	VQ_PARAM_CHK(vq->vq_free_cnt == 0, status, ERROR_VRING_FULL);
 | 
			
		||||
 | 
			
		||||
	VQUEUE_BUSY(vq);
 | 
			
		||||
 | 
			
		||||
	if (status == VQUEUE_SUCCESS) {
 | 
			
		||||
		VQASSERT(vq, cookie != NULL, "enqueuing with no cookie");
 | 
			
		||||
 | 
			
		||||
		head_idx = vq->vq_desc_head_idx;
 | 
			
		||||
		VQ_RING_ASSERT_VALID_IDX(vq, head_idx);
 | 
			
		||||
		dxp = &vq->vq_descx[head_idx];
 | 
			
		||||
 | 
			
		||||
		VQASSERT(vq, dxp->cookie == NULL,
 | 
			
		||||
			 "cookie already exists for index");
 | 
			
		||||
 | 
			
		||||
		dxp->cookie = cookie;
 | 
			
		||||
		dxp->ndescs = needed;
 | 
			
		||||
 | 
			
		||||
		/* Enqueue buffer onto the ring. */
 | 
			
		||||
		idx = vq_ring_add_buffer(vq, vq->vq_ring.desc, head_idx,
 | 
			
		||||
					 buf_list, readable, writable);
 | 
			
		||||
 | 
			
		||||
		vq->vq_desc_head_idx = idx;
 | 
			
		||||
		vq->vq_free_cnt -= needed;
 | 
			
		||||
 | 
			
		||||
		if (vq->vq_free_cnt == 0) {
 | 
			
		||||
			VQ_RING_ASSERT_CHAIN_TERM(vq);
 | 
			
		||||
		} else {
 | 
			
		||||
			VQ_RING_ASSERT_VALID_IDX(vq, idx);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Update vring_avail control block fields so that other
 | 
			
		||||
		 * side can get buffer using it.
 | 
			
		||||
		 */
 | 
			
		||||
		vq_ring_update_avail(vq, head_idx);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VQUEUE_IDLE(vq);
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * virtqueue_get_buffer - Returns used buffers from VirtIO queue
 | 
			
		||||
 *
 | 
			
		||||
 * @param vq            - Pointer to VirtIO queue control block
 | 
			
		||||
 * @param len           - Length of conumed buffer
 | 
			
		||||
 * @param idx           - index of the buffer
 | 
			
		||||
 *
 | 
			
		||||
 * @return              - Pointer to used buffer
 | 
			
		||||
 */
 | 
			
		||||
void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx)
 | 
			
		||||
{
 | 
			
		||||
	struct vring_used_elem *uep;
 | 
			
		||||
	void *cookie;
 | 
			
		||||
	uint16_t used_idx, desc_idx;
 | 
			
		||||
 | 
			
		||||
	if (!vq || vq->vq_used_cons_idx == vq->vq_ring.used->idx)
 | 
			
		||||
		return (NULL);
 | 
			
		||||
 | 
			
		||||
	VQUEUE_BUSY(vq);
 | 
			
		||||
 | 
			
		||||
	used_idx = vq->vq_used_cons_idx++ & (vq->vq_nentries - 1);
 | 
			
		||||
	uep = &vq->vq_ring.used->ring[used_idx];
 | 
			
		||||
 | 
			
		||||
	atomic_thread_fence(memory_order_seq_cst);
 | 
			
		||||
 | 
			
		||||
	desc_idx = (uint16_t)uep->id;
 | 
			
		||||
	if (len)
 | 
			
		||||
		*len = uep->len;
 | 
			
		||||
 | 
			
		||||
	vq_ring_free_chain(vq, desc_idx);
 | 
			
		||||
 | 
			
		||||
	cookie = vq->vq_descx[desc_idx].cookie;
 | 
			
		||||
	vq->vq_descx[desc_idx].cookie = NULL;
 | 
			
		||||
 | 
			
		||||
	if (idx)
 | 
			
		||||
		*idx = used_idx;
 | 
			
		||||
	VQUEUE_IDLE(vq);
 | 
			
		||||
 | 
			
		||||
	return cookie;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx)
 | 
			
		||||
{
 | 
			
		||||
	return vq->vq_ring.desc[idx].len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * virtqueue_free   - Frees VirtIO queue resources
 | 
			
		||||
 *
 | 
			
		||||
 * @param vq        - Pointer to VirtIO queue control block
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void virtqueue_free(struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	if (vq) {
 | 
			
		||||
		if (vq->vq_free_cnt != vq->vq_nentries) {
 | 
			
		||||
			metal_log(METAL_LOG_WARNING,
 | 
			
		||||
				  "%s: freeing non-empty virtqueue\r\n",
 | 
			
		||||
				  vq->vq_name);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		metal_free_memory(vq);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * virtqueue_get_available_buffer   - Returns buffer available for use in the
 | 
			
		||||
 *                                    VirtIO queue
 | 
			
		||||
 *
 | 
			
		||||
 * @param vq                        - Pointer to VirtIO queue control block
 | 
			
		||||
 * @param avail_idx                 - Pointer to index used in vring desc table
 | 
			
		||||
 * @param len                       - Length of buffer
 | 
			
		||||
 *
 | 
			
		||||
 * @return                          - Pointer to available buffer
 | 
			
		||||
 */
 | 
			
		||||
void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx,
 | 
			
		||||
				     uint32_t *len)
 | 
			
		||||
{
 | 
			
		||||
	uint16_t head_idx = 0;
 | 
			
		||||
	void *buffer;
 | 
			
		||||
 | 
			
		||||
	atomic_thread_fence(memory_order_seq_cst);
 | 
			
		||||
	if (vq->vq_available_idx == vq->vq_ring.avail->idx) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VQUEUE_BUSY(vq);
 | 
			
		||||
 | 
			
		||||
	head_idx = vq->vq_available_idx++ & (vq->vq_nentries - 1);
 | 
			
		||||
	*avail_idx = vq->vq_ring.avail->ring[head_idx];
 | 
			
		||||
 | 
			
		||||
	buffer = virtqueue_phys_to_virt(vq, vq->vq_ring.desc[*avail_idx].addr);
 | 
			
		||||
	*len = vq->vq_ring.desc[*avail_idx].len;
 | 
			
		||||
 | 
			
		||||
	VQUEUE_IDLE(vq);
 | 
			
		||||
 | 
			
		||||
	return buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * virtqueue_add_consumed_buffer - Returns consumed buffer back to VirtIO queue
 | 
			
		||||
 *
 | 
			
		||||
 * @param vq                     - Pointer to VirtIO queue control block
 | 
			
		||||
 * @param head_idx               - Index of vring desc containing used buffer
 | 
			
		||||
 * @param len                    - Length of buffer
 | 
			
		||||
 *
 | 
			
		||||
 * @return                       - Function status
 | 
			
		||||
 */
 | 
			
		||||
int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx,
 | 
			
		||||
				  uint32_t len)
 | 
			
		||||
{
 | 
			
		||||
	struct vring_used_elem *used_desc = NULL;
 | 
			
		||||
	uint16_t used_idx;
 | 
			
		||||
 | 
			
		||||
	if (head_idx > vq->vq_nentries) {
 | 
			
		||||
		return ERROR_VRING_NO_BUFF;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VQUEUE_BUSY(vq);
 | 
			
		||||
 | 
			
		||||
	used_idx = vq->vq_ring.used->idx & (vq->vq_nentries - 1);
 | 
			
		||||
	used_desc = &vq->vq_ring.used->ring[used_idx];
 | 
			
		||||
	used_desc->id = head_idx;
 | 
			
		||||
	used_desc->len = len;
 | 
			
		||||
 | 
			
		||||
	atomic_thread_fence(memory_order_seq_cst);
 | 
			
		||||
 | 
			
		||||
	vq->vq_ring.used->idx++;
 | 
			
		||||
 | 
			
		||||
	VQUEUE_IDLE(vq);
 | 
			
		||||
 | 
			
		||||
	return VQUEUE_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * virtqueue_enable_cb  - Enables callback generation
 | 
			
		||||
 *
 | 
			
		||||
 * @param vq            - Pointer to VirtIO queue control block
 | 
			
		||||
 *
 | 
			
		||||
 * @return              - Function status
 | 
			
		||||
 */
 | 
			
		||||
int virtqueue_enable_cb(struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	return vq_ring_enable_interrupt(vq, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * virtqueue_enable_cb - Disables callback generation
 | 
			
		||||
 *
 | 
			
		||||
 * @param vq           - Pointer to VirtIO queue control block
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void virtqueue_disable_cb(struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	VQUEUE_BUSY(vq);
 | 
			
		||||
 | 
			
		||||
	if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) {
 | 
			
		||||
		vring_used_event(&vq->vq_ring) =
 | 
			
		||||
		    vq->vq_used_cons_idx - vq->vq_nentries - 1;
 | 
			
		||||
	} else {
 | 
			
		||||
		vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VQUEUE_IDLE(vq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * virtqueue_kick - Notifies other side that there is buffer available for it.
 | 
			
		||||
 *
 | 
			
		||||
 * @param vq      - Pointer to VirtIO queue control block
 | 
			
		||||
 */
 | 
			
		||||
void virtqueue_kick(struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	VQUEUE_BUSY(vq);
 | 
			
		||||
 | 
			
		||||
	/* Ensure updated avail->idx is visible to host. */
 | 
			
		||||
	atomic_thread_fence(memory_order_seq_cst);
 | 
			
		||||
 | 
			
		||||
	if (vq_ring_must_notify_host(vq))
 | 
			
		||||
		vq_ring_notify_host(vq);
 | 
			
		||||
 | 
			
		||||
	vq->vq_queued_cnt = 0;
 | 
			
		||||
 | 
			
		||||
	VQUEUE_IDLE(vq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * virtqueue_dump Dumps important virtqueue fields , use for debugging purposes
 | 
			
		||||
 *
 | 
			
		||||
 * @param vq - Pointer to VirtIO queue control block
 | 
			
		||||
 */
 | 
			
		||||
void virtqueue_dump(struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	if (!vq)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	metal_log(METAL_LOG_DEBUG,
 | 
			
		||||
		  "VQ: %s - size=%d; free=%d; used=%d; queued=%d; "
 | 
			
		||||
		  "desc_head_idx=%d; avail.idx=%d; used_cons_idx=%d; "
 | 
			
		||||
		  "used.idx=%d; avail.flags=0x%x; used.flags=0x%x\r\n",
 | 
			
		||||
		  vq->vq_name, vq->vq_nentries, vq->vq_free_cnt,
 | 
			
		||||
		  virtqueue_nused(vq), vq->vq_queued_cnt, vq->vq_desc_head_idx,
 | 
			
		||||
		  vq->vq_ring.avail->idx, vq->vq_used_cons_idx,
 | 
			
		||||
		  vq->vq_ring.used->idx, vq->vq_ring.avail->flags,
 | 
			
		||||
		  vq->vq_ring.used->flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * virtqueue_get_desc_size - Returns vring descriptor size
 | 
			
		||||
 *
 | 
			
		||||
 * @param vq            - Pointer to VirtIO queue control block
 | 
			
		||||
 *
 | 
			
		||||
 * @return              - Descriptor length
 | 
			
		||||
 */
 | 
			
		||||
uint32_t virtqueue_get_desc_size(struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	uint16_t head_idx = 0;
 | 
			
		||||
	uint16_t avail_idx = 0;
 | 
			
		||||
	uint32_t len = 0;
 | 
			
		||||
 | 
			
		||||
	if (vq->vq_available_idx == vq->vq_ring.avail->idx) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VQUEUE_BUSY(vq);
 | 
			
		||||
 | 
			
		||||
	head_idx = vq->vq_available_idx & (vq->vq_nentries - 1);
 | 
			
		||||
	avail_idx = vq->vq_ring.avail->ring[head_idx];
 | 
			
		||||
	len = vq->vq_ring.desc[avail_idx].len;
 | 
			
		||||
 | 
			
		||||
	VQUEUE_IDLE(vq);
 | 
			
		||||
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**************************************************************************
 | 
			
		||||
 *                            Helper Functions                            *
 | 
			
		||||
 **************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * vq_ring_add_buffer
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static uint16_t vq_ring_add_buffer(struct virtqueue *vq,
 | 
			
		||||
				   struct vring_desc *desc, uint16_t head_idx,
 | 
			
		||||
				   struct virtqueue_buf *buf_list, int readable,
 | 
			
		||||
				   int writable)
 | 
			
		||||
{
 | 
			
		||||
	struct vring_desc *dp;
 | 
			
		||||
	int i, needed;
 | 
			
		||||
	uint16_t idx;
 | 
			
		||||
 | 
			
		||||
	(void)vq;
 | 
			
		||||
 | 
			
		||||
	needed = readable + writable;
 | 
			
		||||
 | 
			
		||||
	for (i = 0, idx = head_idx; i < needed; i++, idx = dp->next) {
 | 
			
		||||
		VQASSERT(vq, idx != VQ_RING_DESC_CHAIN_END,
 | 
			
		||||
			 "premature end of free desc chain");
 | 
			
		||||
 | 
			
		||||
		dp = &desc[idx];
 | 
			
		||||
		dp->addr = virtqueue_virt_to_phys(vq, buf_list[i].buf);
 | 
			
		||||
		dp->len = buf_list[i].len;
 | 
			
		||||
		dp->flags = 0;
 | 
			
		||||
 | 
			
		||||
		if (i < needed - 1)
 | 
			
		||||
			dp->flags |= VRING_DESC_F_NEXT;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Readable buffers are inserted  into vring before the
 | 
			
		||||
		 * writable buffers.
 | 
			
		||||
		 */
 | 
			
		||||
		if (i >= readable)
 | 
			
		||||
			dp->flags |= VRING_DESC_F_WRITE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * vq_ring_free_chain
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static void vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx)
 | 
			
		||||
{
 | 
			
		||||
	struct vring_desc *dp;
 | 
			
		||||
	struct vq_desc_extra *dxp;
 | 
			
		||||
 | 
			
		||||
	VQ_RING_ASSERT_VALID_IDX(vq, desc_idx);
 | 
			
		||||
	dp = &vq->vq_ring.desc[desc_idx];
 | 
			
		||||
	dxp = &vq->vq_descx[desc_idx];
 | 
			
		||||
 | 
			
		||||
	if (vq->vq_free_cnt == 0) {
 | 
			
		||||
		VQ_RING_ASSERT_CHAIN_TERM(vq);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vq->vq_free_cnt += dxp->ndescs;
 | 
			
		||||
	dxp->ndescs--;
 | 
			
		||||
 | 
			
		||||
	if ((dp->flags & VRING_DESC_F_INDIRECT) == 0) {
 | 
			
		||||
		while (dp->flags & VRING_DESC_F_NEXT) {
 | 
			
		||||
			VQ_RING_ASSERT_VALID_IDX(vq, dp->next);
 | 
			
		||||
			dp = &vq->vq_ring.desc[dp->next];
 | 
			
		||||
			dxp->ndescs--;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VQASSERT(vq, (dxp->ndescs == 0),
 | 
			
		||||
		 "failed to free entire desc chain, remaining");
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * We must append the existing free chain, if any, to the end of
 | 
			
		||||
	 * newly freed chain. If the virtqueue was completely used, then
 | 
			
		||||
	 * head would be VQ_RING_DESC_CHAIN_END (ASSERTed above).
 | 
			
		||||
	 */
 | 
			
		||||
	dp->next = vq->vq_desc_head_idx;
 | 
			
		||||
	vq->vq_desc_head_idx = desc_idx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * vq_ring_init
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static void vq_ring_init(struct virtqueue *vq, void *ring_mem, int alignment)
 | 
			
		||||
{
 | 
			
		||||
	struct vring *vr;
 | 
			
		||||
	int i, size;
 | 
			
		||||
 | 
			
		||||
	size = vq->vq_nentries;
 | 
			
		||||
	vr = &vq->vq_ring;
 | 
			
		||||
 | 
			
		||||
	vring_init(vr, size, (unsigned char *)ring_mem, alignment);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < size - 1; i++)
 | 
			
		||||
		vr->desc[i].next = i + 1;
 | 
			
		||||
	vr->desc[i].next = VQ_RING_DESC_CHAIN_END;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * vq_ring_update_avail
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static void vq_ring_update_avail(struct virtqueue *vq, uint16_t desc_idx)
 | 
			
		||||
{
 | 
			
		||||
	uint16_t avail_idx;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Place the head of the descriptor chain into the next slot and make
 | 
			
		||||
	 * it usable to the host. The chain is made available now rather than
 | 
			
		||||
	 * deferring to virtqueue_notify() in the hopes that if the host is
 | 
			
		||||
	 * currently running on another CPU, we can keep it processing the new
 | 
			
		||||
	 * descriptor.
 | 
			
		||||
	 */
 | 
			
		||||
	avail_idx = vq->vq_ring.avail->idx & (vq->vq_nentries - 1);
 | 
			
		||||
	vq->vq_ring.avail->ring[avail_idx] = desc_idx;
 | 
			
		||||
 | 
			
		||||
	atomic_thread_fence(memory_order_seq_cst);
 | 
			
		||||
 | 
			
		||||
	vq->vq_ring.avail->idx++;
 | 
			
		||||
 | 
			
		||||
	/* Keep pending count until virtqueue_notify(). */
 | 
			
		||||
	vq->vq_queued_cnt++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * vq_ring_enable_interrupt
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static int vq_ring_enable_interrupt(struct virtqueue *vq, uint16_t ndesc)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * Enable interrupts, making sure we get the latest index of
 | 
			
		||||
	 * what's already been consumed.
 | 
			
		||||
	 */
 | 
			
		||||
	if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) {
 | 
			
		||||
		vring_used_event(&vq->vq_ring) = vq->vq_used_cons_idx + ndesc;
 | 
			
		||||
	} else {
 | 
			
		||||
		vq->vq_ring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	atomic_thread_fence(memory_order_seq_cst);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Enough items may have already been consumed to meet our threshold
 | 
			
		||||
	 * since we last checked. Let our caller know so it processes the new
 | 
			
		||||
	 * entries.
 | 
			
		||||
	 */
 | 
			
		||||
	if (virtqueue_nused(vq) > ndesc) {
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * virtqueue_interrupt
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
void virtqueue_notification(struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	atomic_thread_fence(memory_order_seq_cst);
 | 
			
		||||
	if (vq->callback)
 | 
			
		||||
		vq->callback(vq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * vq_ring_must_notify_host
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static int vq_ring_must_notify_host(struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	uint16_t new_idx, prev_idx, event_idx;
 | 
			
		||||
 | 
			
		||||
	if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) {
 | 
			
		||||
		new_idx = vq->vq_ring.avail->idx;
 | 
			
		||||
		prev_idx = new_idx - vq->vq_queued_cnt;
 | 
			
		||||
		event_idx = vring_avail_event(&vq->vq_ring);
 | 
			
		||||
 | 
			
		||||
		return (vring_need_event(event_idx, new_idx, prev_idx) != 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ((vq->vq_ring.used->flags & VRING_USED_F_NO_NOTIFY) == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * vq_ring_notify_host
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static void vq_ring_notify_host(struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	if (vq->notify)
 | 
			
		||||
		vq->notify(vq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *
 | 
			
		||||
 * virtqueue_nused
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static int virtqueue_nused(struct virtqueue *vq)
 | 
			
		||||
{
 | 
			
		||||
	uint16_t used_idx, nused;
 | 
			
		||||
 | 
			
		||||
	used_idx = vq->vq_ring.used->idx;
 | 
			
		||||
 | 
			
		||||
	nused = (uint16_t)(used_idx - vq->vq_used_cons_idx);
 | 
			
		||||
	VQASSERT(vq, nused <= vq->vq_nentries, "used more than available");
 | 
			
		||||
 | 
			
		||||
	return nused;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
/* generated configuration header file - do not edit */
 | 
			
		||||
#ifndef R_MHU_NS_CFG_H_
 | 
			
		||||
#define R_MHU_NS_CFG_H_
 | 
			
		||||
#define MHU_NS_CFG_PARAM_CHECKING_ENABLE (BSP_CFG_PARAM_CHECKING_ENABLE)
 | 
			
		||||
#endif /* R_MHU_NS_CFG_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -59,6 +59,25 @@ const uart_instance_t g_uart2 =
 | 
			
		|||
    .p_api = &g_uart_on_scif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
mhu_ns_instance_ctrl_t g_mhu_ns0_ctrl;
 | 
			
		||||
 | 
			
		||||
const mhu_cfg_t g_mhu_ns0_cfg =
 | 
			
		||||
{ 
 | 
			
		||||
    .channel = 1, 
 | 
			
		||||
    .rx_ipl = 12, 
 | 
			
		||||
    .rx_irq = MHU_MSG1_NS_IRQn, 
 | 
			
		||||
    .p_callback = NULL, 
 | 
			
		||||
    .p_shared_memory = 0, 
 | 
			
		||||
    .p_context = NULL, 
 | 
			
		||||
};
 | 
			
		||||
/* Instance structure to use this module. */
 | 
			
		||||
const mhu_instance_t g_mhu_ns0 =
 | 
			
		||||
{ 
 | 
			
		||||
    .p_ctrl = &g_mhu_ns0_ctrl, 
 | 
			
		||||
    .p_cfg = &g_mhu_ns0_cfg, 
 | 
			
		||||
    .p_api = &g_mhu_ns_on_mhu_ns 
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
gtm_instance_ctrl_t g_timer2_ctrl;
 | 
			
		||||
 | 
			
		||||
const gtm_extended_cfg_t g_timer2_extend =
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +90,7 @@ const timer_cfg_t g_timer2_cfg =
 | 
			
		|||
{
 | 
			
		||||
    .mode = TIMER_MODE_PERIODIC,
 | 
			
		||||
    // .period_counts = 99999 /* Actual period: 0.001 seconds. */,
 | 
			
		||||
    .period_counts = 100000000 /* Actual period: 0.001 seconds. */,
 | 
			
		||||
    .period_counts = 1000000 /* Actual period: 0.001 seconds. */,
 | 
			
		||||
    .channel = 2,
 | 
			
		||||
    .p_callback = NULL,
 | 
			
		||||
    .p_context = NULL,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@
 | 
			
		|||
#include "r_uart_api.h"
 | 
			
		||||
#include "r_scif_uart.h"
 | 
			
		||||
#include "r_timer_api.h"
 | 
			
		||||
#include "r_mhu_ns.h"
 | 
			
		||||
#include "r_gtm.h"
 | 
			
		||||
 | 
			
		||||
FSP_HEADER
 | 
			
		||||
| 
						 | 
				
			
			@ -19,6 +20,13 @@ extern scif_uart_instance_ctrl_t g_uart2_ctrl;
 | 
			
		|||
extern const uart_cfg_t g_uart2_cfg;
 | 
			
		||||
extern const scif_uart_extended_cfg_t g_uart2_cfg_extend;
 | 
			
		||||
 | 
			
		||||
/** MHU Instance */
 | 
			
		||||
extern const mhu_instance_t g_mhu_ns0;
 | 
			
		||||
 | 
			
		||||
/** Access the MHU instance using these structures when calling API functions directly (::p_api is not used). */
 | 
			
		||||
extern mhu_ns_instance_ctrl_t g_mhu_ns0_ctrl;
 | 
			
		||||
extern const mhu_cfg_t g_mhu_ns0_cfg;
 | 
			
		||||
 | 
			
		||||
/** GTM Timer Instance */
 | 
			
		||||
extern const timer_instance_t g_timer2;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,79 @@
 | 
			
		|||
/***********************************************************************************************************************
 | 
			
		||||
 * Copyright [2020-2021] Renesas Electronics Corporation and/or its affiliates.  All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This software and documentation are supplied by Renesas Electronics Corporation and/or its affiliates and may only
 | 
			
		||||
 * be used with products of Renesas Electronics Corp. and its affiliates ("Renesas").  No other uses are authorized.
 | 
			
		||||
 * Renesas products are sold pursuant to Renesas terms and conditions of sale.  Purchasers are solely responsible for
 | 
			
		||||
 * the selection and use of Renesas products and Renesas assumes no liability.  No license, express or implied, to any
 | 
			
		||||
 * intellectual property right is granted by Renesas.  This software is protected under all applicable laws, including
 | 
			
		||||
 * copyright laws. Renesas reserves the right to change or discontinue this software and/or this documentation.
 | 
			
		||||
 * THE SOFTWARE AND DOCUMENTATION IS DELIVERED TO YOU "AS IS," AND RENESAS MAKES NO REPRESENTATIONS OR WARRANTIES, AND
 | 
			
		||||
 * TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, DISCLAIMS ALL WARRANTIES, WHETHER EXPLICITLY OR IMPLICITLY,
 | 
			
		||||
 * INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT, WITH RESPECT TO THE
 | 
			
		||||
 * SOFTWARE OR DOCUMENTATION.  RENESAS SHALL HAVE NO LIABILITY ARISING OUT OF ANY SECURITY VULNERABILITY OR BREACH.
 | 
			
		||||
 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT WILL RENESAS BE LIABLE TO YOU IN CONNECTION WITH THE SOFTWARE OR
 | 
			
		||||
 * DOCUMENTATION (OR ANY PERSON OR ENTITY CLAIMING RIGHTS DERIVED FROM YOU) FOR ANY LOSS, DAMAGES, OR CLAIMS WHATSOEVER,
 | 
			
		||||
 * INCLUDING, WITHOUT LIMITATION, ANY DIRECT, CONSEQUENTIAL, SPECIAL, INDIRECT, PUNITIVE, OR INCIDENTAL DAMAGES; ANY
 | 
			
		||||
 * LOST PROFITS, OTHER ECONOMIC DAMAGE, PROPERTY DAMAGE, OR PERSONAL INJURY; AND EVEN IF RENESAS HAS BEEN ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH LOSS, DAMAGES, CLAIMS OR COSTS.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
/**
 | 
			
		||||
 * @file    OpenAMP_RPMsg_cfg.h
 | 
			
		||||
 * @brief   OpenAMP configurations
 | 
			
		||||
 * @date    2020.10.21
 | 
			
		||||
 * @author  Copyright (c) 2020, eForce Co., Ltd. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 ****************************************************************************
 | 
			
		||||
 * @par     History
 | 
			
		||||
 *          - rev 1.0 (2020.10.21) Imada
 | 
			
		||||
 *            Initial version for RZ/V2.
 | 
			
		||||
 ****************************************************************************
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __OPEN_AMP_CFG_H__
 | 
			
		||||
#define __OPEN_AMP_CFG_H__
 | 
			
		||||
 | 
			
		||||
// RPMSG config
 | 
			
		||||
#define APP_EPT_ADDR              (0x0U)
 | 
			
		||||
 | 
			
		||||
// Memory region reserved between 0x43000000 - 0x437FFFFF for RPMSG
 | 
			
		||||
#define RPMSG_MEM_BASE            (0x43000000U)
 | 
			
		||||
#define RPMSG_MEM_SIZE            (0x00800000U)
 | 
			
		||||
 | 
			
		||||
#define VRING_SIZE                (0x100000U)
 | 
			
		||||
#define VRING_SHM_SIZE            (0x300000U)
 | 
			
		||||
 | 
			
		||||
#define CFG_RPMSG_SVCNO           (0x2U)
 | 
			
		||||
 | 
			
		||||
// RPMSG channel #0
 | 
			
		||||
#define CFG_RPMSG_SVC_NAME0       "rpmsg-service-0"
 | 
			
		||||
#define CFG_VRING0_BASE0_PA       (0x43000000U)
 | 
			
		||||
#define CFG_VRING0_BASE0_VA       (0x63000000U)
 | 
			
		||||
#define CFG_VRING1_BASE0_PA       (0x43050000U)
 | 
			
		||||
#define CFG_VRING1_BASE0_VA       (0x63050000U)
 | 
			
		||||
#define CFG_VRING_SIZE0           (VRING_SIZE)
 | 
			
		||||
#define CFG_VRING_ALIGN0          (0x100U)
 | 
			
		||||
#define CFG_RPMSG_NUM_BUFS0       (512U)
 | 
			
		||||
#define CFG_VRING_SHM_BASE0_PA    (0x43200000U)
 | 
			
		||||
#define CFG_VRING_SHM_BASE0_VA    (0x63200000U)
 | 
			
		||||
#define CFG_VRING_SHM_SIZE0       (VRING_SHM_SIZE)
 | 
			
		||||
#define CFG_VRING_CTL_NAME0       "43000000.vring-ctl0"
 | 
			
		||||
#define CFG_VRING_SHM_NAME0       "43200000.vring-shm0"
 | 
			
		||||
#define VRING_NOTIFYID0           (0U)
 | 
			
		||||
 | 
			
		||||
// RPMSG channel #1
 | 
			
		||||
#define CFG_RPMSG_SVC_NAME1       "rpmsg-service-1"
 | 
			
		||||
#define CFG_VRING0_BASE1_PA       (0x43100000U)
 | 
			
		||||
#define CFG_VRING0_BASE1_VA       (0x63100000U)
 | 
			
		||||
#define CFG_VRING1_BASE1_PA       (0x43150000U)
 | 
			
		||||
#define CFG_VRING1_BASE1_VA       (0x63150000U)
 | 
			
		||||
#define CFG_VRING_SIZE1           (VRING_SIZE)
 | 
			
		||||
#define CFG_VRING_ALIGN1          (0x100U)
 | 
			
		||||
#define CFG_RPMSG_NUM_BUFS1       (512U)
 | 
			
		||||
#define CFG_VRING_SHM_BASE1_PA    (0x43500000U)
 | 
			
		||||
#define CFG_VRING_SHM_BASE1_VA    (0x63500000U)
 | 
			
		||||
#define CFG_VRING_SHM_SIZE1       (VRING_SHM_SIZE)
 | 
			
		||||
#define CFG_VRING_CTL_NAME1       "43100000.vring-ctl1"
 | 
			
		||||
#define CFG_VRING_SHM_NAME1       "43500000.vring-shm1"
 | 
			
		||||
#define VRING_NOTIFYID1           (1U)
 | 
			
		||||
#endif                                 /* OPENAMP_RPMSG_CFG_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,417 @@
 | 
			
		|||
/***********************************************************************************************************************
 | 
			
		||||
 * Copyright [2020-2021] Renesas Electronics Corporation and/or its affiliates.  All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This software and documentation are supplied by Renesas Electronics Corporation and/or its affiliates and may only
 | 
			
		||||
 * be used with products of Renesas Electronics Corp. and its affiliates ("Renesas").  No other uses are authorized.
 | 
			
		||||
 * Renesas products are sold pursuant to Renesas terms and conditions of sale.  Purchasers are solely responsible for
 | 
			
		||||
 * the selection and use of Renesas products and Renesas assumes no liability.  No license, express or implied, to any
 | 
			
		||||
 * intellectual property right is granted by Renesas.  This software is protected under all applicable laws, including
 | 
			
		||||
 * copyright laws. Renesas reserves the right to change or discontinue this software and/or this documentation.
 | 
			
		||||
 * THE SOFTWARE AND DOCUMENTATION IS DELIVERED TO YOU "AS IS," AND RENESAS MAKES NO REPRESENTATIONS OR WARRANTIES, AND
 | 
			
		||||
 * TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, DISCLAIMS ALL WARRANTIES, WHETHER EXPLICITLY OR IMPLICITLY,
 | 
			
		||||
 * INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT, WITH RESPECT TO THE
 | 
			
		||||
 * SOFTWARE OR DOCUMENTATION.  RENESAS SHALL HAVE NO LIABILITY ARISING OUT OF ANY SECURITY VULNERABILITY OR BREACH.
 | 
			
		||||
 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT WILL RENESAS BE LIABLE TO YOU IN CONNECTION WITH THE SOFTWARE OR
 | 
			
		||||
 * DOCUMENTATION (OR ANY PERSON OR ENTITY CLAIMING RIGHTS DERIVED FROM YOU) FOR ANY LOSS, DAMAGES, OR CLAIMS WHATSOEVER,
 | 
			
		||||
 * INCLUDING, WITHOUT LIMITATION, ANY DIRECT, CONSEQUENTIAL, SPECIAL, INDIRECT, PUNITIVE, OR INCIDENTAL DAMAGES; ANY
 | 
			
		||||
 * LOST PROFITS, OTHER ECONOMIC DAMAGE, PROPERTY DAMAGE, OR PERSONAL INJURY; AND EVEN IF RENESAS HAS BEEN ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH LOSS, DAMAGES, CLAIMS OR COSTS.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2014, Mentor Graphics Corporation
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 * Copyright (c) 2017 Xilinx, Inc.
 | 
			
		||||
 * Copyright (c) 2020, eForce Co., Ltd.
 | 
			
		||||
 *
 | 
			
		||||
 * SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**************************************************************************
 | 
			
		||||
 * FILE NAME
 | 
			
		||||
 *
 | 
			
		||||
 *       platform_info.c
 | 
			
		||||
 *
 | 
			
		||||
 * DESCRIPTION
 | 
			
		||||
 *
 | 
			
		||||
 *       This file define platform specific data and implements APIs to set
 | 
			
		||||
 *       platform specific information for OpenAMP.
 | 
			
		||||
 *
 | 
			
		||||
 * @par  History
 | 
			
		||||
 *       - rev 1.0 (2020.10.21) Imada
 | 
			
		||||
 *         Initial version.
 | 
			
		||||
 *
 | 
			
		||||
 **************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include <metal/atomic.h>
 | 
			
		||||
#include <metal/assert.h>
 | 
			
		||||
#include <metal/device.h>
 | 
			
		||||
#include <metal/irq.h>
 | 
			
		||||
#include <metal/utilities.h>
 | 
			
		||||
#include <openamp/rpmsg_virtio.h>
 | 
			
		||||
#include "platform_info.h"
 | 
			
		||||
#include "rsc_table.h"
 | 
			
		||||
 #include <metal/sys.h>
 | 
			
		||||
 #include <sys/errno.h>
 | 
			
		||||
 | 
			
		||||
static int32 ipi_tsk_id[CFG_RPMSG_SVCNO] = {-1, -1};
 | 
			
		||||
 | 
			
		||||
struct ipi_info ipi =
 | 
			
		||||
{
 | 
			
		||||
    MBX_DEV_NAME,                      // name
 | 
			
		||||
    DEV_BUS_NAME,                      // bus_name
 | 
			
		||||
    NULL,                              // dev
 | 
			
		||||
    NULL,                              // io
 | 
			
		||||
    MBX_INT_NUM,                       // irq_info
 | 
			
		||||
    0,                                 // registered
 | 
			
		||||
    {0,      0},                       // mbx_chn (not used on this SoC)
 | 
			
		||||
    0,                                 // chn_mask (not used on this SoC)
 | 
			
		||||
    {-1,    -1},                       // ipi_mutx_id
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* vring information */
 | 
			
		||||
struct vring_info vrinfo[CFG_RPMSG_SVCNO] =
 | 
			
		||||
{
 | 
			
		||||
    {                                  // vinfo[0]
 | 
			
		||||
        {                              // rsc
 | 
			
		||||
            CFG_RSCTBL_DEV_NAME,       // name
 | 
			
		||||
            DEV_BUS_NAME,              // bus_name
 | 
			
		||||
            NULL,                      // dev
 | 
			
		||||
            NULL,                      // io
 | 
			
		||||
            {0},                       // mem
 | 
			
		||||
        },
 | 
			
		||||
        {                              // ctl
 | 
			
		||||
            CFG_VRING_CTL_NAME0,       // name
 | 
			
		||||
            DEV_BUS_NAME,              // bus_name
 | 
			
		||||
            NULL,                      // dev
 | 
			
		||||
            NULL,                      // io
 | 
			
		||||
            {0},                       // mem
 | 
			
		||||
        },
 | 
			
		||||
        {                              // shm
 | 
			
		||||
            CFG_VRING_SHM_NAME0,       // name
 | 
			
		||||
            DEV_BUS_NAME,              // bus_name
 | 
			
		||||
            NULL,                      // dev
 | 
			
		||||
            NULL,                      // io
 | 
			
		||||
            {0},                       // mem
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    {                                  // vinfo[1]
 | 
			
		||||
        {                              // rsc
 | 
			
		||||
            CFG_RSCTBL_DEV_NAME,       // name
 | 
			
		||||
            DEV_BUS_NAME,              // bus_name
 | 
			
		||||
            NULL,                      // dev
 | 
			
		||||
            NULL,                      // io
 | 
			
		||||
            {0},                       // mem
 | 
			
		||||
        },
 | 
			
		||||
        {                              // ctl
 | 
			
		||||
            CFG_VRING_CTL_NAME1,       // name
 | 
			
		||||
            DEV_BUS_NAME,              // bus_name
 | 
			
		||||
            NULL,                      // dev
 | 
			
		||||
            NULL,                      // io
 | 
			
		||||
            {0},                       // mem
 | 
			
		||||
        },
 | 
			
		||||
        {                              // shm
 | 
			
		||||
            CFG_VRING_SHM_NAME1,       // name
 | 
			
		||||
            DEV_BUS_NAME,              // bus_name
 | 
			
		||||
            NULL,                      // dev
 | 
			
		||||
            NULL,                      // io
 | 
			
		||||
            {0},                       // mem
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* processor operations at RZ/V2. It defines
 | 
			
		||||
 * notification operatio0n and remote processor managementi operations. */
 | 
			
		||||
extern struct remoteproc_ops rzv2_proc_ops;
 | 
			
		||||
 | 
			
		||||
/* RPMsg virtio shared buffer pool */
 | 
			
		||||
static struct rpmsg_virtio_shm_pool shpool;
 | 
			
		||||
 | 
			
		||||
static void start_ipi_task(void * platform);
 | 
			
		||||
 | 
			
		||||
static struct remoteproc * platform_create_proc (int proc_index, int rsc_index)
 | 
			
		||||
{
 | 
			
		||||
    void                   * rsc_table;
 | 
			
		||||
    unsigned int             rsc_size;
 | 
			
		||||
    int                      ret;
 | 
			
		||||
    struct remoteproc      * rproc_inst;
 | 
			
		||||
    struct remoteproc_priv * rproc_priv;
 | 
			
		||||
 | 
			
		||||
    /* Allocate and initialize remoteproc_priv instance */
 | 
			
		||||
    rproc_priv = metal_allocate_memory(sizeof(struct remoteproc_priv));
 | 
			
		||||
    if (!rproc_priv)
 | 
			
		||||
    {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    memset(rproc_priv, 0, sizeof(*rproc_priv));
 | 
			
		||||
    rproc_priv->notify_id = (unsigned int) proc_index;
 | 
			
		||||
    rproc_priv->vr_info   = &vrinfo[rsc_index];
 | 
			
		||||
 | 
			
		||||
    /* Allocate remoteproc instance */
 | 
			
		||||
    rproc_inst = metal_allocate_memory(sizeof(struct remoteproc));
 | 
			
		||||
    if (!rproc_inst)
 | 
			
		||||
    {
 | 
			
		||||
        goto err1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    memset(rproc_inst, 0, sizeof(*rproc_inst));
 | 
			
		||||
 | 
			
		||||
    /* remoteproc initialization */
 | 
			
		||||
    if (!remoteproc_init(rproc_inst, &rzv2_proc_ops, rproc_priv))
 | 
			
		||||
    {
 | 
			
		||||
        goto err2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Mmap shared memories
 | 
			
		||||
     * Or shall we constraint that they will be set as carved out
 | 
			
		||||
     * in the resource table?
 | 
			
		||||
     */
 | 
			
		||||
    rsc_table          = get_resource_table(rsc_index, &rsc_size);
 | 
			
		||||
    rproc_inst->rsc_io = rproc_priv->vr_info->rsc.io;
 | 
			
		||||
 | 
			
		||||
    /* Parse resource table to remoteproc */
 | 
			
		||||
    ret = remoteproc_set_rsc_table(rproc_inst, rsc_table, rsc_size);
 | 
			
		||||
    if (ret)
 | 
			
		||||
    {
 | 
			
		||||
        LPRINTF("Failed to initialize remoteproc\n");
 | 
			
		||||
        goto err2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LPRINTF("Initialize remoteproc successfully.\n");
 | 
			
		||||
 | 
			
		||||
    return rproc_inst;
 | 
			
		||||
err2:
 | 
			
		||||
    (void) remoteproc_remove(rproc_inst);
 | 
			
		||||
    metal_free_memory(rproc_inst);
 | 
			
		||||
err1:
 | 
			
		||||
    metal_free_memory(rproc_priv);
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct  rpmsg_device * platform_create_rpmsg_vdev (void           * platform,
 | 
			
		||||
                                                   unsigned int     vdev_index,
 | 
			
		||||
                                                   unsigned int     role,
 | 
			
		||||
                                                   void (         * rst_cb)(struct virtio_device * vdev),
 | 
			
		||||
                                                   rpmsg_ns_bind_cb ns_bind_cb)
 | 
			
		||||
{
 | 
			
		||||
    struct remoteproc          * rproc = platform;
 | 
			
		||||
    struct remoteproc_priv     * prproc;
 | 
			
		||||
    struct rpmsg_virtio_device * rpmsg_vdev;
 | 
			
		||||
    struct virtio_device       * vdev;
 | 
			
		||||
    struct metal_io_region     * shbuf_io;
 | 
			
		||||
    metal_phys_addr_t            pa;
 | 
			
		||||
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    prproc = rproc->priv;
 | 
			
		||||
 | 
			
		||||
    rpmsg_vdev = metal_allocate_memory(sizeof(*rpmsg_vdev));
 | 
			
		||||
    if (!rpmsg_vdev)
 | 
			
		||||
    {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    memset(rpmsg_vdev, 0, sizeof(*rpmsg_vdev));
 | 
			
		||||
 | 
			
		||||
    LPRINTF("creating remoteproc virtio\n");
 | 
			
		||||
    vdev = remoteproc_create_virtio(rproc, (int) vdev_index, role, rst_cb);
 | 
			
		||||
    if (!vdev)
 | 
			
		||||
    {
 | 
			
		||||
        LPRINTF("failed remoteproc_create_virtio\n");
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa       = metal_io_phys(prproc->vr_info->shm.io, 0x0U);
 | 
			
		||||
    shbuf_io = remoteproc_get_io_with_pa(rproc, pa);
 | 
			
		||||
    if (!shbuf_io)
 | 
			
		||||
    {
 | 
			
		||||
        LPRINTF("failed remoteproc_get_io_with_pa\n");
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Only RPMsg virtio master needs to initialize the shared buffers pool */
 | 
			
		||||
    LPRINTF("initializing rpmsg vdev\n");
 | 
			
		||||
 | 
			
		||||
    /* RPMsg virtio slave can set shared buffers pool argument to NULL */
 | 
			
		||||
    ret = rpmsg_init_vdev(rpmsg_vdev, vdev, ns_bind_cb, shbuf_io, &shpool);
 | 
			
		||||
    if (ret)
 | 
			
		||||
    {
 | 
			
		||||
        LPRINTF("failed rpmsg_init_vdev\n");
 | 
			
		||||
        goto err;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    start_ipi_task(rproc);
 | 
			
		||||
 | 
			
		||||
    return rpmsg_virtio_get_rpmsg_device(rpmsg_vdev);
 | 
			
		||||
err:
 | 
			
		||||
    remoteproc_remove_virtio(rproc, vdev);
 | 
			
		||||
    metal_free_memory(rpmsg_vdev);
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int platform_poll (void * priv)
 | 
			
		||||
{
 | 
			
		||||
    (void) priv;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int platform_init (unsigned long proc_id, unsigned long rsc_id, void ** platform)
 | 
			
		||||
{
 | 
			
		||||
    struct remoteproc * rproc;
 | 
			
		||||
 | 
			
		||||
    if (!platform)
 | 
			
		||||
    {
 | 
			
		||||
        LPRINTF("Failed to initialize platform," "NULL pointer to store platform data.\n");
 | 
			
		||||
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((proc_id >= RSC_MAX_NUM) || (rsc_id >= RSC_MAX_NUM))
 | 
			
		||||
    {
 | 
			
		||||
        LPRINTF("Invalid rproc number specified.\n");
 | 
			
		||||
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rproc = platform_create_proc((int) proc_id, (int) rsc_id);
 | 
			
		||||
    if (!rproc)
 | 
			
		||||
    {
 | 
			
		||||
        LPRINTF("Failed to create remoteproc device.\n");
 | 
			
		||||
 | 
			
		||||
        return -EINVAL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *platform = rproc;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void platform_release_rpmsg_vdev (void * platform, struct rpmsg_device * rpdev)
 | 
			
		||||
{
 | 
			
		||||
    /* Need to free memory regions already allocated but not used anymore? */
 | 
			
		||||
    struct remoteproc          * rproc = platform;
 | 
			
		||||
    struct rpmsg_virtio_device * rpmsg_vdev;
 | 
			
		||||
    struct remoteproc_priv     * prproc = rproc->priv;
 | 
			
		||||
 | 
			
		||||
    KTaskDelete(ipi_tsk_id[prproc->notify_id]);
 | 
			
		||||
    ipi_tsk_id[prproc->notify_id] = -1;
 | 
			
		||||
 | 
			
		||||
    KMutexDelete(ipi.ipi_mutx_id[prproc->notify_id]);
 | 
			
		||||
    ipi.ipi_mutx_id[prproc->notify_id] = -1;
 | 
			
		||||
 | 
			
		||||
    rpmsg_vdev = metal_container_of(rpdev, struct rpmsg_virtio_device, rdev);
 | 
			
		||||
    rpmsg_deinit_vdev(rpmsg_vdev);
 | 
			
		||||
    remoteproc_remove_virtio(rproc, rpmsg_vdev->vdev);
 | 
			
		||||
    metal_free_memory(rpmsg_vdev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void platform_cleanup (void * platform)
 | 
			
		||||
{
 | 
			
		||||
    struct remoteproc      * rproc = platform;
 | 
			
		||||
    struct remoteproc_priv * prproc;
 | 
			
		||||
    struct metal_device    * dev;
 | 
			
		||||
 | 
			
		||||
    if (rproc)
 | 
			
		||||
    {
 | 
			
		||||
        prproc = rproc->priv;
 | 
			
		||||
        if (rproc->priv)
 | 
			
		||||
        {
 | 
			
		||||
            /* Release allocated resource */
 | 
			
		||||
            /* Shared memory devices */
 | 
			
		||||
            metal_list_del(&(prproc->vr_info->ctl.mem.node));
 | 
			
		||||
            dev = prproc->vr_info->ctl.dev;
 | 
			
		||||
            if (dev)
 | 
			
		||||
            {
 | 
			
		||||
                metal_device_close(dev);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            metal_list_del(&(prproc->vr_info->shm.mem.node));
 | 
			
		||||
            dev = prproc->vr_info->shm.dev;
 | 
			
		||||
            if (dev)
 | 
			
		||||
            {
 | 
			
		||||
                metal_device_close(dev);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Resource table device */
 | 
			
		||||
            metal_list_del(&(prproc->vr_info->rsc.mem.node));
 | 
			
		||||
            dev = prproc->vr_info->rsc.dev;
 | 
			
		||||
            if (dev)
 | 
			
		||||
            {
 | 
			
		||||
                metal_device_close(dev);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Release the private area */
 | 
			
		||||
            metal_free_memory(rproc->priv);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        (void) remoteproc_remove(rproc);
 | 
			
		||||
        metal_free_memory(rproc);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void* IpiTask(void * exinf);
 | 
			
		||||
 | 
			
		||||
static void* IpiTask (void * exinf)
 | 
			
		||||
{
 | 
			
		||||
    struct remoteproc      * rproc  = exinf;
 | 
			
		||||
    struct remoteproc_priv * prproc = rproc->priv;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    while (1)
 | 
			
		||||
    {
 | 
			
		||||
        // extern long ShowTask(void);
 | 
			
		||||
        // ShowTask();
 | 
			
		||||
 | 
			
		||||
        KMutexObtain(ipi.ipi_mutx_id[prproc->notify_id], WAITING_FOREVER);
 | 
			
		||||
        // KPrintf("IpiTask: after KSemaphoreObtain\n");
 | 
			
		||||
 | 
			
		||||
        /* Ignore a incoming interrupt if the virtio layer of a target remoteproc is not yet initialized */
 | 
			
		||||
        if (metal_list_is_empty(&rproc->vdevs))
 | 
			
		||||
        {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        ret = remoteproc_get_notification(rproc, RSC_NOTIFY_ID_ANY);
 | 
			
		||||
        // KPrintf("IpiTask: after remoteproc_get_notification\n");
 | 
			
		||||
        if (ret)
 | 
			
		||||
        {
 | 
			
		||||
            LPRINTF("remoteproc_get_notification() failed with %d", ret);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        DelayKTask(10);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void start_ipi_task (void * platform)
 | 
			
		||||
{
 | 
			
		||||
    struct remoteproc      * rproc  = platform;
 | 
			
		||||
    struct remoteproc_priv * prproc = rproc->priv;
 | 
			
		||||
 | 
			
		||||
    int32 mutx_id = KMutexCreate();
 | 
			
		||||
 | 
			
		||||
    if (mutx_id < 0)
 | 
			
		||||
    {
 | 
			
		||||
        KPrintf("start_ipi_task: create sem fail!\n");
 | 
			
		||||
        return ;
 | 
			
		||||
    }
 | 
			
		||||
    ipi.ipi_mutx_id[prproc->notify_id] = mutx_id;
 | 
			
		||||
 | 
			
		||||
    KPrintf("start_ipi_task: prproc->notify_id = %d, ipi.ipi_mutx_id[prproc->notify_id] = %d \n",prproc->notify_id,ipi.ipi_mutx_id[prproc->notify_id]);
 | 
			
		||||
 | 
			
		||||
    int32 ipi_task_id = -1;
 | 
			
		||||
    ipi_task_id = KTaskCreate("ipi_task",IpiTask,platform,4096,SHELL_TASK_PRIORITY + 1);
 | 
			
		||||
 | 
			
		||||
    if (ipi_task_id < 0)
 | 
			
		||||
    {
 | 
			
		||||
        LPRINTF("Failed to register an interrupt service routine.\n");
 | 
			
		||||
        return ;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    ipi_tsk_id[prproc->notify_id] = ipi_task_id;
 | 
			
		||||
 | 
			
		||||
    StartupKTask(ipi_task_id);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,154 @@
 | 
			
		|||
/***********************************************************************************************************************
 | 
			
		||||
 * Copyright [2020-2021] Renesas Electronics Corporation and/or its affiliates.  All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This software and documentation are supplied by Renesas Electronics Corporation and/or its affiliates and may only
 | 
			
		||||
 * be used with products of Renesas Electronics Corp. and its affiliates ("Renesas").  No other uses are authorized.
 | 
			
		||||
 * Renesas products are sold pursuant to Renesas terms and conditions of sale.  Purchasers are solely responsible for
 | 
			
		||||
 * the selection and use of Renesas products and Renesas assumes no liability.  No license, express or implied, to any
 | 
			
		||||
 * intellectual property right is granted by Renesas.  This software is protected under all applicable laws, including
 | 
			
		||||
 * copyright laws. Renesas reserves the right to change or discontinue this software and/or this documentation.
 | 
			
		||||
 * THE SOFTWARE AND DOCUMENTATION IS DELIVERED TO YOU "AS IS," AND RENESAS MAKES NO REPRESENTATIONS OR WARRANTIES, AND
 | 
			
		||||
 * TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, DISCLAIMS ALL WARRANTIES, WHETHER EXPLICITLY OR IMPLICITLY,
 | 
			
		||||
 * INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT, WITH RESPECT TO THE
 | 
			
		||||
 * SOFTWARE OR DOCUMENTATION.  RENESAS SHALL HAVE NO LIABILITY ARISING OUT OF ANY SECURITY VULNERABILITY OR BREACH.
 | 
			
		||||
 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT WILL RENESAS BE LIABLE TO YOU IN CONNECTION WITH THE SOFTWARE OR
 | 
			
		||||
 * DOCUMENTATION (OR ANY PERSON OR ENTITY CLAIMING RIGHTS DERIVED FROM YOU) FOR ANY LOSS, DAMAGES, OR CLAIMS WHATSOEVER,
 | 
			
		||||
 * INCLUDING, WITHOUT LIMITATION, ANY DIRECT, CONSEQUENTIAL, SPECIAL, INDIRECT, PUNITIVE, OR INCIDENTAL DAMAGES; ANY
 | 
			
		||||
 * LOST PROFITS, OTHER ECONOMIC DAMAGE, PROPERTY DAMAGE, OR PERSONAL INJURY; AND EVEN IF RENESAS HAS BEEN ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH LOSS, DAMAGES, CLAIMS OR COSTS.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * @file    platform_info.h
 | 
			
		||||
 * @brief   Platform specific configurations for OpenAMP and Shared memory
 | 
			
		||||
 * @date    2020.10.21
 | 
			
		||||
 * @author  Copyright (c) 2020, eForce Co., Ltd. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 ****************************************************************************
 | 
			
		||||
 * @par     History
 | 
			
		||||
 *          - rev 1.0 (2020.10.21) Imada
 | 
			
		||||
 *            Initial version for RZ/V2.
 | 
			
		||||
 ****************************************************************************
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef PLATFORM_INFO_H_
 | 
			
		||||
#define PLATFORM_INFO_H_
 | 
			
		||||
 | 
			
		||||
#include <openamp/rpmsg.h>
 | 
			
		||||
#include <openamp/remoteproc.h>
 | 
			
		||||
#include "open_amp_cfg.h"
 | 
			
		||||
#include "bsp_api.h"
 | 
			
		||||
#include <xizi.h>
 | 
			
		||||
#include "r_mhu_api.h"
 | 
			
		||||
 | 
			
		||||
#define DEV_BUS_NAME     "generic"
 | 
			
		||||
#define MBX_REG_PA      0x10400000
 | 
			
		||||
#define MBX_REG_VA      0x40400000
 | 
			
		||||
#define MBX_MAP_SIZE     0x00000800
 | 
			
		||||
#define MBX_INT_NUM     69            // MSG1_NS_IRQn
 | 
			
		||||
#define RSC_MAX_NUM      2
 | 
			
		||||
 | 
			
		||||
#define LPRINTF(format, ...)    (KPrintf(format, ## __VA_ARGS__))
 | 
			
		||||
#define LPERROR(format, ...)    (LPRINTF("ERROR: " format, ## __VA_ARGS__))
 | 
			
		||||
 | 
			
		||||
// Page size on Linux (Default: 4KB)
 | 
			
		||||
#define PAGE_SIZE       (0x01000U)     // 4KB page size as the dafault value
 | 
			
		||||
 | 
			
		||||
// Mailbox config
 | 
			
		||||
#define MBX_DEV_NAME    "0x10400000.mbox-uio"
 | 
			
		||||
#define MBX_NO          (0x0U)         /* Maibox number (0, 1, ..., or 7) this program uses */
 | 
			
		||||
 | 
			
		||||
struct ipi_info
 | 
			
		||||
{
 | 
			
		||||
    const char             * name;
 | 
			
		||||
    const char             * bus_name;
 | 
			
		||||
    struct metal_device    * dev;
 | 
			
		||||
    struct metal_io_region * io;
 | 
			
		||||
    uintptr_t                irq_info;
 | 
			
		||||
    int          registered;
 | 
			
		||||
    unsigned int mbx_chn[CFG_RPMSG_SVCNO];
 | 
			
		||||
    unsigned int chn_mask;             /**< IPI channel mask */
 | 
			
		||||
    int32 ipi_mutx_id[CFG_RPMSG_SVCNO];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct shm_info
 | 
			
		||||
{
 | 
			
		||||
    const char             * name;
 | 
			
		||||
    const char             * bus_name;
 | 
			
		||||
    struct metal_device    * dev;      /**< pointer to shared memory device */
 | 
			
		||||
    struct metal_io_region * io;       /**< pointer to shared memory i/o region */
 | 
			
		||||
    struct remoteproc_mem    mem;      /**< shared memory */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct vring_info
 | 
			
		||||
{
 | 
			
		||||
    struct shm_info rsc;
 | 
			
		||||
    struct shm_info ctl;
 | 
			
		||||
    struct shm_info shm;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct remoteproc_priv
 | 
			
		||||
{
 | 
			
		||||
    unsigned int        notify_id;
 | 
			
		||||
    unsigned int        mbx_chn_id;
 | 
			
		||||
    struct vring_info * vr_info;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * platform_init - initialize the platform
 | 
			
		||||
 *
 | 
			
		||||
 * It will initialize the platform.
 | 
			
		||||
 *
 | 
			
		||||
 * @proc_id: processor id
 | 
			
		||||
 * @rsc_id: resource id
 | 
			
		||||
 * @platform: pointer to store the platform data pointer
 | 
			
		||||
 *
 | 
			
		||||
 * return 0 for success or negative value for failure
 | 
			
		||||
 */
 | 
			
		||||
int platform_init(unsigned long proc_id, unsigned long rsc_id, void ** platform);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * platform_create_rpmsg_vdev - create rpmsg vdev
 | 
			
		||||
 *
 | 
			
		||||
 * It will create rpmsg virtio device, and returns the rpmsg virtio
 | 
			
		||||
 * device pointer.
 | 
			
		||||
 *
 | 
			
		||||
 * @platform: pointer to the private data
 | 
			
		||||
 * @vdev_index: index of the virtio device, there can more than one vdev
 | 
			
		||||
 *              on the platform.
 | 
			
		||||
 * @role: virtio master or virtio slave of the vdev
 | 
			
		||||
 * @rst_cb: virtio device reset callback
 | 
			
		||||
 * @ns_bind_cb: rpmsg name service bind callback
 | 
			
		||||
 *
 | 
			
		||||
 * return pointer to the rpmsg virtio device
 | 
			
		||||
 */
 | 
			
		||||
struct rpmsg_device * platform_create_rpmsg_vdev(void           * platform,
 | 
			
		||||
                                                 unsigned int     vdev_index,
 | 
			
		||||
                                                 unsigned int     role,
 | 
			
		||||
                                                 void (         * rst_cb)(struct virtio_device * vdev),
 | 
			
		||||
                                                 rpmsg_ns_bind_cb ns_bind_cb);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * platform_poll - platform poll function
 | 
			
		||||
 *
 | 
			
		||||
 * @platform: pointer to the platform
 | 
			
		||||
 *
 | 
			
		||||
 * return negative value for errors, otherwise 0.
 | 
			
		||||
 */
 | 
			
		||||
int platform_poll(void * platform);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * platform_release_rpmsg_vdev - release rpmsg virtio device
 | 
			
		||||
 *
 | 
			
		||||
 * @platform: pointer to the platform
 | 
			
		||||
 * @rpdev: pointer to the rpmsg device
 | 
			
		||||
 */
 | 
			
		||||
void platform_release_rpmsg_vdev(void * platform, struct rpmsg_device * rpdev);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * platform_cleanup - clean up the platform resource
 | 
			
		||||
 *
 | 
			
		||||
 * @platform: pointer to the platform
 | 
			
		||||
 */
 | 
			
		||||
void platform_cleanup(void * platform);
 | 
			
		||||
 | 
			
		||||
#endif                                 /* PLATFORM_INFO_H_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,198 @@
 | 
			
		|||
/***********************************************************************************************************************
 | 
			
		||||
 * Copyright [2020-2021] Renesas Electronics Corporation and/or its affiliates.  All Rights Reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This software and documentation are supplied by Renesas Electronics Corporation and/or its affiliates and may only
 | 
			
		||||
 * be used with products of Renesas Electronics Corp. and its affiliates ("Renesas").  No other uses are authorized.
 | 
			
		||||
 * Renesas products are sold pursuant to Renesas terms and conditions of sale.  Purchasers are solely responsible for
 | 
			
		||||
 * the selection and use of Renesas products and Renesas assumes no liability.  No license, express or implied, to any
 | 
			
		||||
 * intellectual property right is granted by Renesas.  This software is protected under all applicable laws, including
 | 
			
		||||
 * copyright laws. Renesas reserves the right to change or discontinue this software and/or this documentation.
 | 
			
		||||
 * THE SOFTWARE AND DOCUMENTATION IS DELIVERED TO YOU "AS IS," AND RENESAS MAKES NO REPRESENTATIONS OR WARRANTIES, AND
 | 
			
		||||
 * TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, DISCLAIMS ALL WARRANTIES, WHETHER EXPLICITLY OR IMPLICITLY,
 | 
			
		||||
 * INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT, WITH RESPECT TO THE
 | 
			
		||||
 * SOFTWARE OR DOCUMENTATION.  RENESAS SHALL HAVE NO LIABILITY ARISING OUT OF ANY SECURITY VULNERABILITY OR BREACH.
 | 
			
		||||
 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT WILL RENESAS BE LIABLE TO YOU IN CONNECTION WITH THE SOFTWARE OR
 | 
			
		||||
 * DOCUMENTATION (OR ANY PERSON OR ENTITY CLAIMING RIGHTS DERIVED FROM YOU) FOR ANY LOSS, DAMAGES, OR CLAIMS WHATSOEVER,
 | 
			
		||||
 * INCLUDING, WITHOUT LIMITATION, ANY DIRECT, CONSEQUENTIAL, SPECIAL, INDIRECT, PUNITIVE, OR INCIDENTAL DAMAGES; ANY
 | 
			
		||||
 * LOST PROFITS, OTHER ECONOMIC DAMAGE, PROPERTY DAMAGE, OR PERSONAL INJURY; AND EVEN IF RENESAS HAS BEEN ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH LOSS, DAMAGES, CLAIMS OR COSTS.
 | 
			
		||||
 **********************************************************************************************************************/
 | 
			
		||||
/**
 | 
			
		||||
 * @file    sample_rpmsg.c
 | 
			
		||||
 * @brief   rpmsg sample program for FreeRTOS
 | 
			
		||||
 * @date    2020.03.24
 | 
			
		||||
 * @author  Copyright (c) 2020, eForce Co., Ltd. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 ****************************************************************************
 | 
			
		||||
 * @par     History
 | 
			
		||||
 *          - rev 1.0 (2020.01.28) Imada
 | 
			
		||||
 *            Initial version.
 | 
			
		||||
 *          - rev 1.1 (2020.03.24) Imada
 | 
			
		||||
 *            Employed a dedicated function to set a string for Shared memory API.
 | 
			
		||||
 ****************************************************************************
 | 
			
		||||
 */
 | 
			
		||||
#include <openamp/open_amp.h>
 | 
			
		||||
#include "platform_info.h"
 | 
			
		||||
#include "rsc_table.h"
 | 
			
		||||
#include <xizi.h>
 | 
			
		||||
 | 
			
		||||
extern int  init_system(void);
 | 
			
		||||
extern void cleanup_system(void);
 | 
			
		||||
 | 
			
		||||
#define SHUTDOWN_MSG     (0xEF56A55A)
 | 
			
		||||
 | 
			
		||||
/* Local variables */
 | 
			
		||||
 | 
			
		||||
/*-----------------------------------------------------------------------------*
 | 
			
		||||
 *  RPMSG callbacks setup by remoteproc_resource_init()
 | 
			
		||||
 *-----------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
/* Local variables */
 | 
			
		||||
 | 
			
		||||
static struct rpmsg_endpoint rp_ept[CFG_RPMSG_SVCNO] = {0};
 | 
			
		||||
 | 
			
		||||
volatile static int evt_svc_unbind[CFG_RPMSG_SVCNO] = {0};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Callback Function: rpmsg_endpoint_cb
 | 
			
		||||
 *
 | 
			
		||||
 *  @param[in] rp_svc
 | 
			
		||||
 *  @param[in] data
 | 
			
		||||
 *  @param[in] len
 | 
			
		||||
 *  @param[in] priv
 | 
			
		||||
 *  @param[in] src
 | 
			
		||||
 */
 | 
			
		||||
static int rpmsg_endpoint_cb0 (struct rpmsg_endpoint * cb_rp_ept, void * data, size_t len, uint32_t src, void * priv)
 | 
			
		||||
{
 | 
			
		||||
    /* service 0 */
 | 
			
		||||
    (void) priv;
 | 
			
		||||
    (void) src;
 | 
			
		||||
    /* On reception of a shutdown we signal the application to terminate */
 | 
			
		||||
    if ((*(unsigned int *) data) == SHUTDOWN_MSG)
 | 
			
		||||
    {
 | 
			
		||||
        evt_svc_unbind[0] = 1;
 | 
			
		||||
 | 
			
		||||
        return RPMSG_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
    KPrintf("rpmsg_endpoint_cb0: recv data = %p, *data = %d,len = %d\n",data,*((int*)(data)),len);
 | 
			
		||||
    /* Send data back to master */
 | 
			
		||||
    if (rpmsg_send(cb_rp_ept, data, (int) len) < 0)
 | 
			
		||||
    {
 | 
			
		||||
        LPERROR("rpmsg_send failed\n");
 | 
			
		||||
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    return RPMSG_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rpmsg_endpoint_cb1 (struct rpmsg_endpoint * cb_rp_ept, void * data, size_t len, uint32_t src, void * priv)
 | 
			
		||||
{
 | 
			
		||||
    /* service 1 */
 | 
			
		||||
    (void) priv;
 | 
			
		||||
    (void) src;
 | 
			
		||||
 | 
			
		||||
    /* On reception of a shutdown we signal the application to terminate */
 | 
			
		||||
    if ((*(unsigned int *) data) == SHUTDOWN_MSG)
 | 
			
		||||
    {
 | 
			
		||||
        evt_svc_unbind[1] = 1;
 | 
			
		||||
 | 
			
		||||
        return RPMSG_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Send data back to master */
 | 
			
		||||
    if (rpmsg_send(cb_rp_ept, data, (int) len) < 0)
 | 
			
		||||
    {
 | 
			
		||||
        LPERROR("rpmsg_send failed \n");
 | 
			
		||||
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return RPMSG_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 *  Callback Function: rpmsg_service_unbind
 | 
			
		||||
 *
 | 
			
		||||
 *  @param[in] ept
 | 
			
		||||
 */
 | 
			
		||||
static void rpmsg_service_unbind0 (struct rpmsg_endpoint * ept)
 | 
			
		||||
{
 | 
			
		||||
    (void) ept;
 | 
			
		||||
 | 
			
		||||
    /* service 0 */
 | 
			
		||||
    rpmsg_destroy_ept(&rp_ept[0]);
 | 
			
		||||
    memset(&rp_ept[0], 0x0, sizeof(struct rpmsg_endpoint));
 | 
			
		||||
    evt_svc_unbind[0] = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rpmsg_service_unbind1 (struct rpmsg_endpoint * ept)
 | 
			
		||||
{
 | 
			
		||||
    (void) ept;
 | 
			
		||||
 | 
			
		||||
    /* service 1 */
 | 
			
		||||
    rpmsg_destroy_ept(&rp_ept[1]);
 | 
			
		||||
    memset(&rp_ept[1], 0x0, sizeof(struct rpmsg_endpoint));
 | 
			
		||||
    evt_svc_unbind[1] = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*-----------------------------------------------------------------------------*
 | 
			
		||||
 *  Application
 | 
			
		||||
 *-----------------------------------------------------------------------------*/
 | 
			
		||||
int app (struct rpmsg_device * rdev, void * platform, unsigned long svcno)
 | 
			
		||||
{
 | 
			
		||||
    (void) platform;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if (svcno == 0UL)
 | 
			
		||||
    {
 | 
			
		||||
        ret = rpmsg_create_ept(&rp_ept[0],
 | 
			
		||||
                               rdev,
 | 
			
		||||
                               CFG_RPMSG_SVC_NAME0,
 | 
			
		||||
                               APP_EPT_ADDR,
 | 
			
		||||
                               RPMSG_ADDR_ANY,
 | 
			
		||||
                               rpmsg_endpoint_cb0,
 | 
			
		||||
                               rpmsg_service_unbind0);
 | 
			
		||||
        if (ret)
 | 
			
		||||
        {
 | 
			
		||||
            LPERROR("Failed to create endpoint.\n");
 | 
			
		||||
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        KPrintf("app: Success to create endpoint rp_ept[0]\n");
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        ret = rpmsg_create_ept(&rp_ept[1],
 | 
			
		||||
                               rdev,
 | 
			
		||||
                               CFG_RPMSG_SVC_NAME1,
 | 
			
		||||
                               APP_EPT_ADDR,
 | 
			
		||||
                               RPMSG_ADDR_ANY,
 | 
			
		||||
                               rpmsg_endpoint_cb1,
 | 
			
		||||
                               rpmsg_service_unbind1);
 | 
			
		||||
        if (ret)
 | 
			
		||||
        {
 | 
			
		||||
            LPERROR("Failed to create endpoint.\n");
 | 
			
		||||
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LPRINTF("Waiting for events...\n");
 | 
			
		||||
 | 
			
		||||
    while (1)
 | 
			
		||||
    {
 | 
			
		||||
        DelayKTask(100);
 | 
			
		||||
 | 
			
		||||
        /* we got a shutdown request, exit */
 | 
			
		||||
        if (evt_svc_unbind[svcno])
 | 
			
		||||
        {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Clear shutdown flag */
 | 
			
		||||
    evt_svc_unbind[svcno] = 0;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue