当前位置:网站首页>[semidrive source code analysis] [x9 chip startup process] 25 - Introduction to mailbox inter core communication mechanism (code analysis) rpmsg-ipcc RTOS & QNX
[semidrive source code analysis] [x9 chip startup process] 25 - Introduction to mailbox inter core communication mechanism (code analysis) rpmsg-ipcc RTOS & QNX
2022-06-12 13:44:00 【CielleeX】
【SemiDrive Source code analysis 】【X9 Chip startup process 】25 - MailBox Introduction to inter core communication mechanism ( Code analysis ) And RPMSG-IPCC RTOS & QNX piece
- One 、RPMSG Interface
- 1.1 Linux Kernel Interface
- 1.2 Linux Kernel Sample code analysis :rpmsg-vdev.c be based on virtio Bus mode implementation RPMSG
- 1.3 Linux Kernel Sample code analysis :semidrive_ipcc.c be based on IPCC Bus mode implementation RPMSG
- 1.4 Linux User layer interface
- 1.5 RTOS API
- 1.6 【RTOS_IPCC example 】dcf\dcf_sample.c With IPCC How to achieve
- 1.7 【RTOS_VIRTIO example 】dcf\test_rpmsg_linux.c use VIRTIO How to achieve
- 1.8 【RTOS_VIRTIO】rpmsg_channel_create() Function creation rpmsg channel passageway
- 1.9 【RTOS_VIRTIO】rpmsg_channel_start() Function implementation starts rpmsg channel passageway
- 1.10 【RTOS_VIRTIO】rpmsg_channel_sendmsg /rpmsg_channel_sendto () Function to send data
- 1.11 【RTOS_VIRTIO】rpmsg_channel_recvmsg / rpmsg_channel_recvfrom() Function to receive data
- 1.12 QNX API
Ben SemiDrive Source code analysis And Yocto Source code analysis The series is summarized below :
- 《【SemiDrive Source code analysis 】【Yocto Source code analysis 】01 - yocto/base Directory source code analysis ( Compilation environment initialization process )》
- 《【SemiDrive Source code analysis 】【Yocto Source code analysis 】02 - yocto/meta-openembedded Directory source code analysis 》
- 《【SemiDrive Source code analysis 】【Yocto Source code analysis 】03 - yocto/meta-semidrive Contents and Yocto Kernel Compile process analysis ( On )》
- 《【SemiDrive Source code analysis 】【Yocto Source code analysis 】04 - yocto/meta-semidrive Contents and Yocto Kernel Compile process analysis ( Next )》
- 《【SemiDrive Source code analysis 】【Yocto Source code analysis 】05 - Look for it Yocto Kernel All during compilation Task Where is the source code defined ?》
- 《【SemiDrive Source code analysis 】【Yocto Source code analysis 】06 - Kernel Compile generated Image.bin、Image_nobt.dtb、modules.tgz How are these three files generated ?》
- 《【SemiDrive Source code analysis 】【Yocto Source code analysis 】07 - core-image-base-x9h_ref_serdes.rootfs.ext4 How the file system is generated 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】08 - X9 platform lk Directory source code analysis And catalogue 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】09 - X9 Platform system startup process analysis 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】10 - BareMetal_Suite Catalog R5 DIL.bin Bootstrap source code analysis 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】11 - freertos_safetyos Catalog Cortex-R5 DIL2.bin Bootstrap source code analysis 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】12 - freertos_safetyos Catalog Cortex-R5 DIL2.bin And sdm_display_init Display initialization source code analysis 》
- 《【SemiDrive Source code analysis 】【X9 Chip driver debugging 】13 - GPIO Configuration method 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】14 - freertos_safetyos Catalog Cortex-R5 SafetyOS/RTOS Workflow analysis 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】15 - freertos_safetyos Catalog R5 SafetyOS And tcpip_init() Code flow analysis 》
- 《【SemiDrive Source code analysis 】【X9 Audio Audio module analysis 】16 - Audio module block diagram and hardware schematic diagram analysis 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】17 - R5 SafetyOS And LK_INIT_LEVEL_PLATFORM Stage code flow analysis ( On )dcf_init Inter core communication initialization 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】18 - R5 SafetyOS And LK_INIT_LEVEL_PLATFORM Stage code flow analysis ( Next )》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】19 - MailBox Introduction to inter core communication mechanism ( Theory Chapter )》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】20 - MailBox Introduction to inter core communication mechanism ( Code analysis ) And MailBox for RTOS piece 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】21 - MailBox Introduction to inter core communication mechanism ( Code analysis ) And Mailbox for Linux piece 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】22 - MailBox Introduction to inter core communication mechanism ( Code analysis ) And RPMSG-VIRTIO Kernel piece 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】23 - MailBox Introduction to inter core communication mechanism ( Code analysis ) And RPMSG-IPCC Kernel piece 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】24 - MailBox Inter core communication mechanism related register introduction 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】25 - MailBox Introduction to inter core communication mechanism ( Code analysis ) And RPMSG-IPCC RTOS & QNX piece 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】26 - MailBox Introduction to inter core communication mechanism ( Code analysis ) And Property piece 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】27 - MailBox Introduction to inter core communication mechanism ( Code analysis ) And RPCall piece 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】28 - MailBox Introduction to inter core communication mechanism ( Code analysis ) And Notify piece 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】29 - MailBox Introduction to inter core communication mechanism ( Code analysis ) And Socket piece 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】30 - MailBox Introduction to inter core communication mechanism ( Code analysis ) And /dev/vircan piece 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】31 - freertos_safetyos Catalog R5 SafetyOS And LK_INIT_LEVEL_TARGET Stage code flow analysis 》
- 《【SemiDrive Source code analysis 】【X9 Chip startup process 】32 - freertos_safetyos Catalog R5 SafetyOS And .apps Application startup code flow analysis 》
In the previous article , We mainly introduce... From the theoretical aspect , be based on MailBox Of various scenes API,
Its characteristics are as follows :
| RTOS | Linux Kernel | Linux User | Dom0 Linux | DomU Linux | QNX | TX/RX Buffer size | Features and usage scenarios | |
|---|---|---|---|---|---|---|---|---|
| Mailbox | Support | Support | I won't support it | Support | Support | Support | RX/TX Are all 512 byte | Interrupt context callback , Low latency , No message queue , It is not recommended that users directly use |
| RPMSG-VIRTIO | Support | Support | Support | Support | I won't support it | Support | RX/TX Two loop queues Each queue supports a maximum of 512 block Buffer, Minimum 256 block each Buffer by 512 byte Memory is mainly allocated DMA Low address continuous physical memory | Large data block transmission , Use DDR Shared memory data , High throughput ,MTU The adjustable |
| RPMSG-IPCC | Support | Support | Support | Support | I won't support it | Support | Maximum number of transmission targets 16 individual Each transfer destination defaults to 512 byte , Maximum transmission 512-16=496 byte ( Can be configured as 1024 byte ) Memory uses GFP_KERNEL Part of the memory | Control command , event , Notice, etc , Interactive data is small , Less delay |
| RPCall | Support | Support | I won't support it | Support | Support | Support | To be analyzed and summarized | be based on request / reply Distributed data exchange mode of the model |
| Property | Support | Support | Support | Support | Support | Support | To be analyzed and summarized | A distributed 、 Runtime heterogeneous data storage mechanism , You can save the running status or execution results , Convenient heterogeneous OS Share certain resources between |
| Notify | Support | Support | I won't support it | Support | Support | I won't support it | To be analyzed and summarized | Short data , Low latency , One way transmission |
| Socket | No support | Support | Support | Support | Support | I won't support it | To be analyzed and summarized | Support AF_RPMSG agreement , The user layer uses , The disadvantage is that it needs to be modified Linux uapi The header file |
| /dev/vircan | NA | NA | Support | Support | Support | I won't support it | To be analyzed and summarized | Linux interview ask Safety CAN |
In the foreword 《【SemiDrive Source code analysis 】【X9 Chip startup process 】23 - MailBox Introduction to inter core communication mechanism ( Code analysis ) And RPMSG-IPCC Kernel piece 》 in ,
We analyzed and learned RPMSG-VIRTIO Kernel Partial implementation ,
But there is a problem left , It hasn't been solved yet , Namely Kernel Medium RPMSG-IPCC The only way to receive is to go echo cb This road , There is no way to see its reception ,
So it's strange , With this question , Let's analyze it today RTOS、QNX These two pieces of RPMSG-IPCC How to achieve ,
Maybe after understanding these two pieces , We'll know the answer .
RPMSG yes Remote Processor Messaging System, Remote processor message transmission system .
RPMSGIt is a data transmission protocol between heterogeneous systems .RPMSGThe standard does not specify the underlying transmission medium and method , Because of the universality of shared memory , And less dependence on specific hardware differences ,VIRTIOAs a kind ofRPMSGCommon implementation forms , It has been widely used .VIRTIOIs based onShared MemoryA data transmission standard , Including buffer and message queue management , Not only for heterogeneous multiprocessor communication , It is also commonly used inKVMVirtualized device .VirtQueueIt's a data receiving and sending queue , Contains a pair of send queues and receive queuesVring.VRingyesVirtQueueThe queue in , A method withBuffer DescriptorImplementation method of index quantization circular buffer , EveryVRingThere is only one sender and one receiver , Two way communication is requiredVRingMake a couple , The index structure and buffer of the whole queue exist in the shared memory area , Accessed by processors at both ends of the communication . in order to
Ensure the data access consistency of heterogeneous processors , Shared memory is configured as a device memory model ,Strong Order,Non-CacheableNotification mechanism of standard provisions (
notify) It's about the platform , Used on Xinchi platformMailboxHardware implementation .
One 、RPMSG Interface
Xinchi fully follows the standard RPMSG Realization , On this basis , For ease of use , Put forward RPMSG Channel Concept and a set of interface implementation .
meanwhile , In order to take advantage of Mailbox Chip characteristics of on-chip memory , Put forward IPCC Channel The concept of , That is to keep RPMSG Interface logic ,
Follow the standards RPMSG On the basis of , To replace the VIRTIO The bottom part of . These two functions can coexist , Users can choose one of them according to their needs .
IPCC Make the most of it Mailbox Features of hardware , It has independent buffer queue management and thread model , and IPCC No need for external DDR As shared memory , High for safety MCU It has obvious advantages , Recommended priority IPCC Interface functions perform the same functions .
in addition , in consideration of VIRTIO The concept of master-slave equipment is required , Usually Linux perhaps QNX The terminal is the main equipment , be responsible for Virtqueue Initialization of buffer queue , Lead to MCU If you want to use VIRTIO, The timing depends on the initialization of the master device , It will inevitably affect the start-up .
and IPCC All ends are equal , There is a mobile phone holding system during startup to ensure normal connection between both parties , It also supports abnormal situations such as restart and disconnection of one party , More in line with the requirements of functional safety .
When the user needs to use large memory transfer , Or when there is a more radical demand for bandwidth , Consider using RPMSG VIRTIO Implementation version .
increase MTU Greater single transmission capability can be obtained , Improve transmission bandwidth .
1.1 Linux Kernel Interface
1.2 Linux Kernel Sample code analysis :rpmsg-vdev.c be based on virtio Bus mode implementation RPMSG
1.3 Linux Kernel Sample code analysis :semidrive_ipcc.c be based on IPCC Bus mode implementation RPMSG
1.4 Linux User layer interface
See... For the first four sections :《【SemiDrive Source code analysis 】【X9 Chip startup process 】23 - MailBox Introduction to inter core communication mechanism ( Code analysis ) And RPMSG-IPCC Kernel piece 》
1.5 RTOS API
Zaixin Chi RTOS SDK Use in rpmsg virtio The function needs to include the following header files : #include <rpmsg_rtos.h>
rpmsg channel Based on the open source community rpmsg lite Do further encapsulation , Use virtio As data transmission , Use Mailbox As a notification of a cross nuclear event .
When using rpmsg channel Interface created endpoint After success ,Linux At the end, the corresponding virtio0( If security The domain is virtio1) Prefixed rpmsg device
rpmsg lite The code for is located in ${RTOS_SDK_TOP}/3rd/rpmsg-literpmsg channel The encapsulation layer is located at ${RTOS_SDK_TOP}/framework/service/rpmsg
rpmsg channel API Definition :
struct rpmsg_channel * rpmsg_channel_create(int rproc, int dst, const char *name);
int rpmsg_channel_start(struct rpmsg_channel *rpchn, rpmsg_msg_handler handler);
void rpmsg_channel_destroy(struct rpmsg_channel *rpchn);
status_t rpmsg_channel_stop(struct rpmsg_channel *rpchn);
void rpmsg_channel_listall(struct rpmsg_device *dev);
status_t rpmsg_channel_sendmsg(struct rpmsg_channel *rpchn, struct dcf_message *msg, int len, lk_time_t timeout);
status_t rpmsg_channel_recvmsg(struct rpmsg_channel *rpchn, struct dcf_message *msg, int msglen, lk_time_t timeout);
status_t rpmsg_channel_recvfrom(struct rpmsg_channel *rpchn, unsigned long *src, char *data, int maxlen, int *len, unsigned long timeout);
status_t rpmsg_channel_sendto(struct rpmsg_channel *rpchn, unsigned long dst, char *data, unsigned long size, unsigned long timeout);
Zaixin Chi RTOS SDK Use in IPCC The function needs to include the following header files :#include <dcf.h>
IPCC Channel API The definition is similar to the above , Please refer to the interface statement for details :${RTOS_SDK_TOP}/framework/communication/include/ipcc_device.h
Interface implementation C file :${RTOS_SDK_TOP}/framework/communication/ipcc_device.c
Reference resources SDK Sample code included in RPMSG VIRTIO: ${RTOS_SDK_TOP}/framework/test/dcf/test_rpmsg_linux.cRPMSG IPCC: ${RTOS_SDK_TOP}/framework/test/dcf/dcf_sample.c
below , Let's first learn about the example program , Let's see how to use :
1.6 【RTOS_IPCC example 】dcf\dcf_sample.c With IPCC How to achieve
stay RTOS in , function ipccc ping You will enter dcf_sample.c Source code function do_ipcc_ping() function
# buildsystem\rtos\lk_boot\framework\test\dcf\dcf_sample.c
int do_ipcc_cmd(int argc, const cmd_args *argv)
{
if (!strcmp(argv[1].str, "ping")) {
do_ipcc_ping(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "perf")) {
do_ipcc_perf(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "iperf")) {
do_ipcc_iperf(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "reset")) {
do_ipcc_reset_dev(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "list")) {
do_ipcc_listdev(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "rpc_echo")) {
do_dcf_rpc_ping(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "rpc_reg_svc")) {
do_ipcc_rpc_customize(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "rpc_gettimeofday")) {
do_dcf_rpc_gettimeofday(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "rpc_uname")) {
do_dcf_rpc_get_uname(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "rpc_failsafe")) {
do_dcf_rpc_failsafe(argc-1, &argv[1]); }
#if CONFIG_USE_SYS_PROPERTY
if (!strcmp(argv[1].str, "setprop")) {
do_set_property(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "getprop")) {
do_get_property(argc-1, &argv[1]); }
#endif
#if CONFIG_RPC_UNITTEST
if (!strcmp(argv[1].str, "rpc_ut")) {
do_rpc_ut_cmd(argc-1, &argv[1]); }
#endif
return 0;
}
STATIC_COMMAND_START
STATIC_COMMAND("ipcc", "ipcc toolbox", do_ipcc_cmd)
STATIC_COMMAND_END(dcf_sample);
Let's see do_ipcc_ping() How functions are implemented :
- analysis
IPCCArguments to the command :ipcc ping [remote Distal ] [round frequency ] [len Packet size ] - The size of the transfer cannot be greater than
512 - 16 = 496byte - take
tx_buf、rx_bufFormatted asstruct dcf_ccm_hdrType of structure - The message format is
COMM_MSG_CCM_ECHO, The opposite end will passecho endpointcallept->echo_cbTo receive parsing messages - initialization
tx_hdr->time[4]Andtx_hdr->data[IPCC_MB_MTU]The data in the two parts of memory is0 - obtain
remoteCorresponding to the far endipcc_devices[]Structure - apply
ipcc_channelpassageway , start-upipcc_channelpassageway - Start sending , Record the current time to
time[0]in ,time[2]It is used to record the time after the remote end receives it - adopt
ipcc channelStart sending , Apply for a piece ofbuffer, The address is saved atstruct rpmsg_ipcc_msg->dataIs used to save data , Then callrpmsg_dcf_dev->chan_ops->send_data()send data - receive data , Timeout time
1000ms
The whole process is relatively simple , It's easy to understand .
# buildsystem\rtos\lk_boot\framework\test\dcf\dcf_sample.c
/* Test case: ping remote cpu with payload and recv equal payload like network ping */
int do_ipcc_ping(int argc, const cmd_args *argv)
{
struct ipcc_device *dev;
struct ipcc_channel *chan;
char tx_buf[IPCC_MB_MTU] = {
0,}; // 512 - 16 = 496 byte
char rx_buf[IPCC_MB_MTU] = {
0,}; // 512 - 16 = 496 byte
int len = TEST_IPCC_PING_PAYSZ; // 64 byte Every time ping The packet size of
unsigned long remote = 0;
struct dcf_ccm_hdr *tx_hdr, *rx_hdr;
u32 round = 10; // loop ping The number of times
// 1. analysis IPCC Arguments to the command : ipcc ping [remote Distal ] [round frequency ] [len Packet size ]
if (argc == 1) {
remote = 1;
} else {
remote = argv[1].u;
if (argc == 3) {
round = argv[2].u; }
if (argc == 4) {
round = argv[2].u; len = argv[3].u; }
}
// 2. The size of the transfer cannot be greater than 496 byte
if (len > IPCC_MB_MTU) {
printf("len %d exceed MTU %d, trim\n", len, IPCC_MB_MTU); len = IPCC_MB_MTU; }
// 3. take tx_buf、rx_buf Formatted as struct dcf_ccm_hdr Type of structure
tx_hdr = (struct dcf_ccm_hdr *) tx_buf;
rx_hdr = (struct dcf_ccm_hdr *) rx_buf;
// 4. The message format is COMM_MSG_CCM_ECHO, The opposite end will pass echo endpoint call ept->echo_cb To receive parsing messages
tx_hdr->dmsg.msg_type = COMM_MSG_CCM_ECHO;
tx_hdr->dmsg.msg_len = len - sizeof(struct dcf_message);
tx_hdr->dmsg.opflags |= DCF_MSGF_TMS;
// 5. initialization tx_hdr->time[4] And tx_hdr->data[IPCC_MB_MTU] The data in the two parts of memory is 0
memset(&tx_hdr->time[0], 0, sizeof(tx_hdr->time));
memset(&tx_hdr->data[0], COMM_MSG_CCM_ECHO, len - sizeof(struct dcf_ccm_hdr));
printf("PING rproc%d %d(%d) bytes of data\n", remote, len, len + IPCC_TRANSPORT_HDRLEN);
// 6. obtain remote Corresponding to the far end ipcc_devices[] Structure
dev = ipcc_device_gethandle(remote, 1000);
-----> struct ipcc_device *dev = find_device_by_rproc(rproc);
============================>
+ struct ipcc_device *dev = NULL;
+ for (i = 0;i < MAX_DEVICE_NUM;i++) {
+ dev = &ipcc_devices[i];
+ if (dev->used && rproc == dev->config.rproc) {
+ return dev;
+ }
+ }
<============================
// 7. apply ipcc_channel passageway
chan = ipcc_channel_create(dev, RPMSG_TEST_EPT, RPMSG_TEST_EPT_NAME, false);
============================>
+ struct ipcc_channel * ipcc_channel_create(struct ipcc_device *dev, int endpoint, const char *name, bool announce){
+ struct ipcc_channel *ichan;
+ ichan = calloc(1, sizeof(struct ipcc_channel));
+
+ event_init(&ichan->initialized, false, EVENT_FLAG_AUTOUNSIGNAL);
+ sd_rpbuf_init_queue(&ichan->rxq);
+ sem_init(&ichan->rxq_wait, 0);
+
+ ichan->rproc = dev->config.rproc;
+ ichan->addr = endpoint;
+ ichan->state = DCF_STATE_Initializing;
+ ichan->mtu = DCF_MSG_MAX_LEN;
+ ichan->parent = dev;
+ ichan->announce = announce;
+ ichan->last_announced = 0;
+ ichan->endpoint = rpmsg_dcf_create_ept(dev->rpmsg_dev, ichan->addr, ipcc_channel_rx_cb, ichan); // Put the received data in the callback function &ichan->rxq in
+
+ attach_channel(dev, ichan);
+ strncpy(ichan->name, name, 16);
+ ichan->state = DCF_STATE_Initialized;
+ return ichan;
+ }
<============================
// 8. start-up ipcc_channel passageway
ipcc_channel_start(chan, NULL);
do {
start_time = current_time_hires();
// 9. Start sending , Record the current time to time[0] in , time[2] It is used to record the time after the remote end receives it
/* use the time[0] for the sending, time[2] for receving in remote */
tx_hdr->time[0] = syscnt_get_cnt();
tx_hdr->seq = tx_count;
// 10. adopt Ipcc channel Start sending , Apply for a piece of buffer, The address is saved at struct rpmsg_ipcc_msg->data Is used to save data , Then call send_data send data
ret = ipcc_channel_sendto(chan, IPCC_ECHO_EPT, tx_buf, len, 100);
------> return rpmsg_dcf_send(ichan->parent->rpmsg_dev, ichan->endpoint, dst, data, size, (unsigned long)timeout);
==========> return rpmsg_dcf_format_message(rpmsg_dcf_dev, ept->addr, dst, data, size, DCF_NO_FLAGS, timeout);
=======================>
+ buffer = rpmsg_dcf_dev->chan_ops->send_alloc(rpmsg_dcf_dev->tvq, &buff_len, &idx);
+ rpmsg_msg = (struct rpmsg_ipcc_msg *)buffer;
+ /* Initialize RPMSG header. */
+ rpmsg_msg->hdr.dst = dst;
+ rpmsg_msg->hdr.src = src;
+ rpmsg_msg->hdr.len = size;
+ rpmsg_msg->hdr.flags = flags;
+ /* Copy data to rpmsg buffer. */
+ memcpy(rpmsg_msg->data, data, size);
+ /* Enqueue buffer on sd_ipcc_chan. */
+ status = rpmsg_dcf_dev->chan_ops->send_data(rpmsg_dcf_dev->tvq, buffer, buff_len, idx);
<========================
tx_time = current_time_hires();
tx_count++;
// 11. receive data , Timeout time 1000ms
ret = ipcc_channel_recvfrom(chan, &src, rx_buf, &len, 1000);
---> rpbuf = recv_rpbuf_timed(ichan, timeout); ret = recvfrom_timed(ichan, src, data, len, timeout);
=====> return rpmsg_dcf_copy_payload(rpmsg_dev, rpbuf, src, data, len);
===========> rpmsg_msg = (struct rpmsg_ipcc_msg *) rpbuf->buffer; *len = rpmsg_msg->hdr.len; memcpy(data, get_payload(rpbuf), *len);
end_time = current_time_hires();
......
} while (tx_count < round);
printf("%d packets transmitted, %d packets received, %.02f%% loss, time %ld us\n", tx_count, rx_count, 100 - 100 * (float)(rx_count/round), rtt_total);
printf("rtt min/avg/max = %llu/%llu/%llu us\n", rtt_min, rtt_total/rx_count, rtt_max);
ipcc_channel_stop(chan);
ipcc_channel_destroy(chan);
return 0;
}
1.6.1 【RTOS_IPCC】dcf\dcf_sample.c receive data ipcc_send_data()
# buildsystem\rtos\lk_boot\framework\communication\ipcc_rpmsg.c
/* Interface used in case this processor is MASTER */
static const struct dcf_ipcc_ops master_chan_ops = {
ipcc_send_data, ipcc_send_data_nocopy, send_alloc_buffer, ipcc_rx_data, recv_free_buffer,
};
static int ipcc_send_data(sd_ipcc_chan_t *tvq, void *buffer, uint32_t len, uint16_t idx){
int status;
status = sd_ipcc_chan_send_data(tvq, buffer, len);
======> status = sd_ipcc_chan_send_data(tvq, buffer, len);
return status;
}
Let's see sd_ipcc_chan_send_data() What did you do :
# buildsystem\rtos\lk_boot\hal\mbox_hal\sd_mbox_hal\src\mbox_hal.c
int sd_ipcc_chan_send_data(sd_ipcc_chan_t *chan, u8 *dat, u32 len)
{
ret = hal_mb_send_data(chan->mb_chan, dat, len_short, timeout);
====> return hal_mb_send_data_detail(chan, data, len, MB_MSG_PROTO_DFT, cl->low_latency, chan->dest_addr, timeout);
return ret;
}
Let's see hal_mb_send_data_detail() Implementation code :
# buildsystem\rtos\lk_boot\hal\mbox_hal\sd_mbox_hal\src\mbox_hal.c
int hal_mb_send_data_detail(hal_mb_chan_t *chan, u8 *data, u16 len, int proto, int priority, u8 dest, lk_time_t timeout)
{
hal_mb_client_t cl = containerof(chan, struct _hal_mbox_client, mchan);
u8 *msg_buf;
sd_msghdr_t *msg;
ret = __alloc_avail_buf(chan);
msg_buf = chan->msg_data[ret];
msg = (sd_msghdr_t *)msg_buf;
mb_msg_init_head(msg, chan->remote_proc, proto, priority, len, dest);
memcpy(msg->data, data, len);
/* wait for a while, 1000 ms for hardcode */
ret = __send_data_sync(chan, (u8 *)msg, timeout);
__free_used_buf(chan);
return ret;
}
Let's see __send_data_sync() What has been achieved :
# buildsystem\rtos\lk_boot\hal\mbox_hal\sd_mbox_hal\src\mbox_hal.c
static status_t __send_data_sync(hal_mb_chan_t *chan, u8 *data, lk_time_t timeout)
{
hal_mb_client_t cl = containerof(chan, struct _hal_mbox_client, mchan);
u32 spin_usec = MB_TX_MAX_ACK_TIME;
int ret = 0;
lk_time_t end_time;
end_time = current_time() + timeout;
do {
ret = sd_mbox_send_data(chan->hwchan, data);
} while ((ret == ERR_NO_MSG) && TIME_LT(current_time(), end_time));
while (!sd_mbox_last_tx_done(chan->hwchan)) {
thread_sleep(1);
}
}
Data saved in data in , Then call sd_mbox_send_data() send data , Write register BM_TMC0_TMC0_MSG_SEND Trigger send ,
I won't go into details , The previous article introduced registers in great detail .
# buildsystem\rtos\lk_boot\chipdev\mailbox\sd_mbox\mb_controller.c
int sd_mbox_send_data(struct sd_mbox_chan *mlink, u8 *data)
{
struct sd_mbox_device *mbdev = mlink->mbox;
int prefer_msg;
mlink->actual_size = mb_msg_parse_packet_len(data);
mlink->priority = mb_msg_parse_packet_prio(data);
mlink->protocol = mb_msg_parse_packet_proto(data);
mlink->dest_addr = mb_msg_parse_addr(data);
prefer_msg = (mlink->protocol == MB_MSG_PROTO_ROM) ? 1 : 0;
if (!mlink->msg) {
mlink->msg = sd_mu_alloc_msg(mbdev, prefer_msg, mlink->priority);
mlink->msg->remote = mlink->target;
mlink->msg->client = mlink->cl_data;
}
dprintf(SPEW, "mu: send_data proto: %d length: %d msg: %d\n", mlink->protocol, mlink->actual_size, mlink->msg->msg_id);
if (MB_MSG_PROTO_ROM == mlink->protocol) {
ret = sd_mu_write_rom_msg(mlink, data);
} else if (MB_MSG_PROTO_DSP == mlink->protocol) {
ret = sd_mu_write_rom_msg(mlink, data);
} else {
ret = sd_mu_fill_tmh(mlink);
sd_mu_write_msg(mlink, data);
}
sd_mu_send_msg(mlink->msg);
=======> writel(readl(msg->tmc) | BM_TMC0_TMC0_MSG_SEND, msg->tmc);
return ret;
}
1.7 【RTOS_VIRTIO example 】dcf\test_rpmsg_linux.c use VIRTIO How to achieve
# buildsystem\rtos\lk_boot\framework\test\dcf\test_rpmsg_linux.c
int do_rpmsg_cmd(int argc, const cmd_args *argv){
if (!strcmp(argv[1].str, "start")) {
do_start_rpmsg_service(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "reset")) {
do_reset_rpmsg_service(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "open")) {
do_rpmsg_open_close(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "list")) {
do_rpmsg_listdev(argc-1, &argv[1]);}
if (!strcmp(argv[1].str, "ping")) {
do_rpmsg_ping(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "echo_test")) {
do_rpmsg_echo_test(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "iperf")) {
do_rpmsg_iperf(argc-1, &argv[1]); }
if (!strcmp(argv[1].str, "perf")) {
do_rpmsg_perf(argc-1, &argv[1]); }
}
STATIC_COMMAND_START
STATIC_COMMAND("rpmsg", "rpmsg toolbox and test", do_rpmsg_cmd)
STATIC_COMMAND_END(test_rpmsg_linux);
With iperf For example :
# buildsystem\rtos\lk_boot\framework\test\dcf\test_rpmsg_linux.c
int start_rpmsg_perf_test(int remote, int round, int size)
{
struct rpmsg_channel *chan;
char send_buf[RPMSG_PKT_MTU] = {
0,};
char rx_buf[RPMSG_TACK_LEN] = {
0,};
int len = RPMSG_PKT_MTU;
int recvd = 4;
printf("Buffer size rproc%d %d(%d) bytes of data\n", remote, len, len + RPMSG_PKT_HDRLEN);
chan = rpmsg_channel_create(remote, RPMSG_TEST_EPT, RPMSG_TEST_EPT_NAME);
rpmsg_channel_start(chan, NULL);
memset(send_buf, COMM_MSG_CCM_ACK, len);
do {
ret = rpmsg_channel_sendto(chan, RPMSG_ECHO_EPT, send_buf, len, 100);
tx_count++;
recvd = RPMSG_TACK_LEN;
ret = rpmsg_channel_recvfrom(chan, &src, rx_buf, RPMSG_PKT_MTU, &recvd, 1000);
if (recvd != RPMSG_TACK_LEN || strncmp(rx_buf, RPMSG_TACK_CODE, recvd)) {
// Check whether the received security string is "ACK"
break;
}
rx_count++;
memset(rx_buf, 0, recvd);
} while (tx_count < round);
printf("%d packets transmitted, %d acked, %.02f%% loss, time %ld us\n",
tx_count, rx_count, 100 - 100 * (float)(rx_count/round), rtt_total);
printf("rtt min/avg/max = %llu/%llu/%llu us\n", rtt_min, rtt_total/rx_count, rtt_max);
printf("throughput avg. = %.2f MB/s\n", (float)(rx_count * len)/rtt_total);
rpmsg_channel_stop(chan);
rpmsg_channel_destroy(chan);
return 0;
}
The code doesn't explain , A look at will understand .
1.8 【RTOS_VIRTIO】rpmsg_channel_create() Function creation rpmsg channel passageway
# rtos\lk_boot\framework\service\rpmsg\rpmsg_channel.c
struct rpmsg_channel *rpmsg_channel_create(int rproc, int endpoint, const char *name){
struct rpmsg_channel *rpchn = calloc(1, sizeof(struct rpmsg_channel));
event_init(&rpchn->initialized, false, EVENT_FLAG_AUTOUNSIGNAL);
rpchn->rproc = rproc;
rpchn->addr = endpoint;
rpchn->state = DCF_STATE_Initializing;
rpchn->mtu = DCF_MSG_MAX_LEN;
rpchn->parent = rpmsg_device_get_handle(rpchn->rproc, RPMC_INIT_TIMEOUT);
rpchn->rpmsg_dev = rpchn->parent->rl_instance;
// Apply for one vring ring buffer, Used to receive data , The quantity is vq->vq_nentries = ring->num_descs
rpchn->msg_queue = rpmsg_queue_create(rpchn->rpmsg_dev);
-------> status = env_create_queue(&q, rpmsg_lite_dev->rvq->vq_nentries, sizeof(rpmsg_queue_rx_cb_data_t));
rpchn->endpoint = rpmsg_lite_create_ept(rpchn->rpmsg_dev, rpchn->addr, rpmsg_queue_rx_cb, rpchn->msg_queue);
rpmsg_device_add_channel(rpchn->parent, rpchn);
strncpy(rpchn->name, name, DCF_NAM_MAX_LEN);
rpchn->state = DCF_STATE_Initialized;
return rpchn;
}
1.9 【RTOS_VIRTIO】rpmsg_channel_start() Function implementation starts rpmsg channel passageway
# rtos\lk_boot\framework\service\rpmsg\rpmsg_channel.c
int rpmsg_channel_start(struct rpmsg_channel *rpchn, rpmsg_msg_handler handler)
{
struct rpmsg_device *dev = rpchn->parent;
/* connecting with remote side */
if (!dev->config.is_master) {
rpmsg_ns_announce(rpchn->rpmsg_dev, rpchn->endpoint, rpchn->name, RL_NS_CREATE);
}
/* if specify msg handler, spawn a thread to receive msg and call handler */
if (handler) {
rpchn->msg_handler = handler;
/* start up a thread to process message queue */
thread_resume(thread_create(rpchn->name, rpmsg_looper_thread, rpchn, THREAD_PRI_RPMSG_CHN, CONFIG_RPMSG_STACK_SIZE));
event_wait(&rpchn->initialized);
} else
rpchn->state = DCF_STATE_Connected;
dprintf(INFO, "rpmsg channel %s:%d->%d connected\n",
rpchn->name, dcf_get_this_proc(), rpchn->rproc);
return 0;
}
1.10 【RTOS_VIRTIO】rpmsg_channel_sendmsg /rpmsg_channel_sendto () Function to send data
# rtos\lk_boot\framework\service\rpmsg\rpmsg_channel.c
status_t rpmsg_channel_sendmsg(struct rpmsg_channel *rpchn, struct dcf_message *msg, int len, lk_time_t timeout)
{
return rpmsg_lite_send(rpchn->rpmsg_dev, rpchn->endpoint, rpchn->addr, (char *)msg, len, timeout);
=====> return rpmsg_lite_format_message(rpmsg_lite_dev, ept->addr, dst, data, size, RL_NO_FLAGS, timeout);
}
int rpmsg_lite_format_message(struct rpmsg_lite_instance *rpmsg_lite_dev, unsigned long src, unsigned long dst, char *data, unsigned long size, int flags, unsigned long timeout)
{
struct rpmsg_std_msg *rpmsg_msg;
void *buffer;
unsigned long tick_count = 0;
/* Get rpmsg buffer for sending message. */
buffer = rpmsg_lite_dev->vq_ops->vq_tx_alloc(rpmsg_lite_dev->tvq, &buff_len, &idx);
while (!buffer)
{
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 += RL_MS_PER_INTERVAL;
if ((tick_count >= timeout) && (!buffer))
{
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 = size;
rpmsg_msg->hdr.flags = flags;
/* Copy data to rpmsg buffer. */
env_memcpy(rpmsg_msg->data, data, size);
virtqueue_kick(rpmsg_lite_dev->tvq);
}
1.11 【RTOS_VIRTIO】rpmsg_channel_recvmsg / rpmsg_channel_recvfrom() Function to receive data
# rtos\lk_boot\framework\service\rpmsg\rpmsg_channel.c
status_t rpmsg_channel_recvmsg(struct rpmsg_channel *rpchn, struct dcf_message *msg, int msglen, lk_time_t timeout)
{
ret = rpmsg_queue_recv(rpchn->rpmsg_dev, rpchn->msg_queue, &src, (char *)msg, msglen, &len, timeout);
return 0;
}
# rtos\lk_boot\framework\service\rpmsg\rpmsg_channel.c
/* user rx by itself, no internal loop reciever */
status_t rpmsg_channel_recvfrom(struct rpmsg_channel *rpchn, unsigned long *src, char *data, int maxlen, int *len, unsigned long timeout)
{
return rpmsg_queue_recv(rpchn->rpmsg_dev, rpchn->msg_queue, src,
data, maxlen, len, timeout);
}
int rpmsg_queue_recv(struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_queue_handle q,
unsigned long *src, char *data, int maxlen,int *len, unsigned long timeout)
{
rpmsg_queue_rx_cb_data_t msg = {
0};
/* Get an element out of the message queue for the selected endpoint */
if (env_get_queue((void *)q, &msg, timeout)){
env_memcpy(data, msg.data, msg.len);
/* Return used buffers. */
rpmsg_lite_release_rx_buffer(rpmsg_lite_dev, msg.data);
}
}
int rpmsg_lite_release_rx_buffer(struct rpmsg_lite_instance *rpmsg_lite_dev, void *rxbuf)
{
struct rpmsg_std_msg *rpmsg_msg;
struct rpmsg_hdr_reserved *reserved = RL_NULL;
#if defined(RL_DEBUG_CHECK_BUFFERS) && (RL_DEBUG_CHECK_BUFFERS == 1)
RL_ASSERT(
/* master check */
((rpmsg_lite_dev->vq_ops == &master_vq_ops) &&
(rxbuf >= (void *)rpmsg_lite_dev->sh_mem_base) &&
(rxbuf <= (void *)(rpmsg_lite_dev->sh_mem_base + (RL_BUFFER_COUNT*RL_BUFFER_SIZE)))) ||
/* remote check */
((rpmsg_lite_dev->vq_ops == &remote_vq_ops) &&
(rxbuf >= (void *)(rpmsg_lite_dev->sh_mem_base + (RL_BUFFER_COUNT*RL_BUFFER_SIZE))) &&
(rxbuf <= (void *)(rpmsg_lite_dev->sh_mem_base + (2*RL_BUFFER_COUNT*RL_BUFFER_SIZE))))
)
#endif
rpmsg_msg = RPMSG_STD_MSG_FROM_BUF(rxbuf);
/* Get the pointer to the reserved field that contains buffer size and the index */
reserved = (struct rpmsg_hdr_reserved *)&rpmsg_msg->hdr.reserved;
/* Return used buffer, with total length (header length + buffer size). */
rpmsg_lite_dev->vq_ops->vq_rx_free(rpmsg_lite_dev->rvq, rpmsg_msg, (unsigned long)virtqueue_get_buffer_length(rpmsg_lite_dev->rvq, reserved->idx), reserved->idx);
return RL_SUCCESS;
}
/* 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,
};
static void *vq_rx_master(struct virtqueue *rvq, unsigned long *len, unsigned short *idx)
{
return virtqueue_get_buffer(rvq, (uint32_t *)len, idx);
}
1.12 QNX API
from X9 PTG3.9 Publish start , Inter core communication is officially supported QNX, Reference code echo_test.c Through the and Linux RPMSG Similar interfaces interact with other cores .
at present QNX API Support character type and traditional type .
Character device type :
compatiblePOSIXFile operations , adoptopen,close,write,readInterface opens inter core communicationendpoint.Traditional type :
adoptRPMSGPeculiarAPI,bufferProcessing data receiving and sending , It can provide lower level developers with higher fine-grained control .
Character type interface is the encapsulation of traditional types , Convenient for users , For ordinary users , Character device types are simpler and more convenient , Recommended .
For detailed use, please refer toSemidrive QNX SDKIncidental echo_test Program .
And Linux The slightly different user layer interface is ,QNX On the system RPMSG The equipment name is modified to /dev/rpmsgX In the form of .X It's a decimal number , The correspondence is as follows :
| /dev/rpmsgX | RPSMG The physical layer | Peer processor | remarks |
|---|---|---|---|
| 0 | Virtio | Safety | |
| 1 | Virtio | Secure | |
| 2 | Virtio | MP core | be used for G9 series |
| 3 | IPCC | AP1 IVI | be used for X9HP QNX Meter |
| 10 | IPCC | Safety | |
| 11 | IPCC | Secure | |
| 12 | IPCC | MP Core |
For the time being, we will not engage in QNX , therefore QNX Code , Just don't look at it first , Interested brothers , Go by yourself ,
I can tell you ,QNX710 Mailbox Relevant codes are located in :QNX710\bsp\BSP_SemiDrive_X9H_br-710_be-710_SVN954750_JBN32\src\hardware\support\semidrive
The screenshot is as follows :
Learning words , Suggestion or from test Start to look at , Code is located :QNX710\bsp\BSP_SemiDrive_X9H_br-710_be-710_SVN954750_JBN32\src\hardware\support\semidrive\rpmsg\test\rpmsg-test.c
of MailBox Code , Read some , The principles are quite different , Continue to look at It will take a long time to finish .
But the current project , I guess I have the most 10 Days preparation time , It's too late to read the code slowly .
of MailBox , In principle , I've almost understood , It doesn't make much sense to keep looking at the code ,
want With specific drive , Write according to the reference example , The basic problem is not big .
Next , Let's go on with the analysis RTOS After starting the process .
边栏推荐
- Debug code to quickly locate the error location
- Explanation of static and extern keywords
- Introduction to color coding format
- Byte order data read / write
- Ffmpeg Learning Guide
- Factory mode of "object creation" mode
- It is enough to read this article. Web Chinese development
- What if the MySQL installation on the apple computer is completed and cannot be found
- Use of awlive structures
- C language structure
猜你喜欢

D1 Nezha Development Board understands the basic startup and loading process

D1 哪吒开发板 了解基本的启动加载流程

Innovation training (XI) summary of some bugs in the development process

Automatic Generation of Visual-Textual Presentation Layout

安装MySQL时出错,照着下面这个链接,做到cmd就不行了

上海解封背后,这群开发者“云聚会”造了个AI抗疫机器人

A method of quickly creating test window

Transmission and response of events and use cases

Application of binary search -- finding the square root sqrt of a number

C#DBHelper_ FactoryDB_ GetConn
随机推荐
Resume NFT platform trustrecruit joined Octopus network as a candidate application chain
618 entered the second half of the period, apple occupied the high-end market, and the domestic mobile phones finally undercut the price competition
Codeforces 1638 D. Big Brush —— BFS
Codeforces 1637 A. sorting parts - simple thinking
jsp跳转问题,不能显示数据库数据,并且不能跳转
Codeforces 1637 E. best pair - Thinking
C language implementation of string and memory library functions
Codeforces 1637 B. mex and array - reading, violence
GPUImage链式纹理的简单实现
Introduction to application design scheme of intelligent garbage can voice chip, wt588f02b-8s
Data type conversion and conditional control statements
1001:Hello,World
Successfully rated Tencent t3-2, 10000 word parsing
【刷题篇】超级洗衣机
Pytorch framework
1002: output the second integer
2064: [example 2.1] exchange value
Codeforces 1629 F2. Game on sum (hard version) - Yang Hui's triangle, violence, finding rules
Codeforces 1629 C. Mexico array - simple greed
Time processing in C language (conversion between string and timestamp)