/**************************************************************************** * drivers/rpmsg/rpmsg_test.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include "rpmsg_test.h" /**************************************************************************** * Pre-processor definitions ****************************************************************************/ #define RPMSG_TEST_EPT_NAME "rpmsg-test" #define RPMSG_TEST_CMD(type, value) (((type) << 16) | (value)) #define RPMSG_TEST_GET_TYPE(cmd) ((cmd) >> 16) #define RPMSG_TEST_GET_VALUE(cmd) ((cmd) & 0xffff) /* Rpmsg test type,value and cmd definition */ #define RPMSG_TEST_TYPE_HOLD_RX 1 #define RPMSG_TEST_VAL_HOLD_RX 0 #define RPMSG_TEST_VAL_HOLD_RX_END 1 #define RPMSG_TEST_CMD_HOLD_RX \ RPMSG_TEST_CMD(RPMSG_TEST_TYPE_HOLD_RX, RPMSG_TEST_VAL_HOLD_RX) #define RPMSG_TEST_CMD_HOLD_RX_END \ RPMSG_TEST_CMD(RPMSG_TEST_TYPE_HOLD_RX, RPMSG_TEST_VAL_HOLD_RX_END) /* Magic number used in test case */ #define RPMSG_TEST_MAGIC1 0x55 #define RPMSG_TEST_MAGIC2 0xaa /**************************************************************************** * Private Types ****************************************************************************/ struct rpmsg_test_priv_s { FAR struct rpmsg_endpoint *ept; struct list_node rxhead; struct work_s work; }; begin_packed_struct struct rpmsg_test_msg_s { uint32_t node[4]; /* Used for the list node */ uint32_t cmd; uint32_t len; uint8_t data[1]; } end_packed_struct; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: rpmsg_test_memcmp ****************************************************************************/ static bool rpmsg_test_memcmp(FAR const uint8_t *buf, uint8_t ch, size_t size) { size_t i; for (i = 0; i < size; i++) { if (buf[i] != ch) { return false; } } return true; } /**************************************************************************** * Name: rpmsg_test_hold_rx_work ****************************************************************************/ static void rpmsg_test_hold_rx_work(FAR void *arg) { FAR struct rpmsg_test_priv_s *priv = arg; FAR struct rpmsg_test_msg_s *msg; bool ret; /* Check all the rx buffer value (should still be MAGIC2) and release * all the held rx buffers. */ syslog(LOG_EMERG, "Rpmsg Test: release rx buffers start\n"); while (!list_is_empty(&priv->rxhead)) { msg = (FAR struct rpmsg_test_msg_s *)list_remove_head(&priv->rxhead); ret = rpmsg_test_memcmp(msg->data, RPMSG_TEST_MAGIC2, msg->len); DEBUGASSERT(ret); rpmsg_release_rx_buffer(priv->ept, msg); } syslog(LOG_EMERG, "Rpmsg Test: release rx buffers end\n"); } /**************************************************************************** * Name: rpmsg_test_hold_rx_cb ****************************************************************************/ static void rpmsg_test_hold_rx_cb(FAR struct rpmsg_endpoint *ept, FAR void *data, size_t len, uint32_t src, FAR void *_priv) { FAR struct rpmsg_test_priv_s *priv = _priv; FAR struct rpmsg_test_msg_s *msg = data; uint32_t value = RPMSG_TEST_GET_VALUE(msg->cmd); bool ret; /* Hold the rx buffer and fill the rx buffer data with MAGIC2 */ ret = rpmsg_test_memcmp(msg->data, RPMSG_TEST_MAGIC1, msg->len); DEBUGASSERT(ret); memset(msg->data, RPMSG_TEST_MAGIC2, msg->len); rpmsg_hold_rx_buffer(ept, data); list_add_tail(&priv->rxhead, (FAR struct list_node *)data); if (value == RPMSG_TEST_VAL_HOLD_RX_END) { syslog(LOG_EMERG, "Rpmsg Test: hold rx buffer finish\n"); /* Delay 10ms to release all the rx buffers, to make sure * the hold rx buffer api is valid. */ work_queue(LPWORK, &priv->work, rpmsg_test_hold_rx_work, priv, MSEC2TICK(10)); } } /**************************************************************************** * Name: rpmsg_test_ept_cb ****************************************************************************/ static int rpmsg_test_ept_cb(FAR struct rpmsg_endpoint *ept, FAR void *data, size_t len, uint32_t src, FAR void *priv) { FAR struct rpmsg_test_msg_s *msg = data; switch (RPMSG_TEST_GET_TYPE(msg->cmd)) { case RPMSG_TEST_TYPE_HOLD_RX: rpmsg_test_hold_rx_cb(ept, data, len, src, priv); break; default: break; } return 0; } /**************************************************************************** * Name: rpmsg_test_hold_rx ****************************************************************************/ static int rpmsg_test_hold_rx(FAR struct rpmsg_test_priv_s *priv) { FAR struct rpmsg_endpoint *ept = priv->ept; FAR struct rpmsg_test_msg_s *msg; FAR struct rpmsg_test_msg_s *nmsg; uint32_t space; uint32_t nspace; int num = 0; int ret; syslog(LOG_EMERG, "Rpmsg Test: start send\n"); /* Send all the tx buffer to remote core, remote core will hold this * buffer. */ msg = rpmsg_get_tx_payload_buffer(ept, &space, false); if (msg == NULL) { return -ENOMEM; } for (; ; ) { nmsg = rpmsg_get_tx_payload_buffer(ept, &nspace, false); num++; msg->cmd = nmsg ? RPMSG_TEST_CMD_HOLD_RX : RPMSG_TEST_CMD_HOLD_RX_END; msg->len = space - sizeof(*msg) + 1; memset(msg->data, RPMSG_TEST_MAGIC1, msg->len); ret = rpmsg_send_nocopy(ept, msg, space); DEBUGASSERT(ret >= 0); if (nmsg == NULL) { break; } msg = nmsg; space = nspace; } syslog(LOG_EMERG, "Rpmsg Test: tx buffer num=%d space=%" PRIu32 "\n", num, space); syslog(LOG_EMERG, "Rpmsg Test: send finish\n"); return 0; } /**************************************************************************** * Public Functions ****************************************************************************/ int rpmsg_test(FAR struct rpmsg_endpoint *ept, unsigned long arg) { FAR struct rpmsg_test_priv_s *priv = ept->priv; /* Only support rx hold buffer test case for now */ return rpmsg_test_hold_rx(priv); } int rpmsg_test_init(FAR struct rpmsg_device *rdev, FAR struct rpmsg_endpoint *ept) { FAR struct rpmsg_test_priv_s *priv; priv = kmm_zalloc(sizeof(*priv)); if (priv == NULL) { return -ENOMEM; } list_initialize(&priv->rxhead); priv->ept = ept; ept->priv = priv; return rpmsg_create_ept(ept, rdev, RPMSG_TEST_EPT_NAME, RPMSG_ADDR_ANY, RPMSG_ADDR_ANY, rpmsg_test_ept_cb, NULL); } void rpmsg_test_deinit(FAR struct rpmsg_endpoint *ept) { FAR struct rpmsg_test_priv_s *priv = ept->priv; rpmsg_destroy_ept(ept); kmm_free(priv); }