diff --git a/open-amp/VERSION b/open-amp/VERSION index b28f934..a32a550 100644 --- a/open-amp/VERSION +++ b/open-amp/VERSION @@ -1,3 +1,3 @@ VERSION_MAJOR = 1 -VERSION_MINOR = 5 -VERSION_PATCH = 0 +VERSION_MINOR = 6 +VERSION_PATCH = 1 diff --git a/open-amp/cmake/options.cmake b/open-amp/cmake/options.cmake index 35a3333..2f0a749 100644 --- a/open-amp/cmake/options.cmake +++ b/open-amp/cmake/options.cmake @@ -60,23 +60,19 @@ endif(NOT ${MACHINE} STREQUAL "zynqmp_r5") option (WITH_VIRTIO_DRIVER "Build with virtio driver (front end) enabled" ON) option (WITH_VIRTIO_DEVICE "Build with virtio device (back end) enabled" ON) -option (WITH_VIRTIO_MASTER "Build with virtio driver (front end) enabled" OFF) -option (WITH_VIRTIO_SLAVE "Build with virtio device (back end) enabled" OFF) - -if (WITH_VIRTIO_MASTER) - message(DEPRECATION "deprecated cmake option replaced by WITH_VIRTIO_DRIVER" ...) -endif (WITH_VIRTIO_MASTER) -if (WITH_VIRTIO_SLAVE) - message(DEPRECATION "deprecated cmake option replaced by WITH_VIRTIO_DEVICE" ...) -endif (WITH_VIRTIO_SLAVE) - -if (NOT WITH_VIRTIO_DRIVER AND NOT WITH_VIRTIO_MASTER) - add_definitions(-DVIRTIO_DEVICE_ONLY) -endif (NOT WITH_VIRTIO_DRIVER AND NOT WITH_VIRTIO_MASTER) - -if (NOT WITH_VIRTIO_DEVICE AND NOT WITH_VIRTIO_SLAVE) - add_definitions(-DVIRTIO_DRIVER_ONLY) -endif (NOT WITH_VIRTIO_DEVICE AND NOT WITH_VIRTIO_SLAVE) + + +if (NOT WITH_VIRTIO_DRIVER) + add_definitions(-DVIRTIO_DRIVER_SUPPORT=0) +else (NOT WITH_VIRTIO_DRIVER) + add_definitions(-DVIRTIO_DRIVER_SUPPORT=1) +endif (NOT WITH_VIRTIO_DRIVER) + +if (NOT WITH_VIRTIO_DEVICE) + add_definitions(-DVIRTIO_DEVICE_SUPPORT=0) +else (NOT WITH_VIRTIO_DEVICE) + add_definitions(-DVIRTIO_DEVICE_SUPPORT=1) +endif (NOT WITH_VIRTIO_DEVICE) option (WITH_VIRTIO_MMIO_DRV "Build with virtio mmio driver support enabled" OFF) diff --git a/open-amp/lib/CMakeLists.txt b/open-amp/lib/CMakeLists.txt index ff2e399..f8f9e2f 100644 --- a/open-amp/lib/CMakeLists.txt +++ b/open-amp/lib/CMakeLists.txt @@ -61,6 +61,7 @@ else (WITH_ZEPHYR) if (WITH_STATIC_LIB) set (_lib ${OPENAMP_LIB}-static) add_library (${_lib} STATIC ${_sources}) + target_include_directories(${_lib} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) install (TARGETS ${_lib} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) set_target_properties (${_lib} PROPERTIES OUTPUT_NAME "${OPENAMP_LIB}" diff --git a/open-amp/lib/include/openamp/remoteproc.h b/open-amp/lib/include/openamp/remoteproc.h index 23f9178..84bf233 100644 --- a/open-amp/lib/include/openamp/remoteproc.h +++ b/open-amp/lib/include/openamp/remoteproc.h @@ -79,34 +79,43 @@ struct fw_rsc_hdr { } METAL_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 remoteproc 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 + * @brief Types of resource entries * * 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 + * lookup table, so please keep them sane. Moreover, \ref 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 { + /** carveout resource + * + * Request for allocation of a physically contiguous memory region. + */ RSC_CARVEOUT = 0, + /** device memory resource + * + * Request to iommu_map a memory-based peripheral. + */ RSC_DEVMEM = 1, + /** trace resource + * + * Announces the availability of a trace buffer into which the remote remoteproc will be + * writing logs. + */ RSC_TRACE = 2, + /** virtio device resource + * + * Declare support for a virtio device, and serve as its virtio header. + */ RSC_VDEV = 3, + /** end of the generic resources */ RSC_LAST = 4, + /** Start of the vendor specific resource types range */ RSC_VENDOR_START = 128, + /** End of the vendor specific resource types range */ RSC_VENDOR_END = 512, }; @@ -520,24 +529,24 @@ static inline void *RPROC_ERR_PTR(long error) } /** - * enum rproc_state - remote processor states - * @RPROC_OFFLINE: remote is offline - * @RPROC_CONFIGURED: remote is configured - * @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 + * @brief Remote processor states */ enum remoteproc_state { + /** Remote is offline */ RPROC_OFFLINE = 0, + /** Remote is configured */ RPROC_CONFIGURED = 1, + /** Remote is ready to start */ RPROC_READY = 2, + /** Remote is up and running */ RPROC_RUNNING = 3, + /** Remote is suspended */ RPROC_SUSPENDED = 4, + /** Remote is has error; need to recover */ RPROC_ERROR = 5, + /** Remote is stopped */ RPROC_STOPPED = 6, + /** Just keep this one at the end */ RPROC_LAST = 7, }; @@ -573,22 +582,9 @@ int remoteproc_remove(struct remoteproc *rproc); * @param size Memory size * @param 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 || !io || size == 0) - 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; -} +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); /** * @brief Add remoteproc memory @@ -596,13 +592,7 @@ remoteproc_init_mem(struct remoteproc_mem *mem, const char *name, * @param rproc Pointer to remoteproc * @param 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); -} +void remoteproc_add_mem(struct remoteproc *rproc, struct remoteproc_mem *mem); /** * @brief Get remoteproc memory I/O region with name diff --git a/open-amp/lib/include/openamp/rpmsg.h b/open-amp/lib/include/openamp/rpmsg.h index 9cf1e74..f994e1d 100644 --- a/open-amp/lib/include/openamp/rpmsg.h +++ b/open-amp/lib/include/openamp/rpmsg.h @@ -43,6 +43,7 @@ extern "C" { #define RPMSG_ERR_INIT (RPMSG_ERROR_BASE - 6) #define RPMSG_ERR_ADDR (RPMSG_ERROR_BASE - 7) #define RPMSG_ERR_PERM (RPMSG_ERROR_BASE - 8) +#define RPMSG_EOPNOTSUPP (RPMSG_ERROR_BASE - 9) struct rpmsg_endpoint; struct rpmsg_device; @@ -50,6 +51,7 @@ struct rpmsg_device; /* Returns positive value on success or negative error value on failure */ typedef int (*rpmsg_ept_cb)(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv); +typedef void (*rpmsg_ept_release_cb)(struct rpmsg_endpoint *ept); 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); @@ -73,6 +75,12 @@ struct rpmsg_endpoint { /** Address of the default remote endpoint binded */ uint32_t dest_addr; + /** Reference count for determining whether the endpoint can be deallocated */ + uint32_t refcnt; + + /** Callback to inform the user that the endpoint allocation can be safely removed */ + rpmsg_ept_release_cb release_cb; + /** * User rx callback, return value of this callback is reserved for future * use, for now, only allow RPMSG_SUCCESS as return value @@ -113,6 +121,12 @@ struct rpmsg_device_ops { /** Release RPMsg TX buffer */ int (*release_tx_buffer)(struct rpmsg_device *rdev, void *txbuf); + + /** Get RPMsg RX buffer size */ + int (*get_rx_buffer_size)(struct rpmsg_device *rdev); + + /** Get RPMsg TX buffer size */ + int (*get_tx_buffer_size)(struct rpmsg_device *rdev); }; /** @brief Representation of a RPMsg device */ @@ -125,6 +139,7 @@ struct rpmsg_device { /** Table endpoint address allocation */ unsigned long bitmap[metal_bitmap_longs(RPMSG_ADDR_BMP_SIZE)]; + unsigned int bitnext; /** Mutex lock for RPMsg management */ metal_mutex_t lock; @@ -146,8 +161,8 @@ struct rpmsg_device { * @brief Send a message across to the remote processor, * specifying source and destination address. * - * This function sends @data of length @len to the remote @dst address from - * the source @src address. + * 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. * @@ -167,9 +182,9 @@ int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src, /** * @brief Send a message across to the remote processor * - * This function sends @data of length @len based on the @ept. + * 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. + * 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. @@ -193,9 +208,9 @@ static inline int rpmsg_send(struct rpmsg_endpoint *ept, const void *data, /** * @brief Send a message across to the remote processor, specify dst * - * 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. + * 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. @@ -219,9 +234,9 @@ static inline int rpmsg_sendto(struct rpmsg_endpoint *ept, const void *data, /** * @brief Send a message using explicit src/dst addresses * - * 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 + * 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 @@ -245,9 +260,9 @@ static inline int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, /** * @brief Send a message across to the remote processor * - * 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. + * 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. * @@ -270,9 +285,9 @@ static inline int rpmsg_trysend(struct rpmsg_endpoint *ept, const void *data, /** * @brief Send a message across to the remote processor, specify dst * - * 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. + * 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. * @@ -295,9 +310,9 @@ static inline int rpmsg_trysendto(struct rpmsg_endpoint *ept, const void *data, /** * @brief Send a message using explicit src/dst addresses * - * 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 + * 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. @@ -395,6 +410,30 @@ void *rpmsg_get_tx_payload_buffer(struct rpmsg_endpoint *ept, */ int rpmsg_release_tx_buffer(struct rpmsg_endpoint *ept, void *txbuf); +/** + * @brief Get RPMsg Tx buffer size + * + * @param ept The rpmsg endpoint + * + * @return + * - Next available Tx buffer size on success + * - RPMSG_ERR_PARAM on invalid parameter + * - RPMSG_ERR_PERM if service not implemented + */ +int rpmsg_get_tx_buffer_size(struct rpmsg_endpoint *ept); + +/** + * @brief Get RPMsg Rx buffer size + * + * @param ept The rpmsg endpoint + * + * @return + * - Next available Rx buffer size on success + * - RPMSG_ERR_PARAM on invalid parameter + * - RPMSG_ERR_PERM if service not implemented + */ +int rpmsg_get_rx_buffer_size(struct rpmsg_endpoint *ept); + /** * @brief Send a message in tx buffer reserved by * rpmsg_get_tx_payload_buffer() across to the remote processor. diff --git a/open-amp/lib/include/openamp/rpmsg_rpc_client_server.h b/open-amp/lib/include/openamp/rpmsg_rpc_client_server.h index f940784..a344cde 100644 --- a/open-amp/lib/include/openamp/rpmsg_rpc_client_server.h +++ b/open-amp/lib/include/openamp/rpmsg_rpc_client_server.h @@ -25,21 +25,21 @@ extern "C" { * Aligning to 64 bits -> 488UL */ #define MAX_BUF_LEN 488UL -#define MAX_FUNC_ID_LEN sizeof(unsigned long int) +#define MAX_FUNC_ID_LEN sizeof(uint32_t) struct rpmsg_rpc_clt; struct rpmsg_rpc_svr; typedef void (*rpmsg_rpc_shutdown_cb)(struct rpmsg_rpc_clt *rpc); -typedef void (*app_cb)(struct rpmsg_rpc_clt *rpc, int statust, void *data, +typedef void (*app_cb)(struct rpmsg_rpc_clt *rpc, int status, void *data, size_t len); typedef int (*rpmsg_rpc_syscall_cb)(void *data, struct rpmsg_rpc_svr *rpcs); /** * struct rpmsg_rpc_request - rpc request message * - * @id: service id - * @params: request params + * @param id service id + * @param params request params * */ struct rpmsg_rpc_request { @@ -181,7 +181,7 @@ int rpmsg_rpc_server_init(struct rpmsg_rpc_svr *rpcs, struct rpmsg_device *rdev, * @return Length of the received response, negative value for failure. */ int rpmsg_rpc_client_send(struct rpmsg_rpc_clt *rpc, - unsigned int rpc_id, void *request_param, + uint32_t rpc_id, void *request_param, size_t req_param_size); /** diff --git a/open-amp/lib/include/openamp/rpmsg_virtio.h b/open-amp/lib/include/openamp/rpmsg_virtio.h index aea2edf..44ac4c0 100644 --- a/open-amp/lib/include/openamp/rpmsg_virtio.h +++ b/open-amp/lib/include/openamp/rpmsg_virtio.h @@ -41,6 +41,9 @@ extern "C" { #define BUFFER_INVALIDATE(x, s) do { } while (0) #endif /* VIRTIO_CACHED_BUFFERS || VIRTIO_USE_DCACHE */ +/* Callback handler for rpmsg virtio service */ +typedef int (*rpmsg_virtio_notify_wait_cb)(struct rpmsg_device *rdev, uint32_t id); + /** @brief Shared memory pool used for RPMsg buffers */ struct rpmsg_virtio_shm_pool { /** Base address of the memory pool */ @@ -98,49 +101,99 @@ struct rpmsg_virtio_device { * \ref rpmsg_virtio_release_tx_buffer function */ struct metal_list reclaimer; + + /** + * Callback handler for rpmsg virtio service, called when service + * can't get tx buffer + */ + rpmsg_virtio_notify_wait_cb notify_wait_cb; }; #define RPMSG_REMOTE VIRTIO_DEV_DEVICE #define RPMSG_HOST VIRTIO_DEV_DRIVER -#define RPMSG_SLAVE deprecated_rpmsg_slave() -#define RPMSG_MASTER deprecated_rpmsg_master() - -__deprecated static inline int deprecated_rpmsg_master(void) -{ - /* "RPMSG_MASTER is deprecated, please use RPMSG_HOST" */ - return RPMSG_HOST; -} - -__deprecated static inline int deprecated_rpmsg_slave(void) +/** + * @brief Set the virtio callback to manage the wait for TX buffer availability. + * + * @param rvdev Pointer to rpmsg virtio device. + * @param notify_wait_cb Callback handler to wait buffer notification. + */ +static inline void rpmsg_virtio_set_wait_cb(struct rpmsg_virtio_device *rvdev, + rpmsg_virtio_notify_wait_cb notify_wait_cb) { - /* "RPMSG_SLAVE is deprecated, please use RPMSG_REMOTE" */ - return RPMSG_REMOTE; + rvdev->notify_wait_cb = notify_wait_cb; } +/** + * @brief Get rpmsg virtio device role. + * + * @param rvdev Pointer to rpmsg virtio device. + * + * @return VIRTIO_DEV_DEVICE or VIRTIO_DEV_DRIVER + */ static inline unsigned int rpmsg_virtio_get_role(struct rpmsg_virtio_device *rvdev) { return rvdev->vdev->role; } +/** + * @brief Set rpmsg virtio device status. + * + * Deprecated: Use virtio_set_status() instead + * + * @param rvdev Pointer to rpmsg virtio device. + * @param status Value to be set as rpmsg virtio device status. + */ +__deprecated static inline void rpmsg_virtio_set_status(struct rpmsg_virtio_device *rvdev, uint8_t status) { rvdev->vdev->func->set_status(rvdev->vdev, status); } +/** + * @brief Retrieve rpmsg virtio device status. + * + * Deprecated: Use virtio_get_status() instead + * + * @param rvdev Pointer to rpmsg virtio device. + * + * @return The rpmsg virtio device status. + */ +__deprecated static inline uint8_t rpmsg_virtio_get_status(struct rpmsg_virtio_device *rvdev) { return rvdev->vdev->func->get_status(rvdev->vdev); } +/** + * @brief Get the rpmsg virtio device features. + * + * Deprecated: Use virtio_get_features() instead + * + * @param rvdev Pointer to the rpmsg virtio device. + * + * @return The features supported by both the rpmsg driver and rpmsg device. + */ +__deprecated static inline uint32_t rpmsg_virtio_get_features(struct rpmsg_virtio_device *rvdev) { return rvdev->vdev->func->get_features(rvdev->vdev); } +/** + * @brief Retrieve configuration data from the rpmsg virtio device. + * + * Deprecated: Use virtio_read_config() instead + * + * @param rvdev Pointer to the rpmsg virtio device. + * @param offset Offset of the data within the configuration area. + * @param dst Address of the buffer that will hold the data. + * @param length Length of the data to be retrieved. + */ +__deprecated static inline void rpmsg_virtio_read_config(struct rpmsg_virtio_device *rvdev, uint32_t offset, void *dst, int length) @@ -148,13 +201,40 @@ rpmsg_virtio_read_config(struct rpmsg_virtio_device *rvdev, rvdev->vdev->func->read_config(rvdev->vdev, offset, dst, length); } +/** + * @brief Write configuration data to the rpmsg virtio device. + * + * Deprecated: Use virtio_write_config() instead + * + * @param rvdev Pointer to the rpmsg virtio device. + * @param offset Offset of the data within the configuration area. + * @param src Address of the buffer that holds the data to write. + * @param length Length of the data to be written. + * + * @return 0 on success, otherwise error code. + */ +__deprecated static inline void rpmsg_virtio_write_config(struct rpmsg_virtio_device *rvdev, - uint32_t offset, void *dst, int length) + uint32_t offset, void *src, int length) { - rvdev->vdev->func->write_config(rvdev->vdev, offset, dst, length); + rvdev->vdev->func->write_config(rvdev->vdev, offset, src, length); } +/** + * @brief Create the rpmsg virtio device virtqueue. + * + * Deprecated: Use virtio_create_virtqueues() instead + * + * @param rvdev Pointer to the rpmsg virtio device. + * @param flags Create flag. + * @param nvqs The virtqueue number. + * @param names Virtqueue names. + * @param callbacks Virtqueue callback functions. + * + * @return 0 on success, otherwise error code. + */ +__deprecated static inline int rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev, int flags, unsigned int nvqs, @@ -165,6 +245,20 @@ rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev, callbacks, NULL); } +/** + * @brief Delete the virtqueues created in rpmsg_virtio_create_virtqueues() + * + * Deprecated: Use virtio_delete_virtqueues() instead + * + * @param rvdev Pointer to the rpmsg virtio device + */ +__deprecated +static inline void +rpmsg_virtio_delete_virtqueues(struct rpmsg_virtio_device *rvdev) +{ + virtio_delete_virtqueues(rvdev->vdev); +} + /** * @brief Get rpmsg virtio buffer size * @@ -172,7 +266,31 @@ rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev, * * @return Next available buffer size for text, negative value for failure */ -int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev); +int rpmsg_virtio_get_tx_buffer_size(struct rpmsg_device *rdev); + +/** + * @brief Get rpmsg virtio Rx buffer size + * + * @param rdev Pointer to the rpmsg device + * + * @return Next available buffer size for text, negative value for failure + */ +int rpmsg_virtio_get_rx_buffer_size(struct rpmsg_device *rdev); + +/** + * @brief Get rpmsg virtio Tx buffer size + * + * This function is same as rpmsg_virtio_get_tx_buffer_size(), keep it here + * to maintain the forward compatibility. + * + * @param rdev Pointer to the rpmsg device. + * + * @return Next available buffer size for text, negative value for failure. + */ +static inline int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev) +{ + return rpmsg_virtio_get_tx_buffer_size(rdev); +} /** * @brief Initialize rpmsg virtio device diff --git a/open-amp/lib/include/openamp/virtio.h b/open-amp/lib/include/openamp/virtio.h index 9febd1e..c4d4927 100644 --- a/open-amp/lib/include/openamp/virtio.h +++ b/open-amp/lib/include/openamp/virtio.h @@ -70,29 +70,34 @@ extern "C" { #define VIRTIO_DEV_DRIVER 0UL #define VIRTIO_DEV_DEVICE 1UL -#define VIRTIO_DEV_MASTER deprecated_virtio_dev_master() -#define VIRTIO_DEV_SLAVE deprecated_virtio_dev_slave() - -__deprecated static inline int deprecated_virtio_dev_master(void) -{ - /* "VIRTIO_DEV_MASTER is deprecated, please use VIRTIO_DEV_DRIVER" */ - return VIRTIO_DEV_DRIVER; -} - -__deprecated static inline int deprecated_virtio_dev_slave(void) -{ - /* "VIRTIO_DEV_SLAVE is deprecated, please use VIRTIO_DEV_DEVICE" */ - return VIRTIO_DEV_DEVICE; -} - -#ifdef VIRTIO_MASTER_ONLY -#define VIRTIO_DRIVER_ONLY -#warning "VIRTIO_MASTER_ONLY is deprecated, please use VIRTIO_DRIVER_ONLY" +#ifdef VIRTIO_DRIVER_ONLY +#warning "VIRTIO_DRIVER_ONLY is deprecated, please use VIRTIO_DEVICE_SUPPORT=0" +#define VIRTIO_DRIVER_SUPPORT 1 +#define VIRTIO_DEVICE_SUPPORT 0 +#endif /* VIRTIO_DRIVER_ONLY */ + +#ifdef VIRTIO_DEVICE_ONLY +#warning "VIRTIO_DEVICE_ONLY is deprecated, please use VIRTIO_DRIVER_SUPPORT=0" +#define VIRTIO_DRIVER_SUPPORT 0 +#define VIRTIO_DEVICE_SUPPORT 1 +#endif /* VIRTIO_DEVICE_ONLY */ + +#define VIRTIO_ENABLED(option) (option == 1) + +#ifdef VIRTIO_DRIVER_SUPPORT +#define VIRTIO_ROLE_IS_DRIVER(vdev) \ + (VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) && (vdev->role) == VIRTIO_DEV_DRIVER) +#else +/* Default definition without code size optimization */ +#define VIRTIO_ROLE_IS_DRIVER(vdev) (vdev->role == VIRTIO_DEV_DRIVER) #endif -#ifdef VIRTIO_SLAVE_ONLY -#define VIRTIO_DEVICE_ONLY -#warning "VIRTIO_SLAVE_ONLY is deprecated, please use VIRTIO_DEVICE_ONLY" +#ifdef VIRTIO_DEVICE_SUPPORT +#define VIRTIO_ROLE_IS_DEVICE(vdev) \ + (VIRTIO_ENABLED(VIRTIO_DEVICE_SUPPORT) && (vdev->role) == VIRTIO_DEV_DEVICE) +#else +/* Default definition without code size optimization */ +#define VIRTIO_ROLE_IS_DEVICE(vdev) (vdev->role == VIRTIO_DEV_DEVICE) #endif /** @brief Virtio device identifier. */ @@ -246,11 +251,11 @@ struct virtio_dispatch { /** Get the feature exposed by the virtio device. */ uint32_t (*get_features)(struct virtio_device *dev); - /** Set the supported feature (virtio driver only). */ + /** Set the supported `feature` (virtio driver only). */ void (*set_features)(struct virtio_device *dev, uint32_t feature); /** - * Set the supported feature negotiate between the \ref features parameter and features + * Set the supported features negotiate between the `features` parameter and features * supported by the device (virtio driver only). */ uint32_t (*negotiate_features)(struct virtio_device *dev, @@ -310,7 +315,7 @@ static inline void virtio_delete_virtqueues(struct virtio_device *vdev) /** * @brief Get device ID. * - * @param dev Pointer to device structure. + * @param vdev Pointer to device structure. * * @return Device ID value. */ @@ -324,7 +329,7 @@ static inline uint32_t virtio_get_devid(const struct virtio_device *vdev) /** * @brief Retrieve device status. * - * @param dev Pointer to device structure. + * @param vdev Pointer to device structure. * @param status Pointer to the virtio device status. * * @return 0 on success, otherwise error code. @@ -344,7 +349,7 @@ static inline int virtio_get_status(struct virtio_device *vdev, uint8_t *status) /** * @brief Set device status. * - * @param dev Pointer to device structure. + * @param vdev Pointer to device structure. * @param status Value to be set as device status. * * @return 0 on success, otherwise error code. @@ -364,7 +369,7 @@ static inline int virtio_set_status(struct virtio_device *vdev, uint8_t status) /** * @brief Retrieve configuration data from the device. * - * @param dev Pointer to device structure. + * @param vdev Pointer to device structure. * @param offset Offset of the data within the configuration area. * @param dst Address of the buffer that will hold the data. * @param len Length of the data to be retrieved. @@ -387,7 +392,7 @@ static inline int virtio_read_config(struct virtio_device *vdev, /** * @brief Write configuration data to the device. * - * @param dev Pointer to device structure. + * @param vdev Pointer to device structure. * @param offset Offset of the data within the configuration area. * @param src Address of the buffer that holds the data to write. * @param len Length of the data to be written. @@ -410,7 +415,7 @@ static inline int virtio_write_config(struct virtio_device *vdev, /** * @brief Get the virtio device features. * - * @param dev Pointer to device structure. + * @param vdev Pointer to device structure. * @param features Pointer to features supported by both the driver and * the device as a bitfield. * @@ -432,7 +437,7 @@ static inline int virtio_get_features(struct virtio_device *vdev, /** * @brief Set features supported by the VIRTIO driver. * - * @param dev Pointer to device structure. + * @param vdev Pointer to device structure. * @param features Features supported by the driver as a bitfield. * * @return 0 on success, otherwise error code. @@ -453,7 +458,7 @@ static inline int virtio_set_features(struct virtio_device *vdev, /** * @brief Negotiate features between virtio device and driver. * - * @param dev Pointer to device structure. + * @param vdev Pointer to device structure. * @param features Supported features. * @param final_features Pointer to the final features after negotiate. * diff --git a/open-amp/lib/include/openamp/virtio_mmio.h b/open-amp/lib/include/openamp/virtio_mmio.h index db678f6..6ed419c 100644 --- a/open-amp/lib/include/openamp/virtio_mmio.h +++ b/open-amp/lib/include/openamp/virtio_mmio.h @@ -170,7 +170,7 @@ struct virtio_mmio_device { /** * @brief Register a VIRTIO device with the VIRTIO stack. * - * @param dev Pointer to device structure. + * @param vdev Pointer to device structure. * @param vq_num Number of virtqueues the device uses. * @param vqs Array of pointers to vthe virtqueues used by the device. */ @@ -179,11 +179,12 @@ void virtio_mmio_register_device(struct virtio_device *vdev, int vq_num, struct /** * @brief Setup a virtqueue structure. * - * @param dev Pointer to device structure. + * @param vdev Pointer to device structure. * @param idx Index of the virtqueue. * @param vq Pointer to virtqueue structure. * @param cb Pointer to virtqueue callback. Can be NULL. * @param cb_arg Argument for the virtqueue callback. + * @param vq_name Name of the virtqueue. * * @return pointer to virtqueue structure. */ @@ -197,10 +198,10 @@ struct virtqueue *virtio_mmio_setup_virtqueue(struct virtio_device *vdev, /** * @brief VIRTIO MMIO device initialization. * - * @param vmdev Pointer to virtio_mmio_device structure. + * @param vmdev Pointer to virtio_mmio_device structure. * @param virt_mem_ptr Guest virtio (shared) memory base address (virtual). * @param cfg_mem_ptr Virtio device configuration memory base address (virtual). - * @param user_data Pointer to custom user data. + * @param user_data Pointer to custom user data. * * @return int 0 for success. */ diff --git a/open-amp/lib/include/openamp/virtqueue.h b/open-amp/lib/include/openamp/virtqueue.h index 1a9d2e8..8194398 100644 --- a/open-amp/lib/include/openamp/virtqueue.h +++ b/open-amp/lib/include/openamp/virtqueue.h @@ -114,10 +114,10 @@ struct virtqueue { uint16_t vq_queued_cnt; /** - * Metal I/O region of the vrings and buffers. + * Metal I/O region of the buffers. * This structure is used for conversion between virtual and physical addresses. */ - void *shm_io; + struct metal_io_region *shm_io; /** * Head of the free chain in the descriptor table. If there are no free descriptors, diff --git a/open-amp/lib/remoteproc/elf_loader.c b/open-amp/lib/remoteproc/elf_loader.c index c90b8d4..c0eb116 100644 --- a/open-amp/lib/remoteproc/elf_loader.c +++ b/open-amp/lib/remoteproc/elf_loader.c @@ -368,7 +368,7 @@ static const void *elf_next_load_segment(void *elf_info, int *nseg, if (!phdr) return NULL; elf_parse_segment(elf_info, phdr, &p_type, noffset, - da, NULL, nfsize, nmsize); + NULL, da, nfsize, nmsize); *nseg = *nseg + 1; } return phdr; @@ -571,20 +571,25 @@ int elf_load(struct remoteproc *rproc, nsegment = *load_state & ELF_NEXT_SEGMENT_MASK; phdr = elf_next_load_segment(*img_info, &nsegment, da, noffset, &nsize, &nsegmsize); - if (!phdr) { - metal_log(METAL_LOG_DEBUG, "cannot find more segment\r\n"); - *load_state = (*load_state & (~ELF_NEXT_SEGMENT_MASK)) | - (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 (phdr) { + *nlen = nsize; + *nmemsize = nsegmsize; + metal_log(METAL_LOG_DEBUG, "segment: %d, total segs %d\r\n", + nsegment, phnums); + } + if (nsegment == phnums) { - *load_state = (*load_state & (~RPROC_LOADER_MASK)) | + if (phdr) { + *load_state = (*load_state & (~RPROC_LOADER_MASK)) | RPROC_LOADER_POST_DATA_LOAD; + } else { + metal_log(METAL_LOG_DEBUG, "no more segment to load\r\n"); + *load_state = (*load_state & (~RPROC_LOADER_MASK)) | + RPROC_LOADER_LOAD_COMPLETE; + *da = RPROC_LOAD_ANYADDR; + } } *load_state = (*load_state & (~ELF_NEXT_SEGMENT_MASK)) | (nsegment & ELF_NEXT_SEGMENT_MASK); diff --git a/open-amp/lib/remoteproc/remoteproc.c b/open-amp/lib/remoteproc/remoteproc.c index ad16a2d..eef3197 100644 --- a/open-amp/lib/remoteproc/remoteproc.c +++ b/open-amp/lib/remoteproc/remoteproc.c @@ -13,7 +13,8 @@ #include #include #include -#include + +#include "rsc_table_parser.h" /****************************************************************************** * static functions @@ -112,28 +113,27 @@ static void *remoteproc_get_rsc_table(struct remoteproc *rproc, * the caller should be responsible to release the memory */ rsc_table = metal_allocate_memory(len); - if (!rsc_table) { - return RPROC_ERR_PTR(-RPROC_ENOMEM); - } + if (!rsc_table) + return NULL; + ret = store_ops->load(store, offset, len, &img_data, RPROC_LOAD_ANYADDR, NULL, 1); if (ret < 0 || ret < (int)len || !img_data) { metal_log(METAL_LOG_ERROR, "get rsc failed: 0x%llx, 0x%llx\r\n", offset, len); - ret = -RPROC_EINVAL; goto error; } memcpy(rsc_table, img_data, len); ret = handle_rsc_table(rproc, rsc_table, len, NULL); - if (ret < 0) { + if (ret < 0) goto error; - } + return rsc_table; error: metal_free_memory(rsc_table); - return RPROC_ERR_PTR(ret); + return NULL; } static int remoteproc_parse_rsc_table(struct remoteproc *rproc, @@ -179,10 +179,13 @@ struct remoteproc *remoteproc_init(struct remoteproc *rproc, memset(rproc, 0, sizeof(*rproc)); rproc->state = RPROC_OFFLINE; + rproc->ops = ops; + rproc->priv = priv; metal_mutex_init(&rproc->lock); metal_list_init(&rproc->mems); metal_list_init(&rproc->vdevs); - rproc = ops->init(rproc, ops, priv); + if (ops->init) + rproc = ops->init(rproc, ops, priv); return rproc; } @@ -256,6 +259,7 @@ int remoteproc_stop(struct remoteproc *rproc) if (rproc->ops->stop) ret = rproc->ops->stop(rproc); rproc->state = RPROC_STOPPED; + rproc->bitmap = 0; } else { ret = 0; } @@ -289,6 +293,29 @@ int remoteproc_shutdown(struct remoteproc *rproc) return ret; } +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 || !io || size == 0) + 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; +} + +void remoteproc_add_mem(struct remoteproc *rproc, struct remoteproc_mem *mem) +{ + if (!rproc || !mem) + return; + metal_list_add_tail(&rproc->mems, &mem->node); +} + struct metal_io_region * remoteproc_get_io_with_name(struct remoteproc *rproc, const char *name) @@ -915,12 +942,14 @@ remoteproc_create_virtio(struct remoteproc *rproc, unsigned int num_vrings, i; struct metal_list *node; -#ifdef VIRTIO_DRIVER_ONLY - role = (role != VIRTIO_DEV_DRIVER) ? 0xFFFFFFFFUL : role; +#if !VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) + if (role == VIRTIO_DEV_DRIVER) + return NULL; #endif -#ifdef VIRTIO_DEVICE_ONLY - role = (role != VIRTIO_DEV_DEVICE) ? 0xFFFFFFFFUL : role; +#if !VIRTIO_ENABLED(VIRTIO_DEVICE_SUPPORT) + if (role == VIRTIO_DEV_DEVICE) + return NULL; #endif if (!rproc || (role != VIRTIO_DEV_DEVICE && role != VIRTIO_DEV_DRIVER)) diff --git a/open-amp/lib/remoteproc/remoteproc_virtio.c b/open-amp/lib/remoteproc/remoteproc_virtio.c index 7ef1064..ef39c49 100644 --- a/open-amp/lib/remoteproc/remoteproc_virtio.c +++ b/open-amp/lib/remoteproc/remoteproc_virtio.c @@ -16,6 +16,88 @@ #include #include +static void rproc_virtio_delete_virtqueues(struct virtio_device *vdev) +{ + struct virtio_vring_info *vring_info; + unsigned int i; + + if (!vdev->vrings_info) + return; + + for (i = 0; i < vdev->vrings_num; i++) { + vring_info = &vdev->vrings_info[i]; + if (vring_info->vq) + virtqueue_free(vring_info->vq); + } +} + +static int rproc_virtio_create_virtqueue(struct virtio_device *vdev, + unsigned int flags, + unsigned int idx, + const char *name, + vq_callback callback) +{ + struct virtio_vring_info *vring_info; + struct vring_alloc_info *vring_alloc; + int ret; + (void)flags; + + /* Get the vring information */ + vring_info = &vdev->vrings_info[idx]; + vring_alloc = &vring_info->info; + + /* Fail if the virtqueue has already been created */ + if (vring_info->vq) + return ERROR_VQUEUE_INVLD_PARAM; + + /* Alloc the virtqueue and init it */ + vring_info->vq = virtqueue_allocate(vring_alloc->num_descs); + if (!vring_info->vq) + return ERROR_NO_MEM; + + if (VIRTIO_ROLE_IS_DRIVER(vdev)) { + size_t offset = metal_io_virt_to_offset(vring_info->io, vring_alloc->vaddr); + size_t size = vring_size(vring_alloc->num_descs, vring_alloc->align); + + metal_io_block_set(vring_info->io, offset, 0, size); + } + + ret = virtqueue_create(vdev, idx, name, vring_alloc, callback, + vdev->func->notify, vring_info->vq); + if (ret) + return ret; + + return 0; +} + +static int rproc_virtio_create_virtqueues(struct virtio_device *vdev, + unsigned int flags, + unsigned int nvqs, + const char *names[], + vq_callback callbacks[], + void *callback_args[]) +{ + unsigned int i; + int ret; + (void)callback_args; + + /* Check virtqueue numbers and the vrings_info */ + if (nvqs > vdev->vrings_num || !vdev || !vdev->vrings_info) + return ERROR_VQUEUE_INVLD_PARAM; + + /* set the notification id for vrings */ + for (i = 0; i < nvqs; i++) { + ret = rproc_virtio_create_virtqueue(vdev, flags, i, names[i], callbacks[i]); + if (ret) + goto err; + } + return 0; + +err: + rproc_virtio_delete_virtqueues(vdev); + return ret; +} + static void rproc_virtio_virtqueue_notify(struct virtqueue *vq) { struct remoteproc_virtio *rpvdev; @@ -46,7 +128,7 @@ static unsigned char rproc_virtio_get_status(struct virtio_device *vdev) return status; } -#ifndef VIRTIO_DEVICE_ONLY +#if VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) static void rproc_virtio_set_status(struct virtio_device *vdev, unsigned char status) { @@ -101,7 +183,7 @@ static uint32_t rproc_virtio_get_features(struct virtio_device *vdev) return dfeatures & gfeatures; } -#ifndef VIRTIO_DEVICE_ONLY +#if VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) static void rproc_virtio_set_features(struct virtio_device *vdev, uint32_t features) { @@ -151,7 +233,7 @@ static void rproc_virtio_read_config(struct virtio_device *vdev, } } -#ifndef VIRTIO_DEVICE_ONLY +#if VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) static void rproc_virtio_write_config(struct virtio_device *vdev, uint32_t offset, void *src, int length) { @@ -183,11 +265,13 @@ static void rproc_virtio_reset_device(struct virtio_device *vdev) #endif static const struct virtio_dispatch remoteproc_virtio_dispatch_funcs = { + .create_virtqueues = rproc_virtio_create_virtqueues, + .delete_virtqueues = rproc_virtio_delete_virtqueues, .get_status = rproc_virtio_get_status, .get_features = rproc_virtio_get_features, .read_config = rproc_virtio_read_config, .notify = rproc_virtio_virtqueue_notify, -#ifndef VIRTIO_DEVICE_ONLY +#if VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) /* * We suppose here that the vdev is in a shared memory so that can * be access only by one core: the host. In this case salve core has @@ -213,53 +297,36 @@ rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, 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; + goto err; 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; -#ifndef VIRTIO_DEVICE_ONLY - struct fw_rsc_vdev_vring *vring_rsc; -#endif - unsigned int num_extra_desc = 0; - -#ifndef VIRTIO_DEVICE_ONLY - vring_rsc = &vdev_rsc->vring[i]; - if (role == VIRTIO_DEV_DRIVER) { - num_extra_desc = vring_rsc->num; - } -#endif - vq = virtqueue_allocate(num_extra_desc); - if (!vq) - goto err1; - vrings_info[i].vq = vq; - } + memset(vrings_info, 0, sizeof(*vrings_info) * num_vrings); + /* Initialize the remoteproc virtio */ 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; + /* Initialize the virtio device */ + vdev = &rpvdev->vdev; + vdev->vrings_info = vrings_info; vdev->notifyid = notifyid; + vdev->id.device = vdev_rsc->id; vdev->role = role; vdev->reset_cb = rst_cb; vdev->vrings_num = num_vrings; vdev->func = &remoteproc_virtio_dispatch_funcs; -#ifndef VIRTIO_DEVICE_ONLY +#if VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) if (role == VIRTIO_DEV_DRIVER) { uint32_t dfeatures = rproc_virtio_get_dfeatures(vdev); /* Assume the virtio driver support all remote features */ @@ -268,14 +335,7 @@ rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, #endif 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: +err: metal_free_memory(rpvdev); return NULL; } @@ -283,18 +343,10 @@ rproc_virtio_create_vdev(unsigned int role, unsigned int notifyid, 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); - } if (vdev->vrings_info) metal_free_memory(vdev->vrings_info); metal_free_memory(rpvdev); @@ -348,15 +400,14 @@ void rproc_virtio_wait_remote_ready(struct virtio_device *vdev) { uint8_t status; -#ifndef VIRTIO_DEVICE_ONLY /* * No status available for remote. As virtio driver has not to wait * remote action, we can return. Behavior should be updated * in future if a remote status is added. */ - if (vdev->role == VIRTIO_DEV_DRIVER) + if (VIRTIO_ROLE_IS_DRIVER(vdev)) return; -#endif + while (1) { status = rproc_virtio_get_status(vdev); if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK) diff --git a/open-amp/lib/remoteproc/rsc_table_parser.c b/open-amp/lib/remoteproc/rsc_table_parser.c index c099f84..441b32d 100644 --- a/open-amp/lib/remoteproc/rsc_table_parser.c +++ b/open-amp/lib/remoteproc/rsc_table_parser.c @@ -8,75 +8,22 @@ #include #include -#include -static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc); +#include "rsc_table_parser.h" -/* Resources handler */ -static const 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 */ -}; - -int handle_rsc_table(struct remoteproc *rproc, - struct resource_table *rsc_table, size_t size, - struct metal_io_region *io) -{ - struct fw_rsc_hdr *hdr; - uint32_t rsc_type; - unsigned int idx, offset; - int status = 0; - - /* Validate rsc table header fields */ - - /* Minimum rsc table size */ - if (sizeof(struct resource_table) > 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]); +#define RSC_TAB_SUPPORTED_VERSION 1 - if (offset > 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++) { - hdr = (void *)((char *)rsc_table + rsc_table->offset[idx]); - if (io && metal_io_virt_to_offset(io, hdr) == METAL_BAD_OFFSET) - return -RPROC_ERR_RSC_TAB_TRUNC; - rsc_type = hdr->type; - if (rsc_type < RSC_LAST) - status = rsc_handler_table[rsc_type](rproc, hdr); - else if (rsc_type >= RSC_VENDOR_START && - rsc_type <= RSC_VENDOR_END) - status = handle_vendor_rsc(rproc, hdr); - if (status == -RPROC_ERR_RSC_TAB_NS) { - status = 0; - continue; - } else if (status) { - break; - } - } - - return status; -} - -int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc) +/** + * @internal + * + * @brief Carveout resource handler. + * + * @param rproc Pointer to remote remoteproc + * @param rsc Pointer to carveout resource + * + * @return 0 for success, or negative value for failure + */ +static int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc) { struct fw_rsc_carveout *carve_rsc = rsc; metal_phys_addr_t da; @@ -102,18 +49,29 @@ int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc) return -RPROC_EINVAL; } -int handle_vendor_rsc(struct remoteproc *rproc, void *rsc) +/** + * @internal + * + * @brief Trace resource handler. + * + * @param rproc Pointer to remote remoteproc + * @param rsc Pointer to trace resource + * + * @return No service error + */ +static int handle_trace_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; + struct fw_rsc_trace *vdev_rsc = rsc; + (void)rproc; + + if (vdev_rsc->da != FW_RSC_U32_ADDR_ANY && vdev_rsc->len != 0) + return 0; + /* FIXME: The host should allocated a memory used by remote */ - return rproc->ops->handle_rsc(rproc, rsc, len); - } return -RPROC_ERR_RSC_TAB_NS; } -int handle_vdev_rsc(struct remoteproc *rproc, void *rsc) +static int handle_vdev_rsc(struct remoteproc *rproc, void *rsc) { struct fw_rsc_vdev *vdev_rsc = rsc; int i, num_vrings; @@ -157,15 +115,14 @@ int handle_vdev_rsc(struct remoteproc *rproc, void *rsc) return -RPROC_ERR_RSC_TAB_NP; } -int handle_trace_rsc(struct remoteproc *rproc, void *rsc) +static int handle_vendor_rsc(struct remoteproc *rproc, void *rsc) { - struct fw_rsc_trace *vdev_rsc = rsc; - (void)rproc; - - if (vdev_rsc->da != FW_RSC_U32_ADDR_ANY && vdev_rsc->len != 0) - return 0; - /* FIXME: The host should allocated a memory used by remote */ + 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; } @@ -187,6 +144,73 @@ static int handle_dummy_rsc(struct remoteproc *rproc, void *rsc) return -RPROC_ERR_RSC_TAB_NS; } +/* Standard control request handling. */ +typedef int (*rsc_handler)(struct remoteproc *rproc, void *rsc); + +/* Resources handler */ +static const 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 */ +}; + +int handle_rsc_table(struct remoteproc *rproc, + struct resource_table *rsc_table, size_t size, + struct metal_io_region *io) +{ + struct fw_rsc_hdr *hdr; + uint32_t rsc_type; + unsigned int idx, offset; + int status = 0; + + /* Validate rsc table header fields */ + + /* Minimum rsc table size */ + if (sizeof(struct resource_table) > 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 > 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++) { + hdr = (void *)((char *)rsc_table + rsc_table->offset[idx]); + if (io && metal_io_virt_to_offset(io, hdr) == METAL_BAD_OFFSET) + return -RPROC_ERR_RSC_TAB_TRUNC; + rsc_type = hdr->type; + if (rsc_type < RSC_LAST) + status = rsc_handler_table[rsc_type](rproc, hdr); + else if (rsc_type >= RSC_VENDOR_START && + rsc_type <= RSC_VENDOR_END) + status = handle_vendor_rsc(rproc, hdr); + if (status == -RPROC_ERR_RSC_TAB_NS) { + status = 0; + continue; + } else if (status) { + break; + } + } + + return status; +} + size_t find_rsc(void *rsc_table, unsigned int rsc_type, unsigned int index) { struct resource_table *r_table = rsc_table; diff --git a/open-amp/lib/include/openamp/rsc_table_parser.h b/open-amp/lib/remoteproc/rsc_table_parser.h similarity index 60% rename from open-amp/lib/include/openamp/rsc_table_parser.h rename to open-amp/lib/remoteproc/rsc_table_parser.h index d86da74..46f7dd8 100644 --- a/open-amp/lib/include/openamp/rsc_table_parser.h +++ b/open-amp/lib/remoteproc/rsc_table_parser.h @@ -14,11 +14,6 @@ extern "C" { #endif -#define RSC_TAB_SUPPORTED_VERSION 1 - -/* Standard control request handling. */ -typedef int (*rsc_handler)(struct remoteproc *rproc, void *rsc); - /** * @internal * @@ -37,32 +32,6 @@ int handle_rsc_table(struct remoteproc *rproc, struct resource_table *rsc_table, size_t len, struct metal_io_region *io); -/** - * @internal - * - * @brief Carveout resource handler. - * - * @param rproc Pointer to remote remoteproc - * @param rsc Pointer to carveout resource - * - * @return 0 for success, or negative value for failure - */ -int handle_carve_out_rsc(struct remoteproc *rproc, void *rsc); - -/** - * @internal - * - * @brief Trace resource handler. - * - * @param rproc Pointer to remote remoteproc - * @param rsc Pointer to trace resource - * - * @return No service error - */ -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); - /** * @internal * diff --git a/open-amp/lib/rpmsg/rpmsg.c b/open-amp/lib/rpmsg/rpmsg.c index 5a9237f..39774bc 100644 --- a/open-amp/lib/rpmsg/rpmsg.c +++ b/open-amp/lib/rpmsg/rpmsg.c @@ -24,12 +24,12 @@ * * @return A unique address */ -static uint32_t rpmsg_get_address(unsigned long *bitmap, int size) +static uint32_t rpmsg_get_address(unsigned long *bitmap, unsigned int start, int size) { unsigned int addr = RPMSG_ADDR_ANY; unsigned int nextbit; - nextbit = metal_bitmap_next_clear_bit(bitmap, 0, size); + nextbit = metal_bitmap_next_clear_bit(bitmap, start, size); if (nextbit < (uint32_t)size) { addr = RPMSG_RESERVED_ADDRESSES + nextbit; metal_bitmap_set_bit(bitmap, nextbit); @@ -97,6 +97,25 @@ static int rpmsg_set_address(unsigned long *bitmap, int size, int addr) } } +void rpmsg_ept_incref(struct rpmsg_endpoint *ept) +{ + if (ept) + ept->refcnt++; +} + +void rpmsg_ept_decref(struct rpmsg_endpoint *ept) +{ + if (ept) { + ept->refcnt--; + if (!ept->refcnt) { + if (ept->release_cb) + ept->release_cb(ept); + else + ept->rdev = NULL; + } + } +} + int rpmsg_send_offchannel_raw(struct rpmsg_endpoint *ept, uint32_t src, uint32_t dst, const void *data, int len, int wait) @@ -189,6 +208,36 @@ void *rpmsg_get_tx_payload_buffer(struct rpmsg_endpoint *ept, return NULL; } +int rpmsg_get_tx_buffer_size(struct rpmsg_endpoint *ept) +{ + struct rpmsg_device *rdev; + + if (!ept || !ept->rdev) + return RPMSG_ERR_PARAM; + + rdev = ept->rdev; + + if (rdev->ops.get_tx_buffer_size) + return rdev->ops.get_tx_buffer_size(rdev); + + return RPMSG_EOPNOTSUPP; +} + +int rpmsg_get_rx_buffer_size(struct rpmsg_endpoint *ept) +{ + struct rpmsg_device *rdev; + + if (!ept || !ept->rdev) + return RPMSG_ERR_PARAM; + + rdev = ept->rdev; + + if (rdev->ops.get_rx_buffer_size) + return rdev->ops.get_rx_buffer_size(rdev); + + return RPMSG_EOPNOTSUPP; +} + int rpmsg_send_offchannel_nocopy(struct rpmsg_endpoint *ept, uint32_t src, uint32_t dst, const void *data, int len) { @@ -245,7 +294,7 @@ static void rpmsg_unregister_endpoint(struct rpmsg_endpoint *ept) rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, ept->addr); metal_list_del(&ept->node); - ept->rdev = NULL; + rpmsg_ept_decref(ept); metal_mutex_release(&rdev->lock); } @@ -254,13 +303,15 @@ void rpmsg_register_endpoint(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_ns_unbind_cb ns_unbind_cb, void *priv) { strncpy(ept->name, name ? name : "", sizeof(ept->name)); + ept->refcnt = 1; ept->addr = src; ept->dest_addr = dest; ept->cb = cb; ept->ns_unbind_cb = ns_unbind_cb; + ept->priv = priv; ept->rdev = rdev; metal_list_add_tail(&rdev->endpoints, &ept->node); } @@ -277,11 +328,12 @@ int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev, metal_mutex_acquire(&rdev->lock); if (src == RPMSG_ADDR_ANY) { - addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE); + addr = rpmsg_get_address(rdev->bitmap, rdev->bitnext, RPMSG_ADDR_BMP_SIZE); if (addr == RPMSG_ADDR_ANY) { status = RPMSG_ERR_ADDR; goto ret_status; } + rdev->bitnext = (addr + 1) % RPMSG_ADDR_BMP_SIZE; } else if (src >= RPMSG_RESERVED_ADDRESSES) { status = rpmsg_is_address_set(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, src); @@ -302,7 +354,7 @@ int rpmsg_create_ept(struct rpmsg_endpoint *ept, struct rpmsg_device *rdev, */ } - rpmsg_register_endpoint(rdev, ept, name, addr, dest, cb, unbind_cb); + rpmsg_register_endpoint(rdev, ept, name, addr, dest, cb, unbind_cb, ept->priv); metal_mutex_release(&rdev->lock); /* Send NS announcement to remote processor */ diff --git a/open-amp/lib/rpmsg/rpmsg_internal.h b/open-amp/lib/rpmsg/rpmsg_internal.h index 6721ecf..27b0f0d 100644 --- a/open-amp/lib/rpmsg/rpmsg_internal.h +++ b/open-amp/lib/rpmsg/rpmsg_internal.h @@ -28,22 +28,21 @@ extern "C" { #define RPMSG_ASSERT(_exp, _msg) metal_assert(_exp) #endif -#define RPMSG_BUF_HELD (1U << 31) /* Flag to suggest to hold the buffer */ +/* Mask to get the rpmsg buffer held counter from rpmsg_hdr reserved field */ +#define RPMSG_BUF_HELD_SHIFT 16 +#define RPMSG_BUF_HELD_MASK (0xFFFFU << RPMSG_BUF_HELD_SHIFT) #define RPMSG_LOCATE_HDR(p) \ ((struct rpmsg_hdr *)((unsigned char *)(p) - sizeof(struct rpmsg_hdr))) #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. + * @brief dynamic name service announcement flags */ enum rpmsg_ns_flags { + /** A new remote service was just created */ RPMSG_NS_CREATE = 0, + /** A known remote service was just destroyed */ RPMSG_NS_DESTROY = 1, }; @@ -101,7 +100,7 @@ void rpmsg_register_endpoint(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_ns_unbind_cb ns_unbind_cb, void *priv); static inline struct rpmsg_endpoint * rpmsg_get_ept_from_addr(struct rpmsg_device *rdev, uint32_t addr) @@ -109,6 +108,31 @@ rpmsg_get_ept_from_addr(struct rpmsg_device *rdev, uint32_t addr) return rpmsg_get_endpoint(rdev, NULL, addr, RPMSG_ADDR_ANY); } +/** + * @internal + * + * @brief Increase the endpoint reference count + * + * This function is used to avoid calling ept_cb after release lock causes race condition + * it should be called under lock protection. + * + * @param ept pointer to rpmsg endpoint + * + */ +void rpmsg_ept_incref(struct rpmsg_endpoint *ept); + +/** + * @internal + * + * @brief Decrease the end point reference count + * + * This function is used to avoid calling ept_cb after release lock causes race condition + * it should be called under lock protection. + * + * @param ept pointer to rpmsg endpoint + */ +void rpmsg_ept_decref(struct rpmsg_endpoint *ept); + #if defined __cplusplus } #endif diff --git a/open-amp/lib/rpmsg/rpmsg_virtio.c b/open-amp/lib/rpmsg/rpmsg_virtio.c index ea4cc0d..7baaedd 100644 --- a/open-amp/lib/rpmsg/rpmsg_virtio.c +++ b/open-amp/lib/rpmsg/rpmsg_virtio.c @@ -24,14 +24,33 @@ /* Time to wait - In multiple of 1 msecs. */ #define RPMSG_TICKS_PER_INTERVAL 1000 +/* + * Get the buffer held counter value. + * If 0 the buffer can be released + */ +#define RPMSG_BUF_HELD_COUNTER(rp_hdr) \ + (((rp_hdr)->reserved & RPMSG_BUF_HELD_MASK) >> RPMSG_BUF_HELD_SHIFT) + +/* Increase buffer held counter */ +#define RPMSG_BUF_HELD_INC(rp_hdr) \ + ((rp_hdr)->reserved += 1 << RPMSG_BUF_HELD_SHIFT) + +/* Decrease buffer held counter */ +#define RPMSG_BUF_HELD_DEC(rp_hdr) \ + ((rp_hdr)->reserved -= 1 << RPMSG_BUF_HELD_SHIFT) + +/* Get the buffer index */ +#define RPMSG_BUF_INDEX(rphdr) \ + ((uint16_t)((rp_hdr)->reserved & ~RPMSG_BUF_HELD_MASK)) + /** * struct vbuff_reclaimer_t - vring buffer recycler * * This structure is used by the rpmsg virtio to store unused virtio buffer, as the * virtqueue structure has been already updated and memory allocated. * - * @node: node in reclaimer list. - * @idx: virtio descriptor index containing the buffer information. + * @param node node in reclaimer list. + * @param idx virtio descriptor index containing the buffer information. */ struct vbuff_reclaimer_t { struct metal_list node; @@ -39,7 +58,7 @@ struct vbuff_reclaimer_t { }; /* Default configuration */ -#ifndef VIRTIO_DEVICE_ONLY +#if VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) #define RPMSG_VIRTIO_DEFAULT_CONFIG \ (&(const struct rpmsg_virtio_config) { \ .h2r_buf_size = RPMSG_BUFFER_SIZE, \ @@ -50,7 +69,7 @@ struct vbuff_reclaimer_t { #define RPMSG_VIRTIO_DEFAULT_CONFIG NULL #endif -#ifndef VIRTIO_DEVICE_ONLY +#if VIRTIO_ENABLED(VIRTIO_DRIVER_SUPPORT) metal_weak void * rpmsg_virtio_shm_pool_get_buffer(struct rpmsg_virtio_shm_pool *shpool, size_t size) @@ -64,7 +83,7 @@ rpmsg_virtio_shm_pool_get_buffer(struct rpmsg_virtio_shm_pool *shpool, return buffer; } -#endif /*!VIRTIO_DEVICE_ONLY*/ +#endif void rpmsg_virtio_init_shm_pool(struct rpmsg_virtio_shm_pool *shpool, void *shb, size_t size) @@ -90,28 +109,26 @@ static void rpmsg_virtio_return_buffer(struct rpmsg_virtio_device *rvdev, void *buffer, uint32_t len, uint16_t idx) { - unsigned int role = rpmsg_virtio_get_role(rvdev); + int ret; BUFFER_INVALIDATE(buffer, len); -#ifndef VIRTIO_DEVICE_ONLY - if (role == RPMSG_HOST) { + if (VIRTIO_ROLE_IS_DRIVER(rvdev->vdev)) { struct virtqueue_buf vqbuf; (void)idx; /* Initialize buffer node */ vqbuf.buf = buffer; vqbuf.len = len; - virtqueue_add_buffer(rvdev->rvq, &vqbuf, 0, 1, buffer); + ret = virtqueue_add_buffer(rvdev->rvq, &vqbuf, 0, 1, buffer); + RPMSG_ASSERT(ret == VQUEUE_SUCCESS, "add buffer failed\r\n"); } -#endif /*VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - if (role == RPMSG_REMOTE) { + if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) { (void)buffer; - virtqueue_add_consumed_buffer(rvdev->rvq, idx, len); + ret = virtqueue_add_consumed_buffer(rvdev->rvq, idx, len); + RPMSG_ASSERT(ret == VQUEUE_SUCCESS, "add consumed buffer failed\r\n"); } -#endif /*VIRTIO_DRIVER_ONLY*/ } /** @@ -130,12 +147,9 @@ static int rpmsg_virtio_enqueue_buffer(struct rpmsg_virtio_device *rvdev, void *buffer, uint32_t len, uint16_t idx) { - unsigned int role = rpmsg_virtio_get_role(rvdev); - BUFFER_FLUSH(buffer, len); -#ifndef VIRTIO_DEVICE_ONLY - if (role == RPMSG_HOST) { + if (VIRTIO_ROLE_IS_DRIVER(rvdev->vdev)) { struct virtqueue_buf vqbuf; (void)idx; @@ -144,14 +158,12 @@ static int rpmsg_virtio_enqueue_buffer(struct rpmsg_virtio_device *rvdev, vqbuf.len = len; return virtqueue_add_buffer(rvdev->svq, &vqbuf, 1, 0, buffer); } -#endif /*!VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - if (role == RPMSG_REMOTE) { + if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) { (void)buffer; return virtqueue_add_consumed_buffer(rvdev->svq, idx, len); } -#endif /*!VIRTIO_DRIVER_ONLY*/ + return 0; } @@ -169,7 +181,6 @@ static int rpmsg_virtio_enqueue_buffer(struct rpmsg_virtio_device *rvdev, static void *rpmsg_virtio_get_tx_buffer(struct rpmsg_virtio_device *rvdev, uint32_t *len, uint16_t *idx) { - unsigned int role = rpmsg_virtio_get_role(rvdev); struct metal_list *node; struct vbuff_reclaimer_t *r_desc; void *data = NULL; @@ -180,19 +191,13 @@ static void *rpmsg_virtio_get_tx_buffer(struct rpmsg_virtio_device *rvdev, r_desc = metal_container_of(node, struct vbuff_reclaimer_t, node); metal_list_del(node); data = r_desc; + *idx = r_desc->idx; -#ifndef VIRTIO_DEVICE_ONLY - if (role == RPMSG_HOST) + if (VIRTIO_ROLE_IS_DRIVER(rvdev->vdev)) *len = rvdev->config.h2r_buf_size; -#endif /*!VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - if (role == RPMSG_REMOTE) { - *idx = r_desc->idx; + if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) *len = virtqueue_get_buffer_length(rvdev->svq, *idx); - } -#endif /*!VIRTIO_DRIVER_ONLY*/ -#ifndef VIRTIO_DEVICE_ONLY - } else if (role == RPMSG_HOST) { + } else if (VIRTIO_ROLE_IS_DRIVER(rvdev->vdev)) { data = virtqueue_get_buffer(rvdev->svq, len, idx); if (!data && rvdev->svq->vq_free_cnt) { data = rpmsg_virtio_shm_pool_get_buffer(rvdev->shpool, @@ -200,11 +205,8 @@ static void *rpmsg_virtio_get_tx_buffer(struct rpmsg_virtio_device *rvdev, *len = rvdev->config.h2r_buf_size; *idx = 0; } -#endif /*!VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - } else if (role == RPMSG_REMOTE) { + } else if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) { data = virtqueue_get_available_buffer(rvdev->svq, idx, len); -#endif /*!VIRTIO_DRIVER_ONLY*/ } return data; @@ -224,21 +226,16 @@ static void *rpmsg_virtio_get_tx_buffer(struct rpmsg_virtio_device *rvdev, static void *rpmsg_virtio_get_rx_buffer(struct rpmsg_virtio_device *rvdev, uint32_t *len, uint16_t *idx) { - unsigned int role = rpmsg_virtio_get_role(rvdev); void *data = NULL; -#ifndef VIRTIO_DEVICE_ONLY - if (role == RPMSG_HOST) { + if (VIRTIO_ROLE_IS_DRIVER(rvdev->vdev)) { data = virtqueue_get_buffer(rvdev->rvq, len, idx); } -#endif /*!VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - if (role == RPMSG_REMOTE) { + if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) { data = virtqueue_get_available_buffer(rvdev->rvq, idx, len); } -#endif /*!VIRTIO_DRIVER_ONLY*/ /* Invalidate the buffer before returning it */ if (data) @@ -247,82 +244,87 @@ static void *rpmsg_virtio_get_rx_buffer(struct rpmsg_virtio_device *rvdev, return data; } -#ifndef VIRTIO_DRIVER_ONLY -/* - * check if the remote is ready to start RPMsg communication +/** + * @internal + * + * @brief Check if the remote is ready to start RPMsg communication + * + * @param rvdev Pointer to rpmsg_virtio device + * + * @return 0 on success, otherwise error code. */ static int rpmsg_virtio_wait_remote_ready(struct rpmsg_virtio_device *rvdev) { uint8_t status; + int ret; while (1) { - status = rpmsg_virtio_get_status(rvdev); + ret = virtio_get_status(rvdev->vdev, &status); + if (ret) + return ret; /* Busy wait until the remote is ready */ if (status & VIRTIO_CONFIG_STATUS_NEEDS_RESET) { - rpmsg_virtio_set_status(rvdev, 0); + ret = virtio_set_status(rvdev->vdev, 0); + if (ret) + return ret; /* TODO notify remote processor */ } else if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK) { - return true; + return 0; } /* TODO: clarify metal_cpu_yield usage*/ metal_cpu_yield(); } } -#endif /*!VIRTIO_DRIVER_ONLY*/ /** * @internal * - * @brief Returns buffer size available for sending messages. + * @brief Check whether rpmsg buffer needs to be released or not * - * @param rvdev Pointer to rpmsg device + * @param rp_hdr Pointer to rpmsg buffer header * - * @return Buffer size + * @return true indicates this buffer needs to be released */ -static int _rpmsg_virtio_get_buffer_size(struct rpmsg_virtio_device *rvdev) +static bool rpmsg_virtio_buf_held_dec_test(struct rpmsg_hdr *rp_hdr) { - unsigned int role = rpmsg_virtio_get_role(rvdev); - int length = 0; - -#ifndef VIRTIO_DEVICE_ONLY - if (role == RPMSG_HOST) { - /* - * If device role is host then buffers are provided by us, - * so just provide the macro. - */ - length = rvdev->config.h2r_buf_size - sizeof(struct rpmsg_hdr); + /* Check the held counter first */ + if (RPMSG_BUF_HELD_COUNTER(rp_hdr) <= 0) { + metal_err("unexpected buffer held counter\r\n"); + return false; } -#endif /*!VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - if (role == RPMSG_REMOTE) { - /* - * If other core is host 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); - } -#endif /*!VIRTIO_DRIVER_ONLY*/ + /* Decrease the held counter */ + RPMSG_BUF_HELD_DEC(rp_hdr); - if (length <= 0) { - length = RPMSG_ERR_NO_BUFF; - } + /* Check whether to release the buffer */ + if (RPMSG_BUF_HELD_COUNTER(rp_hdr) > 0) + return false; - return length; + return true; } static void rpmsg_virtio_hold_rx_buffer(struct rpmsg_device *rdev, void *rxbuf) { - struct rpmsg_hdr *rp_hdr; + metal_mutex_acquire(&rdev->lock); + RPMSG_BUF_HELD_INC(RPMSG_LOCATE_HDR(rxbuf)); + metal_mutex_release(&rdev->lock); +} - (void)rdev; +static bool rpmsg_virtio_release_rx_buffer_nolock(struct rpmsg_virtio_device *rvdev, + struct rpmsg_hdr *rp_hdr) +{ + uint16_t idx; + uint32_t len; - rp_hdr = RPMSG_LOCATE_HDR(rxbuf); + /* The reserved field contains buffer index */ + idx = RPMSG_BUF_INDEX(rp_hdr); + /* Return buffer on virtqueue. */ + len = virtqueue_get_buffer_length(rvdev->rvq, idx); + rpmsg_virtio_return_buffer(rvdev, rp_hdr, len, idx); + /* Tell peer we returned an rx buffer */ + virtqueue_kick(rvdev->rvq); - /* Set held status to keep buffer */ - rp_hdr->reserved |= RPMSG_BUF_HELD; + return true; } static void rpmsg_virtio_release_rx_buffer(struct rpmsg_device *rdev, @@ -330,28 +332,34 @@ static void rpmsg_virtio_release_rx_buffer(struct rpmsg_device *rdev, { struct rpmsg_virtio_device *rvdev; struct rpmsg_hdr *rp_hdr; - uint16_t idx; - uint32_t len; rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev); rp_hdr = RPMSG_LOCATE_HDR(rxbuf); - /* The reserved field contains buffer index */ - idx = (uint16_t)(rp_hdr->reserved & ~RPMSG_BUF_HELD); metal_mutex_acquire(&rdev->lock); - /* Return buffer on virtqueue. */ - len = virtqueue_get_buffer_length(rvdev->rvq, idx); - rpmsg_virtio_return_buffer(rvdev, rp_hdr, len, idx); - /* Tell peer we return some rx buffers */ - virtqueue_kick(rvdev->rvq); + if (rpmsg_virtio_buf_held_dec_test(rp_hdr)) + rpmsg_virtio_release_rx_buffer_nolock(rvdev, rp_hdr); metal_mutex_release(&rdev->lock); } +static int rpmsg_virtio_notify_wait(struct rpmsg_virtio_device *rvdev, struct virtqueue *vq) +{ + struct virtio_vring_info *vring_info; + + vring_info = &rvdev->vdev->vrings_info[vq->vq_queue_index]; + + if (!rvdev->notify_wait_cb) + return RPMSG_EOPNOTSUPP; + + return rvdev->notify_wait_cb(&rvdev->rdev, vring_info->notifyid); +} + static void *rpmsg_virtio_get_tx_payload_buffer(struct rpmsg_device *rdev, uint32_t *len, int wait) { struct rpmsg_virtio_device *rvdev; struct rpmsg_hdr *rp_hdr; + uint8_t virtio_status; uint16_t idx; int tick_count; int status; @@ -360,8 +368,8 @@ static void *rpmsg_virtio_get_tx_payload_buffer(struct rpmsg_device *rdev, rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev); /* Validate device state */ - status = rpmsg_virtio_get_status(rvdev); - if (!(status & VIRTIO_CONFIG_STATUS_DRIVER_OK)) + status = virtio_get_status(rvdev->vdev, &virtio_status); + if (status || !(virtio_status & VIRTIO_CONFIG_STATUS_DRIVER_OK)) return NULL; if (wait) @@ -376,8 +384,18 @@ static void *rpmsg_virtio_get_tx_payload_buffer(struct rpmsg_device *rdev, metal_mutex_release(&rdev->lock); if (rp_hdr || !tick_count) break; - metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL); - tick_count--; + + /* + * Try to use wait loop implemented in the virtio dispatcher and + * use metal_sleep_usec() method by default. + */ + status = rpmsg_virtio_notify_wait(rvdev, rvdev->rvq); + if (status == RPMSG_EOPNOTSUPP) { + metal_sleep_usec(RPMSG_TICKS_PER_INTERVAL); + tick_count--; + } else if (status == RPMSG_SUCCESS) { + break; + } } if (!rp_hdr) @@ -386,6 +404,9 @@ static void *rpmsg_virtio_get_tx_payload_buffer(struct rpmsg_device *rdev, /* Store the index into the reserved field to be used when sending */ rp_hdr->reserved = idx; + /* Increase the held counter to hold this Tx buffer */ + RPMSG_BUF_HELD_INC(rp_hdr); + /* Actual data buffer size is vring buffer size minus header length */ *len -= sizeof(struct rpmsg_hdr); return RPMSG_LOCATE_DATA(rp_hdr); @@ -425,11 +446,9 @@ static int rpmsg_virtio_send_offchannel_nocopy(struct rpmsg_device *rdev, metal_mutex_acquire(&rdev->lock); -#ifndef VIRTIO_DEVICE_ONLY - if (rpmsg_virtio_get_role(rvdev) == RPMSG_HOST) + if (VIRTIO_ROLE_IS_DRIVER(rvdev->vdev)) buff_len = rvdev->config.h2r_buf_size; else -#endif /*!VIRTIO_DEVICE_ONLY*/ buff_len = virtqueue_get_buffer_length(rvdev->svq, idx); /* Enqueue buffer on virtqueue. */ @@ -449,20 +468,20 @@ static int rpmsg_virtio_release_tx_buffer(struct rpmsg_device *rdev, void *txbuf struct rpmsg_hdr *rp_hdr = RPMSG_LOCATE_HDR(txbuf); void *vbuff = rp_hdr; /* only used to avoid warning on the cast of a packed structure */ struct vbuff_reclaimer_t *r_desc = (struct vbuff_reclaimer_t *)vbuff; - uint16_t idx; - - /* - * Reuse the RPMsg buffer to temporary store the vbuff_reclaimer_t structure. - * Stores the index locally before overwriting the RPMsg header. - */ - idx = rp_hdr->reserved; rvdev = metal_container_of(rdev, struct rpmsg_virtio_device, rdev); metal_mutex_acquire(&rdev->lock); - r_desc->idx = idx; - metal_list_add_tail(&rvdev->reclaimer, &r_desc->node); + /* Check whether to release the Tx buffer */ + if (rpmsg_virtio_buf_held_dec_test(rp_hdr)) { + /* + * Reuse the RPMsg buffer to temporary store the vbuff_reclaimer_t structure. + * Store the index locally before overwriting the RPMsg header. + */ + r_desc->idx = RPMSG_BUF_INDEX(rp_hdr); + metal_list_add_tail(&rvdev->reclaimer, &r_desc->node); + } metal_mutex_release(&rdev->lock); @@ -545,19 +564,23 @@ static void rpmsg_virtio_rx_callback(struct virtqueue *vq) uint16_t idx; int status; - metal_mutex_acquire(&rdev->lock); - - /* Process the received data from remote node */ - rp_hdr = rpmsg_virtio_get_rx_buffer(rvdev, &len, &idx); + while (1) { + /* Process the received data from remote node */ + metal_mutex_acquire(&rdev->lock); + rp_hdr = rpmsg_virtio_get_rx_buffer(rvdev, &len, &idx); + metal_mutex_release(&rdev->lock); - metal_mutex_release(&rdev->lock); + /* No more filled rx buffers */ + if (!rp_hdr) + break; - while (rp_hdr) { rp_hdr->reserved = idx; /* 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); + rpmsg_ept_incref(ept); + RPMSG_BUF_HELD_INC(rp_hdr); metal_mutex_release(&rdev->lock); if (ept) { @@ -576,18 +599,9 @@ static void rpmsg_virtio_rx_callback(struct virtqueue *vq) } metal_mutex_acquire(&rdev->lock); - - /* Check whether callback wants to hold buffer */ - if (!(rp_hdr->reserved & RPMSG_BUF_HELD)) { - /* No, return used buffers. */ - rpmsg_virtio_return_buffer(rvdev, rp_hdr, len, idx); - } - - rp_hdr = rpmsg_virtio_get_rx_buffer(rvdev, &len, &idx); - if (!rp_hdr) { - /* tell peer we return some rx buffer */ - virtqueue_kick(rvdev->rvq); - } + rpmsg_ept_decref(ept); + if (rpmsg_virtio_buf_held_dec_test(rp_hdr)) + rpmsg_virtio_release_rx_buffer_nolock(rvdev, rp_hdr); metal_mutex_release(&rdev->lock); } } @@ -609,15 +623,18 @@ static void rpmsg_virtio_rx_callback(struct virtqueue *vq) 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 rpmsg_device *rdev = priv; + struct rpmsg_virtio_device *rvdev = metal_container_of(rdev, + 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; + bool ept_to_release; char name[RPMSG_NAME_SIZE]; - (void)priv; + (void)ept; (void)src; ns_msg = data; @@ -633,14 +650,27 @@ static int rpmsg_virtio_ns_callback(struct rpmsg_endpoint *ept, void *data, metal_mutex_acquire(&rdev->lock); _ept = rpmsg_get_endpoint(rdev, name, RPMSG_ADDR_ANY, dest); + /* + * If ept-release callback is not implemented, ns_unbind_cb() can free the ept. + * Test _ept->release_cb before calling ns_unbind_cb() callbacks. + */ + ept_to_release = _ept && _ept->release_cb; + if (ns_msg->flags & RPMSG_NS_DESTROY) { if (_ept) _ept->dest_addr = RPMSG_ADDR_ANY; + if (ept_to_release) + rpmsg_ept_incref(_ept); metal_mutex_release(&rdev->lock); if (_ept && _ept->ns_unbind_cb) _ept->ns_unbind_cb(_ept); if (rdev->ns_unbind_cb) rdev->ns_unbind_cb(rdev, name, dest); + if (ept_to_release) { + metal_mutex_acquire(&rdev->lock); + rpmsg_ept_decref(_ept); + metal_mutex_release(&rdev->lock); + } } else { if (!_ept) { /* @@ -661,17 +691,75 @@ static int rpmsg_virtio_ns_callback(struct rpmsg_endpoint *ept, void *data, return RPMSG_SUCCESS; } -int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev) +int rpmsg_virtio_get_tx_buffer_size(struct rpmsg_device *rdev) { - int size; struct rpmsg_virtio_device *rvdev; + int size = 0; if (!rdev) return RPMSG_ERR_PARAM; + metal_mutex_acquire(&rdev->lock); rvdev = (struct rpmsg_virtio_device *)rdev; - size = _rpmsg_virtio_get_buffer_size(rvdev); + + if (VIRTIO_ROLE_IS_DRIVER(rvdev->vdev)) { + /* + * If device role is host then buffers are provided by us, + * so just provide the macro. + */ + size = rvdev->config.h2r_buf_size - sizeof(struct rpmsg_hdr); + } + + if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) { + /* + * If other core is host then buffers are provided by it, + * so get the buffer size from the virtqueue. + */ + size = (int)virtqueue_get_desc_size(rvdev->svq) - + sizeof(struct rpmsg_hdr); + } + + if (size <= 0) + size = RPMSG_ERR_NO_BUFF; + metal_mutex_release(&rdev->lock); + + return size; +} + +int rpmsg_virtio_get_rx_buffer_size(struct rpmsg_device *rdev) +{ + struct rpmsg_virtio_device *rvdev; + int size = 0; + + if (!rdev) + return RPMSG_ERR_PARAM; + + metal_mutex_acquire(&rdev->lock); + rvdev = (struct rpmsg_virtio_device *)rdev; + + if (VIRTIO_ROLE_IS_DRIVER(rvdev->vdev)) { + /* + * If device role is host then buffers are provided by us, + * so just provide the macro. + */ + size = rvdev->config.r2h_buf_size - sizeof(struct rpmsg_hdr); + } + + if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) { + /* + * If other core is host then buffers are provided by it, + * so get the buffer size from the virtqueue. + */ + size = (int)virtqueue_get_desc_size(rvdev->rvq) - + sizeof(struct rpmsg_hdr); + } + + if (size <= 0) + size = RPMSG_ERR_NO_BUFF; + + metal_mutex_release(&rdev->lock); + return size; } @@ -695,13 +783,15 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, struct rpmsg_device *rdev; const char *vq_names[RPMSG_NUM_VRINGS]; vq_callback callback[RPMSG_NUM_VRINGS]; + uint32_t features; int status; - unsigned int i, role; + unsigned int i; if (!rvdev || !vdev || !shm_io) return RPMSG_ERR_PARAM; rdev = &rvdev->rdev; + rvdev->notify_wait_cb = NULL; memset(rdev, 0, sizeof(*rdev)); metal_mutex_init(&rdev->lock); rvdev->vdev = vdev; @@ -713,10 +803,10 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, rdev->ops.get_tx_payload_buffer = rpmsg_virtio_get_tx_payload_buffer; rdev->ops.send_offchannel_nocopy = rpmsg_virtio_send_offchannel_nocopy; rdev->ops.release_tx_buffer = rpmsg_virtio_release_tx_buffer; - role = rpmsg_virtio_get_role(rvdev); + rdev->ops.get_rx_buffer_size = rpmsg_virtio_get_rx_buffer_size; + rdev->ops.get_tx_buffer_size = rpmsg_virtio_get_tx_buffer_size; -#ifndef VIRTIO_DEVICE_ONLY - if (role == RPMSG_HOST) { + if (VIRTIO_ROLE_IS_DRIVER(rvdev->vdev)) { /* * The virtio configuration contains only options applicable to * a virtio driver, implying rpmsg host role. @@ -726,23 +816,20 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, } rvdev->config = *config; } -#else /*!VIRTIO_DEVICE_ONLY*/ - /* Ignore passed config in the virtio-device-only configuration. */ - (void)config; -#endif /*!VIRTIO_DEVICE_ONLY*/ - -#ifndef VIRTIO_DRIVER_ONLY - if (role == RPMSG_REMOTE) { + if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) { /* wait synchro with the host */ - rpmsg_virtio_wait_remote_ready(rvdev); + status = rpmsg_virtio_wait_remote_ready(rvdev); + if (status) + return status; } -#endif /*!VIRTIO_DRIVER_ONLY*/ - vdev->features = rpmsg_virtio_get_features(rvdev); - rdev->support_ns = !!(vdev->features & (1 << VIRTIO_RPMSG_F_NS)); -#ifndef VIRTIO_DEVICE_ONLY - if (role == RPMSG_HOST) { + status = virtio_get_features(rvdev->vdev, &features); + if (status) + return status; + rdev->support_ns = !!(features & (1 << VIRTIO_RPMSG_F_NS)); + + if (VIRTIO_ROLE_IS_DRIVER(rvdev->vdev)) { /* * Since device is RPMSG Remote so we need to manage the * shared buffers. Create shared memory pool to handle buffers. @@ -757,31 +844,35 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, 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_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - (void)shpool; - if (role == RPMSG_REMOTE) { + if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) { 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_DRIVER_ONLY*/ + rvdev->shbuf_io = shm_io; metal_list_init(&rvdev->reclaimer); /* Create virtqueues for remote device */ - status = rpmsg_virtio_create_virtqueues(rvdev, 0, RPMSG_NUM_VRINGS, - vq_names, callback); + status = virtio_create_virtqueues(rvdev->vdev, 0, RPMSG_NUM_VRINGS, + vq_names, callback, NULL); if (status != RPMSG_SUCCESS) return status; + /* Create virtqueue success, assign back the virtqueue */ + if (VIRTIO_ROLE_IS_DRIVER(rvdev->vdev)) { + rvdev->rvq = vdev->vrings_info[0].vq; + rvdev->svq = vdev->vrings_info[1].vq; + } + + if (VIRTIO_ROLE_IS_DEVICE(rvdev->vdev)) { + rvdev->rvq = vdev->vrings_info[1].vq; + rvdev->svq = vdev->vrings_info[0].vq; + } + /* * Suppress "tx-complete" interrupts * since send method use busy loop when buffer pool exhaust @@ -796,8 +887,7 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, vq->shm_io = shm_io; } -#ifndef VIRTIO_DEVICE_ONLY - if (role == RPMSG_HOST) { + if (VIRTIO_ROLE_IS_DRIVER(rvdev->vdev)) { struct virtqueue_buf vqbuf; unsigned int idx; void *buffer; @@ -809,7 +899,8 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, rvdev->config.r2h_buf_size); if (!buffer) { - return RPMSG_ERR_NO_BUFF; + status = RPMSG_ERR_NO_BUFF; + goto err; } vqbuf.buf = buffer; @@ -823,11 +914,10 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, buffer); if (status != RPMSG_SUCCESS) { - return status; + goto err; } } } -#endif /*!VIRTIO_DEVICE_ONLY*/ /* Initialize channels and endpoints list */ metal_list_init(&rdev->endpoints); @@ -839,14 +929,19 @@ int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev, if (rdev->support_ns) { rpmsg_register_endpoint(rdev, &rdev->ns_ept, "NS", RPMSG_NS_EPT_ADDR, RPMSG_NS_EPT_ADDR, - rpmsg_virtio_ns_callback, NULL); + rpmsg_virtio_ns_callback, NULL, rvdev); + } + + if (VIRTIO_ROLE_IS_DRIVER(rvdev->vdev)) { + status = virtio_set_status(rvdev->vdev, VIRTIO_CONFIG_STATUS_DRIVER_OK); + if (status) + goto err; } -#ifndef VIRTIO_DEVICE_ONLY - if (role == RPMSG_HOST) - rpmsg_virtio_set_status(rvdev, VIRTIO_CONFIG_STATUS_DRIVER_OK); -#endif /*!VIRTIO_DEVICE_ONLY*/ + return RPMSG_SUCCESS; +err: + virtio_delete_virtqueues(rvdev->vdev); return status; } @@ -867,6 +962,7 @@ void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev) rvdev->rvq = 0; rvdev->svq = 0; + virtio_delete_virtqueues(rvdev->vdev); metal_mutex_deinit(&rdev->lock); } } diff --git a/open-amp/lib/service/rpmsg/rpc/rpmsg_rpc_client.c b/open-amp/lib/service/rpmsg/rpc/rpmsg_rpc_client.c index f4e30b2..474218e 100644 --- a/open-amp/lib/service/rpmsg/rpc/rpmsg_rpc_client.c +++ b/open-amp/lib/service/rpmsg/rpc/rpmsg_rpc_client.c @@ -5,6 +5,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include #include static int rpmsg_endpoint_client_cb(struct rpmsg_endpoint *, void *, size_t, @@ -47,7 +48,7 @@ int rpmsg_rpc_client_init(struct rpmsg_rpc_clt *rpc, } int rpmsg_rpc_client_send(struct rpmsg_rpc_clt *rpc, - unsigned int rpc_id, void *request_param, + uint32_t rpc_id, void *request_param, size_t req_param_size) { unsigned char tmpbuf[MAX_BUF_LEN]; @@ -81,8 +82,7 @@ void rpmsg_rpc_client_release(struct rpmsg_rpc_clt *rpc) { if (!rpc) return; - if (&rpc->ept) - rpmsg_destroy_ept(&rpc->ept); + rpmsg_destroy_ept(&rpc->ept); } diff --git a/open-amp/lib/service/rpmsg/rpc/rpmsg_rpc_server.c b/open-amp/lib/service/rpmsg/rpc/rpmsg_rpc_server.c index 33a51c1..716d4a1 100644 --- a/open-amp/lib/service/rpmsg/rpc/rpmsg_rpc_server.c +++ b/open-amp/lib/service/rpmsg/rpc/rpmsg_rpc_server.c @@ -5,6 +5,7 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include #include #define LPERROR(format, ...) metal_log(METAL_LOG_ERROR, format, ##__VA_ARGS__) diff --git a/open-amp/lib/virtio/virtio.c b/open-amp/lib/virtio/virtio.c index 794212a..a442e52 100644 --- a/open-amp/lib/virtio/virtio.c +++ b/open-amp/lib/virtio/virtio.c @@ -4,10 +4,8 @@ * * SPDX-License-Identifier: BSD-2-Clause */ -#include -static const char *virtio_feature_name(unsigned long feature, - const struct virtio_feature_desc *); +#include /* * TODO : @@ -40,16 +38,6 @@ static const struct virtio_ident { 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; @@ -62,36 +50,13 @@ const char *virtio_dev_name(unsigned short devid) 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; -} - __deprecated 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); + (void)desc; } int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, @@ -120,8 +85,7 @@ int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, vring_info = &vdev->vrings_info[i]; vring_alloc = &vring_info->info; -#ifndef VIRTIO_DEVICE_ONLY - if (vdev->role == VIRTIO_DEV_DRIVER) { + if (VIRTIO_ROLE_IS_DRIVER(vdev)) { size_t offset; struct metal_io_region *io = vring_info->io; @@ -131,7 +95,6 @@ int virtio_create_virtqueues(struct virtio_device *vdev, unsigned int flags, 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); diff --git a/open-amp/lib/virtio/virtqueue.c b/open-amp/lib/virtio/virtqueue.c index 2544ee3..363fda8 100644 --- a/open-amp/lib/virtio/virtqueue.c +++ b/open-amp/lib/virtio/virtqueue.c @@ -21,12 +21,8 @@ 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(struct virtqueue *vq); static void vq_ring_notify(struct virtqueue *vq); -#ifndef VIRTIO_DEVICE_ONLY static int virtqueue_nused(struct virtqueue *vq); -#endif -#ifndef VIRTIO_DRIVER_ONLY static int virtqueue_navail(struct virtqueue *vq); -#endif /* Default implementation of P2V based on libmetal */ static inline void *virtqueue_phys_to_virt(struct virtqueue *vq, @@ -177,6 +173,7 @@ void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx) uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx) { + /* Invalidate the desc entry written by driver before accessing it */ VRING_INVALIDATE(&vq->vq_ring.desc[idx].len, sizeof(vq->vq_ring.desc[idx].len)); return vq->vq_ring.desc[idx].len; @@ -184,6 +181,7 @@ uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx) void *virtqueue_get_buffer_addr(struct virtqueue *vq, uint16_t idx) { + /* Invalidate the desc entry written by driver before accessing it */ VRING_INVALIDATE(&vq->vq_ring.desc[idx].addr, sizeof(vq->vq_ring.desc[idx].addr)); return virtqueue_phys_to_virt(vq, vq->vq_ring.desc[idx].addr); @@ -225,11 +223,8 @@ void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx, sizeof(vq->vq_ring.avail->ring[head_idx])); *avail_idx = vq->vq_ring.avail->ring[head_idx]; - /* Invalidate the desc entry written by driver before accessing it */ - VRING_INVALIDATE(&vq->vq_ring.desc[*avail_idx], - sizeof(vq->vq_ring.desc[*avail_idx])); - buffer = virtqueue_phys_to_virt(vq, vq->vq_ring.desc[*avail_idx].addr); - *len = vq->vq_ring.desc[*avail_idx].len; + buffer = virtqueue_get_buffer_addr(vq, *avail_idx); + *len = virtqueue_get_buffer_length(vq, *avail_idx); VQUEUE_IDLE(vq); @@ -283,37 +278,29 @@ void virtqueue_disable_cb(struct virtqueue *vq) VQUEUE_BUSY(vq); if (vq->vq_dev->features & VIRTIO_RING_F_EVENT_IDX) { -#ifndef VIRTIO_DEVICE_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + if (VIRTIO_ROLE_IS_DRIVER(vq->vq_dev)) { vring_used_event(&vq->vq_ring) = vq->vq_used_cons_idx - vq->vq_nentries - 1; VRING_FLUSH(&vring_used_event(&vq->vq_ring), sizeof(vring_used_event(&vq->vq_ring))); } -#endif /*VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + if (VIRTIO_ROLE_IS_DEVICE(vq->vq_dev)) { vring_avail_event(&vq->vq_ring) = vq->vq_available_idx - vq->vq_nentries - 1; VRING_FLUSH(&vring_avail_event(&vq->vq_ring), sizeof(vring_avail_event(&vq->vq_ring))); } -#endif /*VIRTIO_DRIVER_ONLY*/ } else { -#ifndef VIRTIO_DEVICE_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + if (VIRTIO_ROLE_IS_DRIVER(vq->vq_dev)) { vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; VRING_FLUSH(&vq->vq_ring.avail->flags, sizeof(vq->vq_ring.avail->flags)); } -#endif /*VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + if (VIRTIO_ROLE_IS_DEVICE(vq->vq_dev)) { vq->vq_ring.used->flags |= VRING_USED_F_NO_NOTIFY; VRING_FLUSH(&vq->vq_ring.used->flags, sizeof(vq->vq_ring.used->flags)); } -#endif /*VIRTIO_DRIVER_ONLY*/ } VQUEUE_IDLE(vq); @@ -498,15 +485,13 @@ static void vq_ring_init(struct virtqueue *vq, void *ring_mem, int alignment) vring_init(vr, size, ring_mem, alignment); -#ifndef VIRTIO_DEVICE_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + if (VIRTIO_ROLE_IS_DRIVER(vq->vq_dev)) { int i; for (i = 0; i < size - 1; i++) vr->desc[i].next = i + 1; vr->desc[i].next = VQ_RING_DESC_CHAIN_END; } -#endif /*VIRTIO_DEVICE_ONLY*/ } /* @@ -557,37 +542,29 @@ static int vq_ring_enable_interrupt(struct virtqueue *vq, uint16_t ndesc) * what's already been consumed. */ if (vq->vq_dev->features & VIRTIO_RING_F_EVENT_IDX) { -#ifndef VIRTIO_DEVICE_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + if (VIRTIO_ROLE_IS_DRIVER(vq->vq_dev)) { vring_used_event(&vq->vq_ring) = vq->vq_used_cons_idx + ndesc; VRING_FLUSH(&vring_used_event(&vq->vq_ring), sizeof(vring_used_event(&vq->vq_ring))); } -#endif /*VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + if (VIRTIO_ROLE_IS_DEVICE(vq->vq_dev)) { vring_avail_event(&vq->vq_ring) = vq->vq_available_idx + ndesc; VRING_FLUSH(&vring_avail_event(&vq->vq_ring), sizeof(vring_avail_event(&vq->vq_ring))); } -#endif /*VIRTIO_DRIVER_ONLY*/ } else { -#ifndef VIRTIO_DEVICE_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + if (VIRTIO_ROLE_IS_DRIVER(vq->vq_dev)) { vq->vq_ring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; VRING_FLUSH(&vq->vq_ring.avail->flags, sizeof(vq->vq_ring.avail->flags)); } -#endif /*VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + if (VIRTIO_ROLE_IS_DEVICE(vq->vq_dev)) { vq->vq_ring.used->flags &= ~VRING_USED_F_NO_NOTIFY; VRING_FLUSH(&vq->vq_ring.used->flags, sizeof(vq->vq_ring.used->flags)); } -#endif /*VIRTIO_DRIVER_ONLY*/ } atomic_thread_fence(memory_order_seq_cst); @@ -597,20 +574,16 @@ static int vq_ring_enable_interrupt(struct virtqueue *vq, uint16_t ndesc) * since we last checked. Let our caller know so it processes the new * entries. */ -#ifndef VIRTIO_DEVICE_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + if (VIRTIO_ROLE_IS_DRIVER(vq->vq_dev)) { if (virtqueue_nused(vq) > ndesc) { return 1; } } -#endif /*VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + if (VIRTIO_ROLE_IS_DEVICE(vq->vq_dev)) { if (virtqueue_navail(vq) > ndesc) { return 1; } } -#endif /*VIRTIO_DRIVER_ONLY*/ return 0; } @@ -637,8 +610,7 @@ static int vq_ring_must_notify(struct virtqueue *vq) uint16_t new_idx, prev_idx, event_idx; if (vq->vq_dev->features & VIRTIO_RING_F_EVENT_IDX) { -#ifndef VIRTIO_DEVICE_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + if (VIRTIO_ROLE_IS_DRIVER(vq->vq_dev)) { /* CACHE: no need to invalidate avail */ new_idx = vq->vq_ring.avail->idx; prev_idx = new_idx - vq->vq_queued_cnt; @@ -648,9 +620,7 @@ static int vq_ring_must_notify(struct virtqueue *vq) return vring_need_event(event_idx, new_idx, prev_idx) != 0; } -#endif /*VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + if (VIRTIO_ROLE_IS_DEVICE(vq->vq_dev)) { /* CACHE: no need to invalidate used */ new_idx = vq->vq_ring.used->idx; prev_idx = new_idx - vq->vq_queued_cnt; @@ -660,24 +630,19 @@ static int vq_ring_must_notify(struct virtqueue *vq) return vring_need_event(event_idx, new_idx, prev_idx) != 0; } -#endif /*VIRTIO_DRIVER_ONLY*/ } else { -#ifndef VIRTIO_DEVICE_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DRIVER) { + if (VIRTIO_ROLE_IS_DRIVER(vq->vq_dev)) { VRING_INVALIDATE(&vq->vq_ring.used->flags, sizeof(vq->vq_ring.used->flags)); return (vq->vq_ring.used->flags & VRING_USED_F_NO_NOTIFY) == 0; } -#endif /*VIRTIO_DEVICE_ONLY*/ -#ifndef VIRTIO_DRIVER_ONLY - if (vq->vq_dev->role == VIRTIO_DEV_DEVICE) { + if (VIRTIO_ROLE_IS_DEVICE(vq->vq_dev)) { VRING_INVALIDATE(&vq->vq_ring.avail->flags, sizeof(vq->vq_ring.avail->flags)); return (vq->vq_ring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) == 0; } -#endif /*VIRTIO_DRIVER_ONLY*/ } return 0; @@ -699,7 +664,6 @@ static void vq_ring_notify(struct virtqueue *vq) * virtqueue_nused * */ -#ifndef VIRTIO_DEVICE_ONLY static int virtqueue_nused(struct virtqueue *vq) { uint16_t used_idx, nused; @@ -713,14 +677,12 @@ static int virtqueue_nused(struct virtqueue *vq) return nused; } -#endif /*VIRTIO_DEVICE_ONLY*/ /* * * virtqueue_navail * */ -#ifndef VIRTIO_DRIVER_ONLY static int virtqueue_navail(struct virtqueue *vq) { uint16_t avail_idx, navail; @@ -735,4 +697,3 @@ static int virtqueue_navail(struct virtqueue *vq) return navail; } -#endif /*VIRTIO_DRIVER_ONLY*/ diff --git a/open-amp/lib/virtio_mmio/virtio_mmio_drv.c b/open-amp/lib/virtio_mmio/virtio_mmio_drv.c index 5f42180..5700471 100644 --- a/open-amp/lib/virtio_mmio/virtio_mmio_drv.c +++ b/open-amp/lib/virtio_mmio/virtio_mmio_drv.c @@ -325,7 +325,7 @@ struct virtqueue *virtio_mmio_setup_virtqueue(struct virtio_device *vdev, virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_NUM, vq->vq_nentries); virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_ALIGN, 4096); virtio_mmio_write32(vdev, VIRTIO_MMIO_QUEUE_PFN, - ((uintptr_t)metal_io_virt_to_phys(vq->shm_io, + ((uintptr_t)metal_io_virt_to_phys(vmdev->shm_io, (char *)vq->vq_ring.desc)) / 4096); vdev->vrings_info[vdev->vrings_num].vq = vq;