Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

subsys: Add MCTP as a subsystem, built on libmctp with bindings #75743

Merged
merged 4 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions MAINTAINERS.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5034,6 +5034,18 @@ West:
labels:
- "area: Rust"

"West project: libmctp":
status: maintained
maintainers:
- teburd
collaborators:
- nashif
teburd marked this conversation as resolved.
Show resolved Hide resolved
- inteljiangwe1
files:
- samples/modules/mctp/
labels:
- "area: MCTP"

"West project: libmetal":
status: odd fixes
collaborators:
Expand Down
86 changes: 86 additions & 0 deletions include/zephyr/mctp/mctp_uart.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2024 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*
*/

#ifndef ZEPHYR_MCTP_UART_H_
#define ZEPHYR_MCTP_UART_H_

#include <stdint.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <libmctp.h>

/**
* @brief An MCTP binding for Zephyr's asynchronous UART interface
*/
struct mctp_binding_uart {
/** @cond INTERNAL_HIDDEN */
struct mctp_binding binding;
const struct device *dev;

/* receive buffers and state */
uint8_t rx_buf[2][256];
bool rx_buf_used[2];
struct mctp_pktbuf *rx_pkt;
uint8_t rx_exp_len;
uint16_t rx_fcs;
uint16_t rx_fcs_calc;
enum {
STATE_WAIT_SYNC_START,
STATE_WAIT_REVISION,
STATE_WAIT_LEN,
STATE_DATA,
STATE_DATA_ESCAPED,
STATE_WAIT_FCS1,
STATE_WAIT_FCS2,
STATE_WAIT_SYNC_END,
} rx_state;
int rx_res;

/* staging buffer for tx */
uint8_t tx_buf[256];
int tx_res;

/** @endcond INTERNAL_HIDDEN */
};

/**
* @brief Start the receive of a single mctp message
*
* Will read a single mctp message from the uart.
*
* @param uart MCTP UART binding
*/
void mctp_uart_start_rx(struct mctp_binding_uart *uart);

/** @cond INTERNAL_HIDDEN */
int mctp_uart_start(struct mctp_binding *binding);
int mctp_uart_tx(struct mctp_binding *binding, struct mctp_pktbuf *pkt);
/** @endcond INTERNAL_HIDDEN */

/**
* @brief Statically define a MCTP bus binding for a UART
*
* @param _name Symbolic name of the bus binding variable
* @param _dev UART device
*/
#define MCTP_UART_DT_DEFINE(_name, _dev) \
struct mctp_binding_uart _name = { \
.binding = \
{ \
.name = STRINGIFY(_name), .version = 1, \
.pkt_size = MCTP_PACKET_SIZE(MCTP_BTU), \
.pkt_header = 0, .pkt_trailer = 0, \
.start = mctp_uart_start, .tx = mctp_uart_tx, \
}, \
.dev = _dev, \
.rx_state = STATE_WAIT_SYNC_START, \
.rx_pkt = NULL, \
.rx_res = 0, \
.tx_res = 0, \
};

#endif /* ZEPHYR_MCTP_UART_H_ */
5 changes: 5 additions & 0 deletions samples/modules/mctp/mctp.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.. zephyr:code-sample-category:: mctp
:name: MCTP
:show-listing:

These samples demonstrate how to build communicating firmwares using MCTP in Zephyr.
7 changes: 7 additions & 0 deletions samples/modules/mctp/mctp_endpoint/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})

project(mctp_endpoint)

target_sources(app PRIVATE src/main.c)
41 changes: 41 additions & 0 deletions samples/modules/mctp/mctp_endpoint/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.. zephyr:code-sample:: mctp_endpoint_sample
:name: MCTP Endpoint Sample

Create an MCTP endpoint over UART.

Overview
********
Sets up an MCTP node that listens on a UART for messages targeting a particular
MCTP endpoint id with the message "hello". Responds to this "hello" message with
"world".

Requirements
************
A board and SoC that provide access to a UART and a driver that implements the
UART async API.

Wiring
******
The listening UART pins should be wired to a board which will run the MCTP host
sample such that this board's UART tx pin connects to the host board's rx pin,
and this board's UART rx pin connects to the host board's tx pin. The boards'
grounds should also be wired together.

Optionally a logic analyzer can be wired up and listening to the UART to inspect
the data flowing.

Building and Running
********************


.. zephyr-app-commands::
:zephyr-app: samples/modules/mctp/mctp_endpoint
:host-os: unix
:board: nrf52840_nrf52840dk
:goals: run
:compact:

References
**********

`MCTP Base Specification 2019 <https://www.dmtf.org/sites/default/files/standards/documents/DSP0236_1.3.1.pdf>`_
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
&arduino_serial{
status = "okay";
};
8 changes: 8 additions & 0 deletions samples/modules/mctp/mctp_endpoint/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CONFIG_SERIAL=y
CONFIG_UART_ASYNC_API=y
CONFIG_MCTP=y
CONFIG_MCTP_UART=y
CONFIG_LOG=y
CONFIG_LOG_BUFFER_SIZE=4096
CONFIG_MCTP_LOG_LEVEL_DBG=y
CONFIG_ISR_STACK_SIZE=4096
68 changes: 68 additions & 0 deletions samples/modules/mctp/mctp_endpoint/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2024 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <zephyr/kernel.h>
#include <zephyr/types.h>
#include <zephyr/mctp/mctp_uart.h>
#include <libmctp.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(mctp_endpoint);

#include <zephyr/drivers/uart.h>

static struct mctp *mctp_ctx;

#define LOCAL_HELLO_EID 10

#define REMOTE_HELLO_EID 20

K_SEM_DEFINE(mctp_rx, 0, 1);

static void rx_message(uint8_t eid, bool tag_owner, uint8_t msg_tag, void *data, void *msg,
size_t len)
{
switch (eid) {
case REMOTE_HELLO_EID:
LOG_INF("got mctp message %s for eid %d, replying to 5 with \"world\"", (char *)msg,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "replying to 5 with" mean here?

Copy link
Collaborator Author

@teburd teburd Nov 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The endpoint it’s replying to, though I get that’s not necessarily clear

eid);
mctp_message_tx(mctp_ctx, LOCAL_HELLO_EID, false, 0, "world", sizeof("world"));
break;
default:
LOG_INF("Unknown endpoint %d", eid);
break;
}

k_sem_give(&mctp_rx);
}

MCTP_UART_DT_DEFINE(mctp_endpoint, DEVICE_DT_GET(DT_NODELABEL(arduino_serial)));

#define RX_BUF_SZ 128

int main(void)
{
LOG_INF("MCTP Endpoint EID:%d on %s\n", LOCAL_HELLO_EID, CONFIG_BOARD_TARGET);

mctp_set_alloc_ops(malloc, free, realloc);
mctp_ctx = mctp_init();
__ASSERT_NO_MSG(mctp_ctx != NULL);
mctp_register_bus(mctp_ctx, &mctp_endpoint.binding, LOCAL_HELLO_EID);
mctp_set_rx_all(mctp_ctx, rx_message, NULL);

/* MCTP poll loop */
while (true) {
mctp_uart_start_rx(&mctp_endpoint);
k_sem_take(&mctp_rx, K_FOREVER);
}

LOG_INF("exiting");
return 0;
}
6 changes: 6 additions & 0 deletions samples/modules/mctp/mctp_host/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(mctp_host)

target_sources(app PRIVATE src/main.c)
40 changes: 40 additions & 0 deletions samples/modules/mctp/mctp_host/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
.. zephyr:code-sample:: mctp_host_sample
:name: MCTP Host Sample

Create an MCTP host over UART.

Overview
********
Sets up an MCTP node that sends a request on a UART targeting a particular MCTP
endpoint id with the message "hello". Expects and waits for a response to this
"hello" message containing "world".

Requirements
************
A board and SoC that provide access to a UART and a driver that implements the
UART async API.

Wiring
******
The UART pins should be wired to a board which will run the MCTP endpoint
sample such that this board's UART tx pin connects to the endpoint board's rx
pin, and this board's UART rx pin connects to the endpoint board's tx pin. The
boards' grounds should also be wired together.

Optionally a logic analyzer can be wired up and listening to the UART to inspect
the data flowing.

Building and Running
********************

.. zephyr-app-commands::
:zephyr-app: samples/modules/mctp/mctp_host
:host-os: unix
:board: nrf52840_nrf52840dk
:goals: run
:compact:

References
**********

`MCTP Base Specification 2019 <https://www.dmtf.org/sites/default/files/standards/documents/DSP0236_1.3.1.pdf>`_
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
&arduino_serial{
status = "okay";
};
8 changes: 8 additions & 0 deletions samples/modules/mctp/mctp_host/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# nothing here
CONFIG_SERIAL=y
CONFIG_UART_ASYNC_API=y
CONFIG_MCTP=y
CONFIG_MCTP_UART=y
CONFIG_MCTP_LOG_LEVEL_DBG=y
CONFIG_LOG=y
CONFIG_LOG_BUFFER_SIZE=4096
63 changes: 63 additions & 0 deletions samples/modules/mctp/mctp_host/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2024 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <libmctp.h>
#include <zephyr/mctp/mctp_uart.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(mctp_host);

#define LOCAL_HELLO_EID 20

#define REMOTE_HELLO_EID 10

K_SEM_DEFINE(mctp_rx, 0, 1);

static void rx_message(uint8_t eid, bool tag_owner, uint8_t msg_tag, void *data, void *msg,
size_t len)
{
LOG_INF("received message %s for endpoint %d, msg_tag %d, len %zu", (char *)msg, eid,
msg_tag, len);
k_sem_give(&mctp_rx);
}

MCTP_UART_DT_DEFINE(mctp_host, DEVICE_DT_GET(DT_NODELABEL(arduino_serial)));

int main(void)
{
int rc;
struct mctp *mctp_ctx;

LOG_INF("MCTP Host EID:%d on %s\n", LOCAL_HELLO_EID, CONFIG_BOARD_TARGET);

mctp_set_alloc_ops(malloc, free, realloc);
mctp_ctx = mctp_init();
__ASSERT_NO_MSG(mctp_ctx != NULL);
mctp_register_bus(mctp_ctx, &mctp_host.binding, LOCAL_HELLO_EID);
mctp_set_rx_all(mctp_ctx, rx_message, NULL);
mctp_uart_start_rx(&mctp_host);

/* MCTP poll loop, send "hello" and get "world" back */
while (true) {
rc = mctp_message_tx(mctp_ctx, REMOTE_HELLO_EID, false, 0, "hello",
sizeof("hello"));
if (rc != 0) {
LOG_WRN("Failed to send message, errno %d\n", rc);
k_msleep(1000);
} else {
k_sem_take(&mctp_rx, K_MSEC(10));
}
rc = 0;
}

return 0;
}
1 change: 1 addition & 0 deletions subsys/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ add_subdirectory_ifdef(CONFIG_IMG_MANAGER dfu)
add_subdirectory_ifdef(CONFIG_INPUT input)
add_subdirectory_ifdef(CONFIG_JWT jwt)
add_subdirectory_ifdef(CONFIG_LLEXT llext)
add_subdirectory_ifdef(CONFIG_MCTP mctp)
add_subdirectory_ifdef(CONFIG_MODEM_MODULES modem)
add_subdirectory_ifdef(CONFIG_NETWORKING net)
add_subdirectory_ifdef(CONFIG_PROFILING profiling)
Expand Down
1 change: 1 addition & 0 deletions subsys/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ source "subsys/jwt/Kconfig"
source "subsys/llext/Kconfig"
source "subsys/logging/Kconfig"
source "subsys/lorawan/Kconfig"
source "subsys/mctp/Kconfig"
source "subsys/mem_mgmt/Kconfig"
source "subsys/mgmt/Kconfig"
source "subsys/modbus/Kconfig"
Expand Down
2 changes: 2 additions & 0 deletions subsys/mctp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_MCTP_UART mctp_uart.c)
Loading
Loading