| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400 |
- /*
- * Copyright (c) 2014, Mentor Graphics Corporation
- * Copyright (c) 2015 Xilinx, Inc.
- * Copyright (c) 2016 Freescale Semiconductor, Inc.
- * Copyright 2016-2022 NXP
- * Copyright 2021 ACRIOS Systems s.r.o.
- * 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.
- */
- #include "rpmsg_lite.h"
- #include "rpmsg_platform.h"
- /* Interface which is used to interact with the virtqueue layer,
- * a different interface is used, when the local processor is the MASTER
- * and when it is the REMOTE.
- */
- struct virtqueue_ops
- {
- void (*vq_tx)(struct virtqueue *vq, void *buffer, uint32_t len, uint16_t idx);
- void *(*vq_tx_alloc)(struct virtqueue *vq, uint32_t *len, uint16_t *idx);
- void *(*vq_rx)(struct virtqueue *vq, uint32_t *len, uint16_t *idx);
- void (*vq_rx_free)(struct virtqueue *vq, void *buffer, uint32_t len, uint16_t idx);
- };
- /* Zero-Copy extension macros */
- #define RPMSG_STD_MSG_FROM_BUF(buf) (struct rpmsg_std_msg *)(void *)((char *)(buf)-offsetof(struct rpmsg_std_msg, data))
- #if !(defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1))
- /* Check RL_BUFFER_COUNT and RL_BUFFER_SIZE only when RL_ALLOW_CUSTOM_SHMEM_CONFIG is not set to 1 */
- #if (!RL_BUFFER_COUNT) || (RL_BUFFER_COUNT & (RL_BUFFER_COUNT - 1))
- #error "RL_BUFFER_COUNT must be power of two (2, 4, ...)"
- #endif
- /* Buffer is formed by payload and struct rpmsg_std_hdr */
- #define RL_BUFFER_SIZE (RL_BUFFER_PAYLOAD_SIZE + 16UL)
- #if (!RL_BUFFER_SIZE) || (RL_BUFFER_SIZE & (RL_BUFFER_SIZE - 1))
- #error \
- "RL_BUFFER_SIZE must be power of two (256, 512, ...)"\
- "RL_BUFFER_PAYLOAD_SIZE must be equal to (240, 496, 1008, ...) [2^n - 16]."
- #endif
- #endif /* !(defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)) */
- /*!
- * @brief
- * Traverse the linked list of endpoints to get the one with defined address.
- *
- * @param rpmsg_lite_dev RPMsg Lite instance
- * @param addr Local endpoint address
- *
- * @return RL_NULL if not found, node pointer containing the ept on success
- *
- */
- static struct llist *rpmsg_lite_get_endpoint_from_addr(struct rpmsg_lite_instance *rpmsg_lite_dev, uint32_t addr)
- {
- struct llist *rl_ept_lut_head;
- rl_ept_lut_head = rpmsg_lite_dev->rl_endpoints;
- while (rl_ept_lut_head != RL_NULL)
- {
- struct rpmsg_lite_endpoint *rl_ept = (struct rpmsg_lite_endpoint *)rl_ept_lut_head->data;
- if (rl_ept->addr == addr)
- {
- return rl_ept_lut_head;
- }
- rl_ept_lut_head = rl_ept_lut_head->next;
- }
- return RL_NULL;
- }
- /***************************************************************
- mmm mm m m mmmmm mm mmm m m mmmm
- m" " ## # # # # ## m" " # m" #" "
- # # # # # #mmmm" # # # #m# "#mmm
- # #mm# # # # # #mm# # # #m "#
- "mmm" # # #mmmmm #mmmmm #mmmm" # # "mmm" # "m "mmm#"
- ****************************************************************/
- /*!
- * @brief
- * Called when remote side calls virtqueue_kick()
- * at its transmit virtqueue.
- * In this callback, the buffer is read-out
- * of the rvq and user callback is called.
- *
- * @param vq Virtqueue affected by the kick
- *
- */
- static void rpmsg_lite_rx_callback(struct virtqueue *vq)
- {
- struct rpmsg_std_msg *rpmsg_msg;
- uint32_t len;
- uint16_t idx;
- struct rpmsg_lite_endpoint *ept;
- int32_t cb_ret;
- struct llist *node;
- struct rpmsg_lite_instance *rpmsg_lite_dev = (struct rpmsg_lite_instance *)vq->priv;
- #if defined(RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION) && (RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION == 1)
- uint32_t rx_freed = RL_FALSE;
- #endif
- RL_ASSERT(rpmsg_lite_dev != RL_NULL);
- #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
- env_lock_mutex(rpmsg_lite_dev->lock);
- #endif
- /* Process the received data from remote node */
- rpmsg_msg = (struct rpmsg_std_msg *)rpmsg_lite_dev->vq_ops->vq_rx(rpmsg_lite_dev->rvq, &len, &idx);
- while (rpmsg_msg != RL_NULL)
- {
- node = rpmsg_lite_get_endpoint_from_addr(rpmsg_lite_dev, rpmsg_msg->hdr.dst);
- cb_ret = RL_RELEASE;
- if (node != RL_NULL)
- {
- ept = (struct rpmsg_lite_endpoint *)node->data;
- cb_ret = ept->rx_cb(rpmsg_msg->data, rpmsg_msg->hdr.len, rpmsg_msg->hdr.src, ept->rx_cb_data);
- }
- if (cb_ret == RL_HOLD)
- {
- rpmsg_msg->hdr.reserved.idx = idx;
- }
- else
- {
- rpmsg_lite_dev->vq_ops->vq_rx_free(rpmsg_lite_dev->rvq, rpmsg_msg, len, idx);
- #if defined(RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION) && (RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION == 1)
- rx_freed = RL_TRUE;
- #endif
- }
- rpmsg_msg = (struct rpmsg_std_msg *)rpmsg_lite_dev->vq_ops->vq_rx(rpmsg_lite_dev->rvq, &len, &idx);
- #if defined(RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION) && (RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION == 1)
- if ((rpmsg_msg == RL_NULL) && (rx_freed == RL_TRUE))
- {
- /* Let the remote device know that some buffers have been freed */
- virtqueue_kick(rpmsg_lite_dev->rvq);
- }
- #endif
- }
- #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
- env_unlock_mutex(rpmsg_lite_dev->lock);
- #endif
- }
- /*!
- * @brief
- * Called when remote side calls virtqueue_kick()
- * at its receive virtqueue.
- *
- * @param vq Virtqueue affected by the kick
- *
- */
- static void rpmsg_lite_tx_callback(struct virtqueue *vq)
- {
- struct rpmsg_lite_instance *rpmsg_lite_dev = (struct rpmsg_lite_instance *)vq->priv;
- RL_ASSERT(rpmsg_lite_dev != RL_NULL);
- rpmsg_lite_dev->link_state = 1U;
- env_tx_callback(rpmsg_lite_dev->link_id);
- }
- /****************************************************************************
- m m mmmm m m mm mm m mmmm m mmmmm mm m mmm
- "m m" m" "m # # ## #"m # # "m # # #"m # m" "
- # # # # #mmmm# # # # #m # # # # # # #m # # mm
- "mm" # # # # #mm# # # # # # # # # # # # #
- ## #mm#" # # # # # ## #mmm" #mmmmm mm#mm # ## "mmm"
- #
- In case this processor has the REMOTE role
- *****************************************************************************/
- /*!
- * @brief
- * Places buffer on the virtqueue for consumption by the other side.
- *
- * @param vq Virtqueue to use
- * @param buffer Buffer pointer
- * @param len Buffer length
- * @idx Buffer index
- *
- * @return Status of function execution
- *
- */
- static void vq_tx_remote(struct virtqueue *tvq, void *buffer, uint32_t len, uint16_t idx)
- {
- int32_t status;
- status = virtqueue_add_consumed_buffer(tvq, idx, len);
- RL_ASSERT(status == VQUEUE_SUCCESS); /* must success here */
- /* As long as the length of the virtqueue ring buffer is not shorter
- * than the number of buffers in the pool, this function should not fail.
- * This condition is always met, so we don't need to return anything here */
- }
- /*!
- * @brief
- * Provides buffer to transmit messages.
- *
- * @param vq Virtqueue to use
- * @param len Length of returned buffer
- * @param idx Buffer index
- *
- * return Pointer to buffer.
- */
- static void *vq_tx_alloc_remote(struct virtqueue *tvq, uint32_t *len, uint16_t *idx)
- {
- return virtqueue_get_available_buffer(tvq, idx, len);
- }
- /*!
- * @brief
- * Retrieves the received buffer from the virtqueue.
- *
- * @param vq Virtqueue to use
- * @param len Size of received buffer
- * @param idx Index of buffer
- *
- * @return Pointer to received buffer
- *
- */
- static void *vq_rx_remote(struct virtqueue *rvq, uint32_t *len, uint16_t *idx)
- {
- return virtqueue_get_available_buffer(rvq, idx, len);
- }
- /*!
- * @brief
- * Places the used buffer back on the virtqueue.
- *
- * @param vq Virtqueue to use
- * @param len Size of received buffer
- * @param idx Index of buffer
- *
- */
- static void vq_rx_free_remote(struct virtqueue *rvq, void *buffer, uint32_t len, uint16_t idx)
- {
- int32_t status;
- #if defined(RL_CLEAR_USED_BUFFERS) && (RL_CLEAR_USED_BUFFERS == 1)
- env_memset(buffer, 0x00, len);
- #endif
- status = virtqueue_add_consumed_buffer(rvq, idx, len);
- RL_ASSERT(status == VQUEUE_SUCCESS); /* must success here */
- /* As long as the length of the virtqueue ring buffer is not shorter
- * than the number of buffers in the pool, this function should not fail.
- * This condition is always met, so we don't need to return anything here */
- }
- /****************************************************************************
- m m mmmm m m mm mm m mmmm m mmmmm mm m mmm
- "m m" m" "m # # ## #"m # # "m # # #"m # m" "
- # # # # #mmmm# # # # #m # # # # # # #m # # mm
- "mm" # # # # #mm# # # # # # # # # # # # #
- ## #mm#" # # # # # ## #mmm" #mmmmm mm#mm # ## "mmm"
- #
- In case this processor has the MASTER role
- *****************************************************************************/
- /*!
- * @brief
- * Places buffer on the virtqueue for consumption by the other side.
- *
- * @param tvq Virtqueue to use
- * @param buffer Buffer pointer
- * @param len Buffer length
- * @param idx Buffer index
- *
- * @return Status of function execution
- *
- */
- static void vq_tx_master(struct virtqueue *tvq, void *buffer, uint32_t len, uint16_t idx)
- {
- int32_t status;
- status = virtqueue_add_buffer(tvq, idx);
- RL_ASSERT(status == VQUEUE_SUCCESS); /* must success here */
- /* As long as the length of the virtqueue ring buffer is not shorter
- * than the number of buffers in the pool, this function should not fail.
- * This condition is always met, so we don't need to return anything here */
- }
- /*!
- * @brief
- * Provides buffer to transmit messages.
- *
- * @param tvq Virtqueue to use
- * @param len Length of returned buffer
- * @param idx Buffer index
- *
- * return Pointer to buffer.
- */
- static void *vq_tx_alloc_master(struct virtqueue *tvq, uint32_t *len, uint16_t *idx)
- {
- return virtqueue_get_buffer(tvq, len, idx);
- }
- /*!
- * @brief
- * Retrieves the received buffer from the virtqueue.
- *
- * @param rvq Virtqueue to use
- * @param len Size of received buffer
- * @param idx Index of buffer
- *
- * @return Pointer to received buffer
- *
- */
- static void *vq_rx_master(struct virtqueue *rvq, uint32_t *len, uint16_t *idx)
- {
- return virtqueue_get_buffer(rvq, len, idx);
- }
- /*!
- * @brief
- * Places the used buffer back on the virtqueue.
- *
- * @param rvq Virtqueue to use
- * @param buffer Buffer pointer
- * @param len Size of received buffer
- * @param idx Index of buffer
- *
- */
- static void vq_rx_free_master(struct virtqueue *rvq, void *buffer, uint32_t len, uint16_t idx)
- {
- int32_t status;
- #if defined(RL_CLEAR_USED_BUFFERS) && (RL_CLEAR_USED_BUFFERS == 1)
- env_memset(buffer, 0x00, len);
- #endif
- status = virtqueue_add_buffer(rvq, idx);
- RL_ASSERT(status == VQUEUE_SUCCESS); /* must success here */
- /* As long as the length of the virtqueue ring buffer is not shorter
- * than the number of buffers in the pool, this function should not fail.
- * This condition is always met, so we don't need to return anything here */
- }
- /* Interface used in case this processor is MASTER */
- static const struct virtqueue_ops master_vq_ops = {
- vq_tx_master,
- vq_tx_alloc_master,
- vq_rx_master,
- vq_rx_free_master,
- };
- /* Interface used in case this processor is REMOTE */
- static const struct virtqueue_ops remote_vq_ops = {
- vq_tx_remote,
- vq_tx_alloc_remote,
- vq_rx_remote,
- vq_rx_free_remote,
- };
- /* helper function for virtqueue notification */
- static void virtqueue_notify(struct virtqueue *vq)
- {
- #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
- struct rpmsg_lite_instance *inst = vq->priv;
- platform_notify(inst->env ? env_get_platform_context(inst->env) : RL_NULL, vq->vq_queue_index);
- #else
- platform_notify(vq->vq_queue_index);
- #endif
- }
- /*************************************************
- mmmmmm mmmmm mmmmmmm mm m mmmmmmm m
- # # "# # #"m # # # # #
- #mmmmm #mmm#" # # #m # #mmmmm" #"# #
- # # # # # # # ## ##"
- #mmmmm # # # ## #mmmmm # #
- **************************************************/
- #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
- struct rpmsg_lite_endpoint *rpmsg_lite_create_ept(struct rpmsg_lite_instance *rpmsg_lite_dev,
- uint32_t addr,
- rl_ept_rx_cb_t rx_cb,
- void *rx_cb_data,
- struct rpmsg_lite_ept_static_context *ept_context)
- #else
- struct rpmsg_lite_endpoint *rpmsg_lite_create_ept(struct rpmsg_lite_instance *rpmsg_lite_dev,
- uint32_t addr,
- rl_ept_rx_cb_t rx_cb,
- void *rx_cb_data)
- #endif
- {
- struct rpmsg_lite_endpoint *rl_ept;
- struct llist *node;
- uint32_t i;
- if (rpmsg_lite_dev == RL_NULL)
- {
- return RL_NULL;
- }
- env_lock_mutex(rpmsg_lite_dev->lock);
- {
- if (addr == RL_ADDR_ANY)
- {
- /* find lowest free address */
- for (i = 1; i < 0xFFFFFFFFU; i++)
- {
- if (rpmsg_lite_get_endpoint_from_addr(rpmsg_lite_dev, i) == RL_NULL)
- {
- addr = i;
- break;
- }
- }
- if (addr == RL_ADDR_ANY)
- {
- /* no address is free, cannot happen normally */
- env_unlock_mutex(rpmsg_lite_dev->lock);
- return RL_NULL;
- }
- }
- else
- {
- if (rpmsg_lite_get_endpoint_from_addr(rpmsg_lite_dev, addr) != RL_NULL)
- {
- /* Already exists! */
- env_unlock_mutex(rpmsg_lite_dev->lock);
- return RL_NULL;
- }
- }
- #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
- if (ept_context == RL_NULL)
- {
- env_unlock_mutex(rpmsg_lite_dev->lock);
- return RL_NULL;
- }
- rl_ept = &(ept_context->ept);
- node = &(ept_context->node);
- #else
- rl_ept = env_allocate_memory(sizeof(struct rpmsg_lite_endpoint));
- if (rl_ept == RL_NULL)
- {
- env_unlock_mutex(rpmsg_lite_dev->lock);
- return RL_NULL;
- }
- node = env_allocate_memory(sizeof(struct llist));
- if (node == RL_NULL)
- {
- env_free_memory(rl_ept);
- env_unlock_mutex(rpmsg_lite_dev->lock);
- return RL_NULL;
- }
- #endif /* RL_USE_STATIC_API */
- env_memset(rl_ept, 0x00, sizeof(struct rpmsg_lite_endpoint));
- rl_ept->addr = addr;
- rl_ept->rx_cb = rx_cb;
- rl_ept->rx_cb_data = rx_cb_data;
- node->data = rl_ept;
- add_to_list((struct llist **)&rpmsg_lite_dev->rl_endpoints, node);
- }
- env_unlock_mutex(rpmsg_lite_dev->lock);
- return rl_ept;
- }
- /*************************************************
- mmmmmm mmmmm mmmmmmm mmmm mmmmmm m
- # # "# # # "m # #
- #mmmmm #mmm#" # # # #mmmmm #
- # # # # # # #
- #mmmmm # # #mmm" #mmmmm #mmmmm
- **************************************************/
- int32_t rpmsg_lite_destroy_ept(struct rpmsg_lite_instance *rpmsg_lite_dev, struct rpmsg_lite_endpoint *rl_ept)
- {
- struct llist *node;
- if (rpmsg_lite_dev == RL_NULL)
- {
- return RL_ERR_PARAM;
- }
- if (rl_ept == RL_NULL)
- {
- return RL_ERR_PARAM;
- }
- env_lock_mutex(rpmsg_lite_dev->lock);
- node = rpmsg_lite_get_endpoint_from_addr(rpmsg_lite_dev, rl_ept->addr);
- if (node != RL_NULL)
- {
- remove_from_list((struct llist **)&rpmsg_lite_dev->rl_endpoints, node);
- env_unlock_mutex(rpmsg_lite_dev->lock);
- #if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1))
- env_free_memory(node);
- env_free_memory(rl_ept);
- #endif
- return RL_SUCCESS;
- }
- else
- {
- env_unlock_mutex(rpmsg_lite_dev->lock);
- return RL_ERR_PARAM;
- }
- }
- /******************************************
- mmmmmmm m m mm mmmmm mmmmm
- # # # ## # "# #
- # ## # # #mmm#" #
- # m""m #mm# # #
- # m" "m # # # mm#mm
- *******************************************/
- uint32_t rpmsg_lite_is_link_up(struct rpmsg_lite_instance *rpmsg_lite_dev)
- {
- if (rpmsg_lite_dev == RL_NULL)
- {
- return 0U;
- }
- return (RL_TRUE == rpmsg_lite_dev->link_state ? RL_TRUE : RL_FALSE);
- }
- uint32_t rpmsg_lite_wait_for_link_up(struct rpmsg_lite_instance *rpmsg_lite_dev, uint32_t timeout)
- {
- if (rpmsg_lite_dev == RL_NULL)
- {
- return 0U;
- }
- return env_wait_for_link_up(&rpmsg_lite_dev->link_state, rpmsg_lite_dev->link_id, timeout);
- }
- /*!
- * @brief
- * Internal function to format a RPMsg compatible
- * message and sends it
- *
- * @param rpmsg_lite_dev RPMsg Lite instance
- * @param src Local endpoint address
- * @param dst Remote endpoint address
- * @param data Payload buffer
- * @param size Size of payload, in bytes
- * @param flags Value of flags field
- * @param timeout Timeout in ms, 0 if nonblocking
- *
- * @return Status of function execution, RL_SUCCESS on success
- *
- */
- static int32_t rpmsg_lite_format_message(struct rpmsg_lite_instance *rpmsg_lite_dev,
- uint32_t src,
- uint32_t dst,
- char *data,
- uint32_t size,
- uint32_t flags,
- uint32_t timeout)
- {
- struct rpmsg_std_msg *rpmsg_msg;
- void *buffer;
- uint16_t idx;
- uint32_t tick_count = 0U;
- uint32_t buff_len;
- if (rpmsg_lite_dev == RL_NULL)
- {
- return RL_ERR_PARAM;
- }
- if (data == RL_NULL)
- {
- return RL_ERR_PARAM;
- }
- if (rpmsg_lite_dev->link_state != RL_TRUE)
- {
- return RL_NOT_READY;
- }
- /* Lock the device to enable exclusive access to virtqueues */
- env_lock_mutex(rpmsg_lite_dev->lock);
- /* Get rpmsg buffer for sending message. */
- buffer = rpmsg_lite_dev->vq_ops->vq_tx_alloc(rpmsg_lite_dev->tvq, &buff_len, &idx);
- env_unlock_mutex(rpmsg_lite_dev->lock);
- if ((buffer == RL_NULL) && (timeout == RL_FALSE))
- {
- return RL_ERR_NO_MEM;
- }
- while (buffer == RL_NULL)
- {
- env_sleep_msec(RL_MS_PER_INTERVAL);
- env_lock_mutex(rpmsg_lite_dev->lock);
- buffer = rpmsg_lite_dev->vq_ops->vq_tx_alloc(rpmsg_lite_dev->tvq, &buff_len, &idx);
- env_unlock_mutex(rpmsg_lite_dev->lock);
- tick_count += (uint32_t)RL_MS_PER_INTERVAL;
- if ((tick_count >= timeout) && (buffer == RL_NULL))
- {
- return RL_ERR_NO_MEM;
- }
- }
- rpmsg_msg = (struct rpmsg_std_msg *)buffer;
- /* Initialize RPMSG header. */
- rpmsg_msg->hdr.dst = dst;
- rpmsg_msg->hdr.src = src;
- rpmsg_msg->hdr.len = (uint16_t)size;
- rpmsg_msg->hdr.flags = (uint16_t)(flags & 0xFFFFU);
- /* Copy data to rpmsg buffer. */
- env_memcpy(rpmsg_msg->data, data, size);
- env_lock_mutex(rpmsg_lite_dev->lock);
- /* Enqueue buffer on virtqueue. */
- rpmsg_lite_dev->vq_ops->vq_tx(rpmsg_lite_dev->tvq, buffer, buff_len, idx);
- /* Let the other side know that there is a job to process. */
- virtqueue_kick(rpmsg_lite_dev->tvq);
- env_unlock_mutex(rpmsg_lite_dev->lock);
- return RL_SUCCESS;
- }
- int32_t rpmsg_lite_send(struct rpmsg_lite_instance *rpmsg_lite_dev,
- struct rpmsg_lite_endpoint *ept,
- uint32_t dst,
- char *data,
- uint32_t size,
- uintptr_t timeout)
- {
- if (ept == RL_NULL)
- {
- return RL_ERR_PARAM;
- }
- // FIXME : may be just copy the data size equal to buffer length and Tx it.
- #if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)
- if (size > (uint32_t)RL_BUFFER_PAYLOAD_SIZE(rpmsg_lite_dev->link_id))
- #else
- if (size > (uint32_t)RL_BUFFER_PAYLOAD_SIZE)
- #endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */
- {
- return RL_ERR_BUFF_SIZE;
- }
- return rpmsg_lite_format_message(rpmsg_lite_dev, ept->addr, dst, data, size, RL_NO_FLAGS, timeout);
- }
- #if defined(RL_API_HAS_ZEROCOPY) && (RL_API_HAS_ZEROCOPY == 1)
- void *rpmsg_lite_alloc_tx_buffer(struct rpmsg_lite_instance *rpmsg_lite_dev, uint32_t *size, uintptr_t timeout)
- {
- struct rpmsg_std_msg *rpmsg_msg;
- void *buffer;
- uint16_t idx;
- uint32_t tick_count = 0U;
- if (size == RL_NULL)
- {
- return RL_NULL;
- }
- if (rpmsg_lite_dev->link_state != RL_TRUE)
- {
- *size = 0;
- return RL_NULL;
- }
- /* Lock the device to enable exclusive access to virtqueues */
- env_lock_mutex(rpmsg_lite_dev->lock);
- /* Get rpmsg buffer for sending message. */
- buffer = rpmsg_lite_dev->vq_ops->vq_tx_alloc(rpmsg_lite_dev->tvq, size, &idx);
- env_unlock_mutex(rpmsg_lite_dev->lock);
- if ((buffer == RL_NULL) && (timeout == RL_FALSE))
- {
- *size = 0;
- return RL_NULL;
- }
- while (buffer == RL_NULL)
- {
- env_sleep_msec(RL_MS_PER_INTERVAL);
- env_lock_mutex(rpmsg_lite_dev->lock);
- buffer = rpmsg_lite_dev->vq_ops->vq_tx_alloc(rpmsg_lite_dev->tvq, size, &idx);
- env_unlock_mutex(rpmsg_lite_dev->lock);
- tick_count += (uint32_t)RL_MS_PER_INTERVAL;
- if ((tick_count >= timeout) && (buffer == RL_NULL))
- {
- *size = 0;
- return RL_NULL;
- }
- }
- rpmsg_msg = (struct rpmsg_std_msg *)buffer;
- /* keep idx and totlen information for nocopy tx function */
- rpmsg_msg->hdr.reserved.idx = idx;
- /* return the maximum payload size */
- *size -= sizeof(struct rpmsg_std_hdr);
- return rpmsg_msg->data;
- }
- int32_t rpmsg_lite_send_nocopy(struct rpmsg_lite_instance *rpmsg_lite_dev,
- struct rpmsg_lite_endpoint *ept,
- uint32_t dst,
- void *data,
- uint32_t size)
- {
- struct rpmsg_std_msg *rpmsg_msg;
- uint32_t src;
- if ((ept == RL_NULL) || (data == RL_NULL))
- {
- return RL_ERR_PARAM;
- }
- #if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)
- if (size > (uint32_t)RL_BUFFER_PAYLOAD_SIZE(rpmsg_lite_dev->link_id))
- #else
- if (size > (uint32_t)RL_BUFFER_PAYLOAD_SIZE)
- #endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */
- {
- return RL_ERR_BUFF_SIZE;
- }
- if (rpmsg_lite_dev->link_state != RL_TRUE)
- {
- return RL_NOT_READY;
- }
- src = ept->addr;
- rpmsg_msg = RPMSG_STD_MSG_FROM_BUF(data);
- #if defined(RL_DEBUG_CHECK_BUFFERS) && (RL_DEBUG_CHECK_BUFFERS == 1)
- /* Check that the to-be-sent buffer is in the VirtIO ring descriptors list */
- int32_t idx = rpmsg_lite_dev->tvq->vq_nentries - 1;
- while ((idx >= 0) && (rpmsg_lite_dev->tvq->vq_ring.desc[idx].addr != (uint64_t)rpmsg_msg))
- {
- idx--;
- }
- RL_ASSERT(idx >= 0);
- #endif
- /* Initialize RPMSG header. */
- rpmsg_msg->hdr.dst = dst;
- rpmsg_msg->hdr.src = src;
- rpmsg_msg->hdr.len = (uint16_t)size;
- rpmsg_msg->hdr.flags = (uint16_t)(RL_NO_FLAGS & 0xFFFFU);
- env_lock_mutex(rpmsg_lite_dev->lock);
- /* Enqueue buffer on virtqueue. */
- rpmsg_lite_dev->vq_ops->vq_tx(
- rpmsg_lite_dev->tvq, (void *)rpmsg_msg,
- (uint32_t)virtqueue_get_buffer_length(rpmsg_lite_dev->tvq, rpmsg_msg->hdr.reserved.idx),
- rpmsg_msg->hdr.reserved.idx);
- /* Let the other side know that there is a job to process. */
- virtqueue_kick(rpmsg_lite_dev->tvq);
- env_unlock_mutex(rpmsg_lite_dev->lock);
- return RL_SUCCESS;
- }
- /******************************************
- mmmmm m m mm mmmmm mmmmm
- # "# # # ## # "# #
- #mmmm" ## # # #mmm#" #
- # "m m""m #mm# # #
- # " m" "m # # # mm#mm
- *******************************************/
- int32_t rpmsg_lite_release_rx_buffer(struct rpmsg_lite_instance *rpmsg_lite_dev, void *rxbuf)
- {
- struct rpmsg_std_msg *rpmsg_msg;
- if (rpmsg_lite_dev == RL_NULL)
- {
- return RL_ERR_PARAM;
- }
- if (rxbuf == RL_NULL)
- {
- return RL_ERR_PARAM;
- }
- rpmsg_msg = RPMSG_STD_MSG_FROM_BUF(rxbuf);
- #if defined(RL_DEBUG_CHECK_BUFFERS) && (RL_DEBUG_CHECK_BUFFERS == 1)
- /* Check that the to-be-released buffer is in the VirtIO ring descriptors list */
- int32_t idx = rpmsg_lite_dev->rvq->vq_nentries - 1;
- while ((idx >= 0) && (rpmsg_lite_dev->rvq->vq_ring.desc[idx].addr != (uint64_t)rpmsg_msg))
- {
- idx--;
- }
- RL_ASSERT(idx >= 0);
- #endif
- env_lock_mutex(rpmsg_lite_dev->lock);
- /* Return used buffer, with total length (header length + buffer size). */
- rpmsg_lite_dev->vq_ops->vq_rx_free(
- rpmsg_lite_dev->rvq, rpmsg_msg,
- (uint32_t)virtqueue_get_buffer_length(rpmsg_lite_dev->rvq, rpmsg_msg->hdr.reserved.idx),
- rpmsg_msg->hdr.reserved.idx);
- #if defined(RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION) && (RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION == 1)
- /* Let the remote device know that a buffer has been freed */
- virtqueue_kick(rpmsg_lite_dev->rvq);
- #endif
- env_unlock_mutex(rpmsg_lite_dev->lock);
- return RL_SUCCESS;
- }
- #endif /* RL_API_HAS_ZEROCOPY */
- /******************************
- mmmmm mm m mmmmm mmmmmmm
- # #"m # # #
- # # #m # # #
- # # # # # #
- mm#mm # ## mm#mm #
- *****************************/
- #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
- struct rpmsg_lite_instance *rpmsg_lite_master_init(void *shmem_addr,
- size_t shmem_length,
- uint32_t link_id,
- uint32_t init_flags,
- struct rpmsg_lite_instance *static_context)
- #elif defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
- struct rpmsg_lite_instance *rpmsg_lite_master_init(
- void *shmem_addr, size_t shmem_length, uint32_t link_id, uint32_t init_flags, void *env_cfg)
- #else
- struct rpmsg_lite_instance *rpmsg_lite_master_init(void *shmem_addr,
- size_t shmem_length,
- uint32_t link_id,
- uint32_t init_flags)
- #endif
- {
- int32_t status;
- void (*callback[2])(struct virtqueue *vq);
- const char *vq_names[2];
- struct vring_alloc_info ring_info;
- struct virtqueue *vqs[2] = {0};
- void *buffer;
- uint32_t idx, j;
- struct rpmsg_lite_instance *rpmsg_lite_dev = RL_NULL;
- if (link_id > RL_PLATFORM_HIGHEST_LINK_ID)
- {
- return RL_NULL;
- }
- if (shmem_addr == RL_NULL)
- {
- return RL_NULL;
- }
- #if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)
- /* Get the custom shmem configuration defined per each rpmsg_lite instance
- (i.e. per each link id) from the platform layer */
- rpmsg_platform_shmem_config_t shmem_config = {0};
- if (RL_SUCCESS != platform_get_custom_shmem_config(link_id, &shmem_config))
- {
- return RL_NULL;
- }
- /* shmem_config.buffer_count must be power of two (2, 4, ...) */
- if (0U != (shmem_config.buffer_count & (shmem_config.buffer_count - 1U)))
- {
- return RL_NULL;
- }
- /* buffer size must be power of two (256, 512, ...) */
- if (0U != ((shmem_config.buffer_payload_size + 16UL) & ((shmem_config.buffer_payload_size + 16UL) - 1U)))
- {
- return RL_NULL;
- }
- if ((2U * (uint32_t)shmem_config.buffer_count) >
- ((RL_WORD_ALIGN_DOWN(shmem_length - 2U * shmem_config.vring_size)) /
- (uint32_t)(shmem_config.buffer_payload_size + 16UL)))
- {
- return RL_NULL;
- }
- #else
- if ((2U * (uint32_t)RL_BUFFER_COUNT) >
- ((RL_WORD_ALIGN_DOWN(shmem_length - (uint32_t)RL_VRING_OVERHEAD)) / (uint32_t)RL_BUFFER_SIZE))
- {
- return RL_NULL;
- }
- #endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */
- #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
- if (static_context == RL_NULL)
- {
- return RL_NULL;
- }
- rpmsg_lite_dev = static_context;
- #else
- rpmsg_lite_dev = env_allocate_memory(sizeof(struct rpmsg_lite_instance));
- if (rpmsg_lite_dev == RL_NULL)
- {
- return RL_NULL;
- }
- #endif
- env_memset(rpmsg_lite_dev, 0, sizeof(struct rpmsg_lite_instance));
- #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
- status = env_init(&rpmsg_lite_dev->env, env_cfg);
- #else
- status = env_init();
- #endif
- if (status != RL_SUCCESS)
- {
- #if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1))
- env_free_memory(rpmsg_lite_dev); /* coco validated: not able to force the application to reach this line */
- #endif
- return RL_NULL; /* coco validated: not able to force the application to reach this line */
- }
- rpmsg_lite_dev->link_id = link_id;
- /*
- * Since device is RPMSG Remote so we need to manage the
- * shared buffers. Create shared memory pool to handle buffers.
- */
- #if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)
- rpmsg_lite_dev->sh_mem_base =
- (char *)RL_WORD_ALIGN_UP((uintptr_t)(char *)shmem_addr + 2U * shmem_config.vring_size);
- rpmsg_lite_dev->sh_mem_remaining = (RL_WORD_ALIGN_DOWN(shmem_length - 2U * shmem_config.vring_size)) /
- (uint32_t)(shmem_config.buffer_payload_size + 16UL);
- #else
- rpmsg_lite_dev->sh_mem_base = (char *)RL_WORD_ALIGN_UP((uintptr_t)(char *)shmem_addr + (uint32_t)RL_VRING_OVERHEAD);
- rpmsg_lite_dev->sh_mem_remaining =
- (RL_WORD_ALIGN_DOWN(shmem_length - (uint32_t)RL_VRING_OVERHEAD)) / (uint32_t)RL_BUFFER_SIZE;
- #endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */
- rpmsg_lite_dev->sh_mem_total = rpmsg_lite_dev->sh_mem_remaining;
- /* Initialize names and callbacks*/
- vq_names[0] = "rx_vq";
- vq_names[1] = "tx_vq";
- callback[0] = rpmsg_lite_rx_callback;
- callback[1] = rpmsg_lite_tx_callback;
- rpmsg_lite_dev->vq_ops = &master_vq_ops;
- /* Create virtqueue for each vring. */
- for (idx = 0U; idx < 2U; idx++)
- {
- #if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)
- ring_info.phy_addr = (void *)(char *)((uintptr_t)(char *)RL_WORD_ALIGN_UP((uintptr_t)(char *)shmem_addr) +
- (uint32_t)((idx == 0U) ? (0U) : (shmem_config.vring_size)));
- ring_info.align = shmem_config.vring_align;
- ring_info.num_descs = shmem_config.buffer_count;
- #else
- ring_info.phy_addr = (void *)(char *)((uintptr_t)(char *)RL_WORD_ALIGN_UP((uintptr_t)(char *)shmem_addr) +
- (uint32_t)((idx == 0U) ? (0U) : (VRING_SIZE)));
- ring_info.align = VRING_ALIGN;
- ring_info.num_descs = RL_BUFFER_COUNT;
- #endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */
- env_memset((void *)ring_info.phy_addr, 0x00, (uint32_t)vring_size(ring_info.num_descs, ring_info.align));
- #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
- status = virtqueue_create_static((uint16_t)(RL_GET_VQ_ID(link_id, idx)), vq_names[idx], &ring_info,
- callback[idx], virtqueue_notify, &vqs[idx],
- (struct vq_static_context *)&rpmsg_lite_dev->vq_ctxt[idx]);
- #else
- status = virtqueue_create((uint16_t)(RL_GET_VQ_ID(link_id, idx)), vq_names[idx], &ring_info, callback[idx],
- virtqueue_notify, &vqs[idx]);
- #endif /* RL_USE_STATIC_API */
- if (status == RL_SUCCESS)
- {
- /* Initialize vring control block in virtqueue. */
- vq_ring_init(vqs[idx]);
- /* Disable callbacks - will be enabled by the application
- * once initialization is completed.
- */
- virtqueue_disable_cb(vqs[idx]);
- }
- else
- {
- #if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1))
- /* Free all already allocated memory for virtqueues */
- for (uint32_t a = 0U; a < 2U; a++)
- {
- if (RL_NULL != vqs[a])
- {
- virtqueue_free(vqs[a]);
- }
- }
- env_free_memory(rpmsg_lite_dev);
- #endif
- return RL_NULL;
- }
- /* virtqueue has reference to the RPMsg Lite instance */
- vqs[idx]->priv = (void *)rpmsg_lite_dev;
- #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
- vqs[idx]->env = rpmsg_lite_dev->env;
- #endif
- }
- #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
- status = env_create_mutex((LOCK *)&rpmsg_lite_dev->lock, 1, &rpmsg_lite_dev->lock_static_ctxt);
- #else
- status = env_create_mutex((LOCK *)&rpmsg_lite_dev->lock, 1);
- #endif
- if (status != RL_SUCCESS)
- {
- #if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1))
- /* Free all already allocated memory for virtqueues */
- for (uint32_t b = 0U; b < 2U; b++)
- {
- virtqueue_free(vqs[b]);
- }
- env_free_memory(rpmsg_lite_dev);
- #endif
- return RL_NULL;
- }
- // FIXME - a better way to handle this , tx for master is rx for remote and vice versa.
- rpmsg_lite_dev->tvq = vqs[1];
- rpmsg_lite_dev->rvq = vqs[0];
- for (j = 0U; j < 2U; j++)
- {
- for (idx = 0U; ((idx < vqs[j]->vq_nentries) && (idx < rpmsg_lite_dev->sh_mem_total)); idx++)
- {
- /* Initialize TX virtqueue buffers for remote device */
- buffer = (rpmsg_lite_dev->sh_mem_remaining > 0U) ?
- (rpmsg_lite_dev->sh_mem_base +
- #if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)
- (uint32_t)(shmem_config.buffer_payload_size + 16UL) *
- (rpmsg_lite_dev->sh_mem_total - rpmsg_lite_dev->sh_mem_remaining--)) :
- #else
- (uint32_t)RL_BUFFER_SIZE *
- (rpmsg_lite_dev->sh_mem_total - rpmsg_lite_dev->sh_mem_remaining--)) :
- #endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */
- (RL_NULL);
- RL_ASSERT(buffer != RL_NULL);
- #if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)
- env_memset(buffer, 0x00, (uint32_t)(shmem_config.buffer_payload_size + 16UL));
- #else
- env_memset(buffer, 0x00, (uint32_t)RL_BUFFER_SIZE);
- #endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */
- if (vqs[j] == rpmsg_lite_dev->rvq)
- {
- #if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)
- status =
- virtqueue_fill_avail_buffers(vqs[j], buffer, (uint32_t)(shmem_config.buffer_payload_size + 16UL));
- #else
- status = virtqueue_fill_avail_buffers(vqs[j], buffer, (uint32_t)RL_BUFFER_SIZE);
- #endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */
- }
- else if (vqs[j] == rpmsg_lite_dev->tvq)
- {
- #if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)
- status =
- virtqueue_fill_used_buffers(vqs[j], buffer, (uint32_t)(shmem_config.buffer_payload_size + 16UL));
- #else
- status = virtqueue_fill_used_buffers(vqs[j], buffer, (uint32_t)RL_BUFFER_SIZE);
- #endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */
- }
- else
- {
- /* coco begin validated: this branch will never met unless RAM is corrupted */
- }
- if (status != RL_SUCCESS)
- {
- /* Clean up! */
- env_delete_mutex(rpmsg_lite_dev->lock);
- #if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1))
- for (uint32_t c = 0U; c < 2U; c++)
- {
- virtqueue_free(vqs[c]);
- }
- env_free_memory(rpmsg_lite_dev);
- #endif
- return RL_NULL;
- }
- /* coco end */
- }
- }
- /* Install ISRs */
- #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
- env_init_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->rvq->vq_queue_index, rpmsg_lite_dev->rvq);
- env_init_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->tvq->vq_queue_index, rpmsg_lite_dev->tvq);
- env_disable_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->rvq->vq_queue_index);
- env_disable_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->tvq->vq_queue_index);
- rpmsg_lite_dev->link_state = 1U;
- env_enable_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->rvq->vq_queue_index);
- env_enable_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->tvq->vq_queue_index);
- #else
- (void)platform_init_interrupt(rpmsg_lite_dev->rvq->vq_queue_index, rpmsg_lite_dev->rvq);
- (void)platform_init_interrupt(rpmsg_lite_dev->tvq->vq_queue_index, rpmsg_lite_dev->tvq);
- env_disable_interrupt(rpmsg_lite_dev->rvq->vq_queue_index);
- env_disable_interrupt(rpmsg_lite_dev->tvq->vq_queue_index);
- rpmsg_lite_dev->link_state = 1U;
- env_enable_interrupt(rpmsg_lite_dev->rvq->vq_queue_index);
- env_enable_interrupt(rpmsg_lite_dev->tvq->vq_queue_index);
- #endif
- /*
- * Let the remote device know that Master is ready for
- * communication.
- */
- virtqueue_kick(rpmsg_lite_dev->rvq);
- return rpmsg_lite_dev;
- }
- #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
- struct rpmsg_lite_instance *rpmsg_lite_remote_init(void *shmem_addr,
- uint32_t link_id,
- uint32_t init_flags,
- struct rpmsg_lite_instance *static_context)
- #elif defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
- struct rpmsg_lite_instance *rpmsg_lite_remote_init(void *shmem_addr,
- uint32_t link_id,
- uint32_t init_flags,
- void *env_cfg)
- #else
- struct rpmsg_lite_instance *rpmsg_lite_remote_init(void *shmem_addr, uint32_t link_id, uint32_t init_flags)
- #endif
- {
- int32_t status;
- void (*callback[2])(struct virtqueue *vq);
- const char *vq_names[2];
- struct vring_alloc_info ring_info;
- struct virtqueue *vqs[2] = {0};
- uint32_t idx;
- struct rpmsg_lite_instance *rpmsg_lite_dev = RL_NULL;
- if (link_id > RL_PLATFORM_HIGHEST_LINK_ID)
- {
- return RL_NULL;
- }
- if (shmem_addr == RL_NULL)
- {
- return RL_NULL;
- }
- #if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)
- /* Get the custom shmem configuration defined per each rpmsg_lite instance
- (i.e. per each link id) from the platform layer */
- rpmsg_platform_shmem_config_t shmem_config = {0};
- if (RL_SUCCESS != platform_get_custom_shmem_config(link_id, &shmem_config))
- {
- return RL_NULL;
- }
- /* shmem_config.buffer_count must be power of two (2, 4, ...) */
- if (0U != (shmem_config.buffer_count & (shmem_config.buffer_count - 1U)))
- {
- return RL_NULL;
- }
- /* buffer size must be power of two (256, 512, ...) */
- if (0U != ((shmem_config.buffer_payload_size + 16UL) & ((shmem_config.buffer_payload_size + 16UL) - 1U)))
- {
- return RL_NULL;
- }
- #endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */
- #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
- if (static_context == RL_NULL)
- {
- return RL_NULL;
- }
- rpmsg_lite_dev = static_context;
- #else
- rpmsg_lite_dev = env_allocate_memory(sizeof(struct rpmsg_lite_instance));
- if (rpmsg_lite_dev == RL_NULL)
- {
- return RL_NULL;
- }
- #endif
- env_memset(rpmsg_lite_dev, 0, sizeof(struct rpmsg_lite_instance));
- #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
- status = env_init(&rpmsg_lite_dev->env, env_cfg);
- #else
- status = env_init();
- #endif
- if (status != RL_SUCCESS)
- {
- #if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1))
- env_free_memory(rpmsg_lite_dev); /* coco validated: not able to force the application to reach this line */
- #endif
- return RL_NULL; /* coco validated: not able to force the application to reach this line */
- }
- rpmsg_lite_dev->link_id = link_id;
- vq_names[0] = "tx_vq"; /* swapped in case of remote */
- vq_names[1] = "rx_vq";
- callback[0] = rpmsg_lite_tx_callback;
- callback[1] = rpmsg_lite_rx_callback;
- rpmsg_lite_dev->vq_ops = &remote_vq_ops;
- #if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)
- rpmsg_lite_dev->sh_mem_base =
- (char *)RL_WORD_ALIGN_UP((uintptr_t)(char *)shmem_addr + 2U * shmem_config.vring_size);
- #else
- rpmsg_lite_dev->sh_mem_base = (char *)RL_WORD_ALIGN_UP((uintptr_t)(char *)shmem_addr + (uint32_t)RL_VRING_OVERHEAD);
- #endif /* defined(RL_ALLOW_CUSTOM_VRING_CONFIG) && (RL_ALLOW_CUSTOM_VRING_CONFIG == 1) */
- /* Create virtqueue for each vring. */
- for (idx = 0U; idx < 2U; idx++)
- {
- #if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)
- ring_info.phy_addr = (void *)(char *)((uintptr_t)(char *)RL_WORD_ALIGN_UP((uintptr_t)(char *)shmem_addr) +
- (uint32_t)((idx == 0U) ? (0U) : (shmem_config.vring_size)));
- ring_info.align = shmem_config.vring_align;
- ring_info.num_descs = shmem_config.buffer_count;
- #else
- ring_info.phy_addr = (void *)(char *)((uintptr_t)(char *)RL_WORD_ALIGN_UP((uintptr_t)(char *)shmem_addr) +
- (uint32_t)((idx == 0U) ? (0U) : (VRING_SIZE)));
- ring_info.align = VRING_ALIGN;
- ring_info.num_descs = RL_BUFFER_COUNT;
- #endif /* defined(RL_ALLOW_CUSTOM_VRING_CONFIG) && (RL_ALLOW_CUSTOM_VRING_CONFIG == 1) */
- #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
- status = virtqueue_create_static((uint16_t)(RL_GET_VQ_ID(link_id, idx)), vq_names[idx], &ring_info,
- callback[idx], virtqueue_notify, &vqs[idx],
- (struct vq_static_context *)&rpmsg_lite_dev->vq_ctxt[idx]);
- #else
- status = virtqueue_create((uint16_t)(RL_GET_VQ_ID(link_id, idx)), vq_names[idx], &ring_info, callback[idx],
- virtqueue_notify, &vqs[idx]);
- #endif /* RL_USE_STATIC_API */
- if (status != RL_SUCCESS)
- {
- #if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1))
- /* Free all already allocated memory for virtqueues */
- for (uint32_t a = 0U; a < 2U; a++)
- {
- if (RL_NULL != vqs[a])
- {
- virtqueue_free(vqs[a]);
- }
- }
- env_free_memory(rpmsg_lite_dev);
- #endif
- return RL_NULL;
- }
- /* virtqueue has reference to the RPMsg Lite instance */
- vqs[idx]->priv = (void *)rpmsg_lite_dev;
- #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
- vqs[idx]->env = rpmsg_lite_dev->env;
- #endif
- }
- #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
- status = env_create_mutex((LOCK *)&rpmsg_lite_dev->lock, 1, &rpmsg_lite_dev->lock_static_ctxt);
- #else
- status = env_create_mutex((LOCK *)&rpmsg_lite_dev->lock, 1);
- #endif
- if (status != RL_SUCCESS)
- {
- #if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1))
- /* Free all already allocated memory for virtqueues */
- for (uint32_t b = 0U; b < 2U; b++)
- {
- virtqueue_free(vqs[b]);
- }
- env_free_memory(rpmsg_lite_dev);
- #endif
- return RL_NULL;
- }
- // FIXME - a better way to handle this , tx for master is rx for remote and vice versa.
- rpmsg_lite_dev->tvq = vqs[0];
- rpmsg_lite_dev->rvq = vqs[1];
- /* Install ISRs */
- #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
- env_init_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->rvq->vq_queue_index, rpmsg_lite_dev->rvq);
- env_init_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->tvq->vq_queue_index, rpmsg_lite_dev->tvq);
- env_disable_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->rvq->vq_queue_index);
- env_disable_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->tvq->vq_queue_index);
- rpmsg_lite_dev->link_state = 0;
- env_enable_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->rvq->vq_queue_index);
- env_enable_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->tvq->vq_queue_index);
- #else
- (void)platform_init_interrupt(rpmsg_lite_dev->rvq->vq_queue_index, rpmsg_lite_dev->rvq);
- (void)platform_init_interrupt(rpmsg_lite_dev->tvq->vq_queue_index, rpmsg_lite_dev->tvq);
- env_disable_interrupt(rpmsg_lite_dev->rvq->vq_queue_index);
- env_disable_interrupt(rpmsg_lite_dev->tvq->vq_queue_index);
- rpmsg_lite_dev->link_state = 0;
- env_enable_interrupt(rpmsg_lite_dev->rvq->vq_queue_index);
- env_enable_interrupt(rpmsg_lite_dev->tvq->vq_queue_index);
- #endif
- return rpmsg_lite_dev;
- }
- /*******************************************
- mmmm mmmmmm mmmmm mm m mmmmm mmmmmmm
- # "m # # #"m # # #
- # # #mmmmm # # #m # # #
- # # # # # # # # #
- #mmm" #mmmmm mm#mm # ## mm#mm #
- ********************************************/
- int32_t rpmsg_lite_deinit(struct rpmsg_lite_instance *rpmsg_lite_dev)
- {
- if (rpmsg_lite_dev == RL_NULL)
- {
- return RL_ERR_PARAM;
- }
- if (!((rpmsg_lite_dev->rvq != RL_NULL) && (rpmsg_lite_dev->tvq != RL_NULL) && (rpmsg_lite_dev->lock != RL_NULL)))
- {
- /* ERROR - trying to initialize uninitialized RPMSG? */
- RL_ASSERT((rpmsg_lite_dev->rvq != RL_NULL) && (rpmsg_lite_dev->tvq != RL_NULL) &&
- (rpmsg_lite_dev->lock != RL_NULL));
- return RL_ERR_PARAM;
- }
- #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
- env_deinit_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->rvq->vq_queue_index);
- env_deinit_interrupt(rpmsg_lite_dev->env, rpmsg_lite_dev->tvq->vq_queue_index);
- #else
- (void)platform_deinit_interrupt(rpmsg_lite_dev->rvq->vq_queue_index);
- (void)platform_deinit_interrupt(rpmsg_lite_dev->tvq->vq_queue_index);
- #endif
- rpmsg_lite_dev->link_state = 0;
- #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
- virtqueue_free_static(rpmsg_lite_dev->rvq);
- virtqueue_free_static(rpmsg_lite_dev->tvq);
- #else
- virtqueue_free(rpmsg_lite_dev->rvq);
- virtqueue_free(rpmsg_lite_dev->tvq);
- #endif /* RL_USE_STATIC_API */
- rpmsg_lite_dev->rvq = RL_NULL;
- rpmsg_lite_dev->tvq = RL_NULL;
- env_delete_mutex(rpmsg_lite_dev->lock);
- #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
- (void)env_deinit(rpmsg_lite_dev->env);
- #else
- (void)env_deinit();
- #endif
- #if !(defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1))
- env_free_memory(rpmsg_lite_dev);
- #endif /* RL_USE_STATIC_API */
- return RL_SUCCESS;
- }
|