sample: openamp: Add OpenAMP performance test.

Add a simple sample that tries to answer the silly question: how fast
can I move data from one core to another using OpenAMP?

It depends on a lot of factors but at least we can use this sample as a
skeleton to build tests on top.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
Carlo Caione 2021-10-04 09:34:18 +02:00 committed by Anas Nashif
commit 993cb4cd62
12 changed files with 785 additions and 0 deletions

View file

@ -0,0 +1,39 @@
#
# Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
#
# SPDX-License-Identifier: Apache-2.0
#
cmake_minimum_required(VERSION 3.20.0)
set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/openamp_remote-prefix/src/openamp_remote-build/zephyr)
if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp")
set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet")
else()
message(FATAL_ERROR "${BOARD} was not supported for this sample")
endif()
message(INFO " ${BOARD} compile as Master in this sample")
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(openamp_performance)
enable_language(C ASM)
target_sources(app PRIVATE src/main.c)
include(ExternalProject)
ExternalProject_Add(
openamp_performance_remote
SOURCE_DIR ${APPLICATION_SOURCE_DIR}/remote
INSTALL_COMMAND "" # This particular build system has no install command
CMAKE_CACHE_ARGS -DBOARD:STRING=${BOARD_REMOTE}
CMAKE_CACHE_ARGS -DDTC_OVERLAY_FILE:STRING=${DTC_OVERLAY_FILE}
BUILD_BYPRODUCTS "${REMOTE_ZEPHYR_DIR}/${KERNEL_BIN_NAME}"
# NB: Do we need to pass on more CMake variables?
BUILD_ALWAYS True
)
target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

View file

@ -0,0 +1,41 @@
# Private config options for openamp sample app
# Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
# SPDX-License-Identifier: Apache-2.0
# Workaround for not being able to have commas in macro arguments
DT_CHOSEN_Z_IPC_SHM := zephyr,ipc_shm
DT_CHOSEN_Z_IPC_TX := zephyr,ipc_tx
DT_CHOSEN_Z_IPC_RX := zephyr,ipc_rx
config OPENAMP_IPC_SHM_BASE_ADDRESS
hex
default "$(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_IPC_SHM))"
help
This option specifies base address of the memory region to
be used for the OpenAMP IPC shared memory
config OPENAMP_IPC_SHM_SIZE
hex
default "$(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_IPC_SHM))"
help
This option specifies size of the memory region to be used
for the OpenAMP IPC shared memory
config OPENAMP_IPC_DEV_TX_NAME
string
default "$(dt_chosen_label,$(DT_CHOSEN_Z_IPC_TX))" if !IPM_NRFX
default "IPM_1" if (IPM_NRFX && OPENAMP_MASTER)
default "IPM_0" if (IPM_NRFX && OPENAMP_SLAVE)
help
This option specifies the device name for the IPC device to be used (TX)
config OPENAMP_IPC_DEV_RX_NAME
string
default "$(dt_chosen_label,$(DT_CHOSEN_Z_IPC_RX))" if !IPM_NRFX
default "IPM_0" if (IPM_NRFX && OPENAMP_MASTER)
default "IPM_1" if (IPM_NRFX && OPENAMP_SLAVE)
help
This option specifies the device name for the IPC device to be used (RX)
source "Kconfig.zephyr"

View file

@ -0,0 +1,10 @@
CONFIG_BOARD_ENABLE_CPUNET=y
CONFIG_IPM=y
CONFIG_IPM_NRFX=y
CONFIG_IPM_MSG_CH_0_ENABLE=y
CONFIG_IPM_MSG_CH_1_ENABLE=y
CONFIG_IPM_MSG_CH_0_RX=y
CONFIG_IPM_MSG_CH_1_TX=y

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef COMMON_H__
#define COMMON_H__
#define VDEV_START_ADDR CONFIG_OPENAMP_IPC_SHM_BASE_ADDRESS
#define VDEV_SIZE CONFIG_OPENAMP_IPC_SHM_SIZE
#define VDEV_STATUS_ADDR VDEV_START_ADDR
#define VDEV_STATUS_SIZE 0x400
#define SHM_START_ADDR (VDEV_START_ADDR + VDEV_STATUS_SIZE)
#define SHM_SIZE (VDEV_SIZE - VDEV_STATUS_SIZE)
#define SHM_DEVICE_NAME "sramx.shm"
#define VRING_COUNT 2
#define VRING_RX_ADDRESS (VDEV_START_ADDR + SHM_SIZE - VDEV_STATUS_SIZE)
#define VRING_TX_ADDRESS (VDEV_START_ADDR + SHM_SIZE)
#define VRING_ALIGNMENT 4
#define VRING_SIZE 16
struct payload {
unsigned long cnt;
unsigned long size;
unsigned char data[];
};
#endif

View file

@ -0,0 +1,9 @@
CONFIG_PRINTK=y
CONFIG_IPM=y
CONFIG_TIMESLICE_SIZE=1
CONFIG_MAIN_STACK_SIZE=2048
CONFIG_HEAP_MEM_POOL_SIZE=4096
CONFIG_OPENAMP=y
CONFIG_OPENAMP_SLAVE=n

View file

@ -0,0 +1,19 @@
#
# Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
#
# SPDX-License-Identifier: Apache-2.0
#
cmake_minimum_required(VERSION 3.20.0)
if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpunet")
message(INFO " ${BOARD} compiles as remote in this sample")
else()
message(FATAL_ERROR "${BOARD} was not supported for this sample")
endif()
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(openamp_performance_remote)
target_sources(app PRIVATE src/main.c)
target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..)

View file

@ -0,0 +1,41 @@
# Private config options for openamp sample app
# Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
# SPDX-License-Identifier: Apache-2.0
# Workaround for not being able to have commas in macro arguments
DT_CHOSEN_Z_IPC_SHM := zephyr,ipc_shm
DT_CHOSEN_Z_IPC_TX := zephyr,ipc_tx
DT_CHOSEN_Z_IPC_RX := zephyr,ipc_rx
config OPENAMP_IPC_SHM_BASE_ADDRESS
hex
default "$(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_IPC_SHM))"
help
This option specifies base address of the memory region to
be used for the OpenAMP IPC shared memory
config OPENAMP_IPC_SHM_SIZE
hex
default "$(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_IPC_SHM))"
help
This option specifies size of the memory region to be used
for the OpenAMP IPC shared memory
config OPENAMP_IPC_DEV_TX_NAME
string
default "$(dt_chosen_label,$(DT_CHOSEN_Z_IPC_TX))" if !IPM_NRFX
default "IPM_1" if (IPM_NRFX && OPENAMP_MASTER)
default "IPM_0" if (IPM_NRFX && OPENAMP_SLAVE)
help
This option specifies the device name for the IPC device to be used (TX)
config OPENAMP_IPC_DEV_RX_NAME
string
default "$(dt_chosen_label,$(DT_CHOSEN_Z_IPC_RX))" if !IPM_NRFX
default "IPM_0" if (IPM_NRFX && OPENAMP_MASTER)
default "IPM_1" if (IPM_NRFX && OPENAMP_SLAVE)
help
This option specifies the device name for the IPC device to be used (RX)
source "Kconfig.zephyr"

View file

@ -0,0 +1,8 @@
CONFIG_IPM=y
CONFIG_IPM_NRFX=y
CONFIG_IPM_MSG_CH_0_ENABLE=y
CONFIG_IPM_MSG_CH_1_ENABLE=y
CONFIG_IPM_MSG_CH_0_TX=y
CONFIG_IPM_MSG_CH_1_RX=y

View file

@ -0,0 +1,7 @@
CONFIG_PRINTK=y
CONFIG_IPM=y
CONFIG_HEAP_MEM_POOL_SIZE=4096
CONFIG_OPENAMP=y
CONFIG_OPENAMP_MASTER=n

View file

@ -0,0 +1,252 @@
/*
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <drivers/ipm.h>
#include <sys/printk.h>
#include <device.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openamp/open_amp.h>
#include <metal/device.h>
#include "common.h"
#define READ_BUFFER (1)
#define APP_TASK_STACK_SIZE (1024)
static const struct device *ipm_tx_handle;
static const struct device *ipm_rx_handle;
static struct virtqueue *vq[2];
static volatile struct payload *received_data;
#if READ_BUFFER
static volatile uint8_t *buffer;
static int max_payload_size;
#endif
static K_SEM_DEFINE(data_sem, 0, 1);
static struct rpmsg_endpoint ep;
static metal_phys_addr_t shm_physmap[] = { SHM_START_ADDR };
static struct metal_device shm_device = {
.name = SHM_DEVICE_NAME,
.bus = NULL,
.num_regions = 1,
{
{
.virt = (void *) SHM_START_ADDR,
.physmap = shm_physmap,
.size = SHM_SIZE,
.page_shift = 0xffffffff,
.page_mask = 0xffffffff,
.mem_flags = 0,
.ops = { NULL },
},
},
.node = { NULL },
.irq_num = 0,
.irq_info = NULL
};
static struct virtio_vring_info rvrings[2] = {
[0] = {
.info.align = VRING_ALIGNMENT,
},
[1] = {
.info.align = VRING_ALIGNMENT,
},
};
static unsigned char virtio_get_status(struct virtio_device *vdev)
{
return sys_read8(VDEV_STATUS_ADDR);
}
static uint32_t virtio_get_features(struct virtio_device *vdev)
{
return BIT(VIRTIO_RPMSG_F_NS);
}
static void virtio_notify(struct virtqueue *vq)
{
ipm_send(ipm_tx_handle, 0, 0, NULL, 0);
}
static struct virtio_dispatch dispatch = {
.get_status = virtio_get_status,
.get_features = virtio_get_features,
.notify = virtio_notify,
};
static void platform_ipm_callback(const struct device *dev, void *context,
uint32_t id, volatile void *data)
{
k_sem_give(&data_sem);
}
static int endpoint_cb(struct rpmsg_endpoint *ept, void *data,
size_t len, uint32_t src, void *priv)
{
received_data = ((struct payload *) data);
/* We do some work here */
#if READ_BUFFER
memcpy((void *) buffer, (void *) received_data->data, received_data->size);
#endif
return RPMSG_SUCCESS;
}
static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
{
(void)ept;
rpmsg_destroy_ept(&ep);
}
static void receive_message(void)
{
k_sem_take(&data_sem, K_FOREVER);
virtqueue_notification(vq[1]);
}
static void receive_task(void *arg1, void *arg2, void *arg3)
{
ARG_UNUSED(arg1);
ARG_UNUSED(arg2);
ARG_UNUSED(arg3);
struct metal_init_params metal_params = METAL_INIT_DEFAULTS;
struct rpmsg_virtio_device rvdev;
struct metal_device *device;
struct metal_io_region *io;
struct rpmsg_device *rdev;
struct virtio_device vdev;
int status = 0;
printk("\r\nOpenAMP[remote] demo started\r\n");
status = metal_init(&metal_params);
if (status != 0) {
printk("metal_init: failed - error code %d\n", status);
return;
}
status = metal_register_generic_device(&shm_device);
if (status != 0) {
printk("Couldn't register shared memory device: %d\n", status);
return;
}
status = metal_device_open("generic", SHM_DEVICE_NAME, &device);
if (status != 0) {
printk("metal_device_open failed: %d\n", status);
return;
}
io = metal_device_io_region(device, 0);
if (io == NULL) {
printk("metal_device_io_region failed to get region\n");
return;
}
/* setup IPM */
ipm_tx_handle = device_get_binding(CONFIG_OPENAMP_IPC_DEV_TX_NAME);
if (ipm_tx_handle == NULL) {
printk("device_get_binding failed to find device\n");
return;
}
ipm_rx_handle = device_get_binding(CONFIG_OPENAMP_IPC_DEV_RX_NAME);
if (ipm_rx_handle == NULL) {
printk("device_get_binding failed to find device\n");
return;
}
ipm_register_callback(ipm_rx_handle, platform_ipm_callback, NULL);
status = ipm_set_enabled(ipm_rx_handle, 1);
if (status != 0) {
printk("ipm_set_enabled failed\n");
return;
}
/* setup vdev */
vq[0] = virtqueue_allocate(VRING_SIZE);
if (vq[0] == NULL) {
printk("virtqueue_allocate failed to alloc vq[0]\n");
return;
}
vq[1] = virtqueue_allocate(VRING_SIZE);
if (vq[1] == NULL) {
printk("virtqueue_allocate failed to alloc vq[1]\n");
return;
}
vdev.role = RPMSG_REMOTE;
vdev.vrings_num = VRING_COUNT;
vdev.func = &dispatch;
rvrings[0].io = io;
rvrings[0].info.vaddr = (void *)VRING_TX_ADDRESS;
rvrings[0].info.num_descs = VRING_SIZE;
rvrings[0].info.align = VRING_ALIGNMENT;
rvrings[0].vq = vq[0];
rvrings[1].io = io;
rvrings[1].info.vaddr = (void *)VRING_RX_ADDRESS;
rvrings[1].info.num_descs = VRING_SIZE;
rvrings[1].info.align = VRING_ALIGNMENT;
rvrings[1].vq = vq[1];
vdev.vrings_info = &rvrings[0];
/* setup rvdev */
status = rpmsg_init_vdev(&rvdev, &vdev, NULL, io, NULL);
if (status != 0) {
printk("rpmsg_init_vdev failed %d\n", status);
return;
}
rdev = rpmsg_virtio_get_rpmsg_device(&rvdev);
status = rpmsg_create_ept(&ep, rdev, "k", RPMSG_ADDR_ANY,
RPMSG_ADDR_ANY, endpoint_cb, rpmsg_service_unbind);
if (status != 0) {
printk("rpmsg_create_ept failed %d\n", status);
return;
}
#if READ_BUFFER
max_payload_size = rpmsg_virtio_get_buffer_size(rdev);
if (max_payload_size < 0) {
printk("No available buffer size\n");
return;
}
buffer = (uint8_t *) metal_allocate_memory(max_payload_size - sizeof(struct payload));
if (!buffer) {
printk("memory allocation failed\n");
return;
}
#endif
while (1) {
receive_message();
}
/* How did we get here? */
}
K_THREAD_DEFINE(thread_receive_id, APP_TASK_STACK_SIZE, receive_task, NULL, NULL, NULL,
K_PRIO_PREEMPT(1), 0, 0);

View file

@ -0,0 +1,11 @@
sample:
description: This app provides an example of how to test OpenAMP
performance with Zephyr.
name: OpenAMP performance example integration
tests:
sample.subsys.ipc.openamp_performance:
build_only: true
platform_allow: nrf5340dk_nrf5340_cpuapp
integration_platforms:
- nrf5340dk_nrf5340_cpuapp
tags: ipm

View file

@ -0,0 +1,316 @@
/*
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <drivers/ipm.h>
#include <sys/printk.h>
#include <device.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <init.h>
#include <openamp/open_amp.h>
#include <metal/device.h>
#include "common.h"
static struct payload *s_payload;
#define APP_TASK_STACK_SIZE (1024)
static const struct device *ipm_tx_handle;
static const struct device *ipm_rx_handle;
static int max_payload_size;
static K_SEM_DEFINE(data_sem, 0, 1);
static K_SEM_DEFINE(ept_sem, 0, 1);
static struct rpmsg_endpoint ep;
static metal_phys_addr_t shm_physmap[] = { SHM_START_ADDR };
static struct metal_device shm_device = {
.name = SHM_DEVICE_NAME,
.bus = NULL,
.num_regions = 1,
{
{
.virt = (void *) SHM_START_ADDR,
.physmap = shm_physmap,
.size = SHM_SIZE,
.page_shift = 0xffffffff,
.page_mask = 0xffffffff,
.mem_flags = 0,
.ops = { NULL },
},
},
.node = { NULL },
.irq_num = 0,
.irq_info = NULL
};
static struct virtio_vring_info rvrings[2] = {
[0] = {
.info.align = VRING_ALIGNMENT,
},
[1] = {
.info.align = VRING_ALIGNMENT,
},
};
static unsigned char virtio_get_status(struct virtio_device *vdev)
{
return VIRTIO_CONFIG_STATUS_DRIVER_OK;
}
static void virtio_set_status(struct virtio_device *vdev, unsigned char status)
{
sys_write8(status, VDEV_STATUS_ADDR);
}
static uint32_t virtio_get_features(struct virtio_device *vdev)
{
return BIT(VIRTIO_RPMSG_F_NS);
}
static void virtio_set_features(struct virtio_device *vdev,
uint32_t features)
{
}
static void virtio_notify(struct virtqueue *vq)
{
ipm_send(ipm_tx_handle, 0, 0, NULL, 0);
}
static struct virtio_dispatch dispatch = {
.get_status = virtio_get_status,
.set_status = virtio_set_status,
.get_features = virtio_get_features,
.set_features = virtio_set_features,
.notify = virtio_notify,
};
static void platform_ipm_callback(const struct device *dev, void *context,
uint32_t id, volatile void *data)
{
k_sem_give(&data_sem);
}
static int endpoint_cb(struct rpmsg_endpoint *ept, void *data,
size_t len, uint32_t src, void *priv)
{
return RPMSG_SUCCESS;
}
static void rpmsg_service_unbind(struct rpmsg_endpoint *ept)
{
(void)ept;
rpmsg_destroy_ept(&ep);
}
static void ns_bind_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest)
{
(void)rpmsg_create_ept(&ep, rdev, name,
RPMSG_ADDR_ANY, dest,
endpoint_cb,
rpmsg_service_unbind);
k_sem_give(&ept_sem);
}
static void send_pkt(struct rpmsg_virtio_device *rvdev)
{
struct rpmsg_device *rpdev;
int status;
rpdev = rpmsg_virtio_get_rpmsg_device(rvdev);
max_payload_size = rpmsg_virtio_get_buffer_size(rpdev);
if (max_payload_size < 0) {
printk("No available buffer size\n");
return;
}
s_payload = (struct payload *) metal_allocate_memory(max_payload_size);
if (!s_payload) {
printk("memory allocation failed\n");
return;
}
memset(s_payload->data, 0xA5, max_payload_size - sizeof(struct payload));
s_payload->size = max_payload_size;
s_payload->cnt = 0;
while (1) {
status = rpmsg_send(&ep, s_payload, max_payload_size);
if (status < 0) {
printk("%s failed with status %d\n", __func__, status);
return;
}
s_payload->cnt++;
}
}
static void send_task(void *arg1, void *arg2, void *arg3)
{
ARG_UNUSED(arg1);
ARG_UNUSED(arg2);
ARG_UNUSED(arg3);
struct metal_init_params metal_params = METAL_INIT_DEFAULTS;
struct rpmsg_virtio_shm_pool shpool;
struct rpmsg_virtio_device rvdev;
struct metal_device *device;
struct metal_io_region *io;
struct virtio_device vdev;
struct virtqueue *vq[2];
int status = 0;
printk("\r\nOpenAMP[master] demo started\r\n");
status = metal_init(&metal_params);
if (status != 0) {
printk("metal_init: failed - error code %d\n", status);
return;
}
status = metal_register_generic_device(&shm_device);
if (status != 0) {
printk("Couldn't register shared memory device: %d\n", status);
return;
}
status = metal_device_open("generic", SHM_DEVICE_NAME, &device);
if (status != 0) {
printk("metal_device_open failed: %d\n", status);
return;
}
io = metal_device_io_region(device, 0);
if (io == NULL) {
printk("metal_device_io_region failed to get region\n");
return;
}
/* setup IPM */
ipm_tx_handle = device_get_binding(CONFIG_OPENAMP_IPC_DEV_TX_NAME);
if (ipm_tx_handle == NULL) {
printk("device_get_binding failed to find device\n");
return;
}
ipm_rx_handle = device_get_binding(CONFIG_OPENAMP_IPC_DEV_RX_NAME);
if (ipm_rx_handle == NULL) {
printk("device_get_binding failed to find device\n");
return;
}
ipm_register_callback(ipm_rx_handle, platform_ipm_callback, NULL);
status = ipm_set_enabled(ipm_rx_handle, 1);
if (status != 0) {
printk("ipm_set_enabled failed\n");
return;
}
/* setup vdev */
vq[0] = virtqueue_allocate(VRING_SIZE);
if (vq[0] == NULL) {
printk("virtqueue_allocate failed to alloc vq[0]\n");
return;
}
vq[1] = virtqueue_allocate(VRING_SIZE);
if (vq[1] == NULL) {
printk("virtqueue_allocate failed to alloc vq[1]\n");
return;
}
vdev.role = RPMSG_MASTER;
vdev.vrings_num = VRING_COUNT;
vdev.func = &dispatch;
rvrings[0].io = io;
rvrings[0].info.vaddr = (void *)VRING_TX_ADDRESS;
rvrings[0].info.num_descs = VRING_SIZE;
rvrings[0].info.align = VRING_ALIGNMENT;
rvrings[0].vq = vq[0];
rvrings[1].io = io;
rvrings[1].info.vaddr = (void *)VRING_RX_ADDRESS;
rvrings[1].info.num_descs = VRING_SIZE;
rvrings[1].info.align = VRING_ALIGNMENT;
rvrings[1].vq = vq[1];
vdev.vrings_info = &rvrings[0];
/* setup rvdev */
rpmsg_virtio_init_shm_pool(&shpool, (void *)SHM_START_ADDR, SHM_SIZE);
status = rpmsg_init_vdev(&rvdev, &vdev, ns_bind_cb, io, &shpool);
if (status != 0) {
printk("rpmsg_init_vdev failed %d\n", status);
return;
}
/* Since we are using name service, we need to wait for a response
* from NS setup and than we need to process it
*/
k_sem_take(&data_sem, K_FOREVER);
virtqueue_notification(vq[0]);
/* Wait til nameservice ep is setup */
k_sem_take(&ept_sem, K_FOREVER);
/* Start the flood */
send_pkt(&rvdev);
/* We should get here only on error */
rpmsg_deinit_vdev(&rvdev);
metal_finish();
printk("OpenAMP demo ended.\n");
}
K_THREAD_DEFINE(thread_send_id, APP_TASK_STACK_SIZE, send_task, NULL, NULL, NULL,
K_PRIO_PREEMPT(2), 0, 0);
static void check_task(void *arg1, void *arg2, void *arg3)
{
ARG_UNUSED(arg1);
ARG_UNUSED(arg2);
ARG_UNUSED(arg3);
unsigned long last_cnt = s_payload->cnt;
unsigned long delta;
while (1) {
k_sleep(K_SECONDS(1));
delta = s_payload->cnt - last_cnt;
printk("Δpkt: %ld (%ld B/pkt) | throughput: %ld bit/s\n",
delta, s_payload->size, delta * max_payload_size * 8);
last_cnt = s_payload->cnt;
}
}
K_THREAD_DEFINE(thread_check_id, APP_TASK_STACK_SIZE, check_task, NULL, NULL, NULL,
K_PRIO_PREEMPT(1), 0, 1000);
/* Make sure we clear out the status flag very early (before we bringup the
* secondary core) so the secondary core see's the proper status
*/
static int init_status_flag(const struct device *arg)
{
virtio_set_status(NULL, 0);
return 0;
}
SYS_INIT(init_status_flag, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);