Skip to content
Open
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
1 change: 1 addition & 0 deletions doc/connectivity/usb/device_next/api/index.rst
Copy link
Contributor

Choose a reason for hiding this comment

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

In order to support the USB binding for libMCTP, we must first add a device
class for MCTP. MCTP is one of the base classes in the USB specification.

Well no, it is specified by the "DMTF association", https://www.dmtf.org/sites/default/files/standards/documents/DSP0283_1.0.0.pdf

Copy link
Author

Choose a reason for hiding this comment

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

It's base class 0x14 in the USB spec, so I'm not sure what you mean here.

https://www.usb.org/defined-class-codes

Choose a reason for hiding this comment

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

Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ USB device support APIs
usbd_msc_device.rst
usbd_midi2.rst
usbd_dfu.rst
usbd_mctp.rst
14 changes: 14 additions & 0 deletions doc/connectivity/usb/device_next/api/usbd_mctp.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.. _usbd_mctp:

MCTP (Management Component Transport Protocol) USB device API
#############################################################

MCTP USB device specific API defined in :zephyr_file:`include/zephyr/usb/class/usbd_mctp.h`.

The implementation of this device class is specified by DMTF and the spec is found `here
<https://www.dmtf.org/sites/default/files/standards/documents/DSP0283_1.0.1.pdf>`__.

API Reference
*************

.. doxygengroup:: usbd_mctp
4 changes: 4 additions & 0 deletions doc/connectivity/usb/device_next/usb_device.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ Samples

* :zephyr:code-sample:`usb-hid-mouse`

* :zephyr:code-sample:`mctp-usb-endpoint`
Copy link
Contributor

Choose a reason for hiding this comment

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

* :zephyr:code-sample:mctp-usb-binding`` Anyway, you cannot add it in this commit, this sample does not exist yet.

Copy link
Author

Choose a reason for hiding this comment

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

Do you suggest that I just update this file in a commit with the sample application, or do one 'super commit' with all of these feature/MCTP changes? I did it this way for human readability, but didn't fully understand the need for every commit to build.

Copy link
Contributor

Choose a reason for hiding this comment

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

"Commits in a pull request should represent clear, logical units of change that are easy to review and maintain bisectability." https://docs.zephyrproject.org/latest/contribute/contributor_expectations.html#pr-requirements


* :zephyr:code-sample:`zperf` To build the sample for the device support,
set the configuration overlay file
``-DDEXTRA_CONF_FILE=overlay-usbd_next_ecm.conf`` and devicetree overlay file
Expand Down Expand Up @@ -217,6 +219,8 @@ instance (``n``) and is used as an argument to the :c:func:`usbd_register_class`
+-----------------------------------+-------------------------+-------------------------+
| USB Video Class (UVC) | Video device | :samp:`uvc_{n}` |
+-----------------------------------+-------------------------+-------------------------+
| MCTP over USB Endpoint class | :ref:`usbd_mctp` | :samp:`mctp_{n}` |
+-----------------------------------+-------------------------+-------------------------+

CDC ACM UART
============
Expand Down
13 changes: 13 additions & 0 deletions dts/bindings/pmci/mctp/usb.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2025 NXP
# SPDX-License-Identifier: Apache-2.0

description: |
A configuration for MCTP binding to a USB target.
compatible: "zephyr,mctp-usb"

properties:
endpoint-id:
type: int
description: |
MCTP Endpoint ID
79 changes: 79 additions & 0 deletions include/zephyr/pmci/mctp/mctp_usb.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2024 Intel Corporation
* Copyright 2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*
*/

#ifndef ZEPHYR_MCTP_USB_H_
#define ZEPHYR_MCTP_USB_H_

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

#define MCTP_USB_HEADER_SIZE 4
#define MCTP_USB_MAX_PACKET_LENGTH 255

/**
* @brief An MCTP binding for Zephyr's USB device stack
*/
struct mctp_binding_usb {
/** @cond INTERNAL_HIDDEN */
struct mctp_binding binding;
const struct usbd_mctp_inst *usb_inst;
uint8_t endpoint_id;
uint8_t tx_buf[MCTP_USB_HEADER_SIZE + MCTP_USB_MAX_PACKET_LENGTH];
struct k_sem tx_lock;
struct mctp_pktbuf *rx_pkt;
uint8_t rx_data_idx;
enum {
STATE_WAIT_HDR_DMTF0,
STATE_WAIT_HDR_DMTF1,
STATE_WAIT_HDR_RSVD0,
STATE_WAIT_HDR_LEN,
STATE_DATA
} rx_state;
/** @endcond INTERNAL_HIDDEN */
};

/** @cond INTERNAL_HIDDEN */
void mctp_usb_data_recv_cb(const void *const buf, const uint16_t size, const void *const priv);
void mctp_usb_error_cb(const int err, const uint8_t ep, const void *const priv);
int mctp_usb_start(struct mctp_binding *binding);
int mctp_usb_tx(struct mctp_binding *binding, struct mctp_pktbuf *pkt);
/** @endcond INTERNAL_HIDDEN */

/**
* @brief Define a MCTP bus binding for USB
*
* @param _name Symbolic name of the bus binding variable
* @param _dev DeviceTree Node containing the configuration of this MCTP binding
*/
#define MCTP_USB_DEFINE(_name, _dev, _subclass, _protocol) \
extern const struct usbd_mctp_inst usbd_mctp_inst_##_name; \
\
struct mctp_binding_usb _name = { \
.binding = { \
.name = STRINGIFY(_name), \
.version = 1, \
.pkt_size = MCTP_PACKET_SIZE(MCTP_USB_MAX_PACKET_LENGTH), \
.pkt_header = 0, \
.pkt_trailer = 0, \
.start = mctp_usb_start, \
.tx = mctp_usb_tx \
}, \
.usb_inst = &usbd_mctp_inst_##_name, \
.endpoint_id = DT_PROP(_dev, endpoint_id), \
.rx_pkt = NULL, \
.rx_data_idx = 0, \
.rx_state = STATE_WAIT_HDR_DMTF0 \
}; \
\
USBD_DEFINE_MCTP_INSTANCE(_name, _subclass, _protocol, &_name, mctp_usb_data_recv_cb, \
mctp_usb_error_cb);

#endif /* ZEPHYR_MCTP_USB_H_ */
93 changes: 93 additions & 0 deletions include/zephyr/usb/class/usbd_mctp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
* Copyright 2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/

/**
* @file
* @brief MCTP over USB Protocol Endpoint Device Class public header
*
* This API is currently considered experimental.
*/

#include <zephyr/sys/iterable_sections.h>

#ifndef ZEPHYR_INCLUDE_USB_CLASS_USBD_MCTP_H_
#define ZEPHYR_INCLUDE_USB_CLASS_USBD_MCTP_H_

/**
* @brief USB MCTP device API
* @defgroup usbd_mctp USB MCTP device API
* @ingroup usb
* @since 4.2
* @version 0.1.0
* @{
*/

/* MCTP class subclass options */
#define USBD_MCTP_SUBCLASS_MANAGEMENT_CONTROLLER 0
#define USBD_MCTP_SUBCLASS_MANAGED_DEVICE_ENDPOINT 0
#define USBD_MCTP_SUBCLASS_HOST_INTERFACE_ENDPOINT 1

/* MCTP class protocol options */
#define USBD_MCTP_PROTOCOL_1_X 1
#define USBD_MCTP_PROTOCOL_2_X 2

struct usbd_mctp_inst {
const char *name;
uint8_t sublcass;
uint8_t mctp_protocol;
void *priv;
void (*data_recv_cb)(const void *const buf,
const uint16_t size,
const void *const priv);
void (*error_cb)(const int err,
const uint8_t ep,
const void *const priv);
};

/**
* @brief Define USB MCTP instance
*
* Use this macro to create set the parameters of an MCTP instance.
*
* @param id Identifier by which the linker sorts registered instances
* @param subclass MCTP subclass used in the USB interfce descriptor
* @param protocol MCTP protocol used in the USB interface descriptor
* @param private Opaque private/user data
* @param recv_cb Data received callback
* @param err_cb Error callback
*/
#define USBD_DEFINE_MCTP_INSTANCE(id, subclass, protocol, private, recv_cb, err_cb) \
const STRUCT_SECTION_ITERABLE(usbd_mctp_inst, usbd_mctp_inst_##id) = { \
.name = STRINGIFY(id), \
.sublcass = subclass, \
.mctp_protocol = protocol, \
.priv = private, \
.data_recv_cb = recv_cb, \
.error_cb = err_cb \
}

/**
* @brief Send data to the MCTP bus owner.
*
* @note Buffer ownership is transferred to the stack in case of success, in
* case of an error the caller retains the ownership of the buffer.
*
* @param inst USBD MCTP instance to send data through
* @param buf Buffer containing outgoing data
* @param size Number of bytes to send
*
* @return 0 on success, negative value on error
*/
int usbd_mctp_send(const struct usbd_mctp_inst *const inst,
const void *const buf,
const uint16_t size);

/**
* @}
*/

#endif /* ZEPHYR_INCLUDE_USB_CLASS_USBD_MCTP_H_ */
1 change: 1 addition & 0 deletions include/zephyr/usb/usb_ch9.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ struct usb_association_descriptor {
#define USB_BCC_MASS_STORAGE 0x08
#define USB_BCC_CDC_DATA 0x0A
#define USB_BCC_VIDEO 0x0E
#define USB_BCC_MCTP 0x14
#define USB_BCC_WIRELESS_CONTROLLER 0xE0
#define USB_BCC_MISCELLANEOUS 0xEF
#define USB_BCC_APPLICATION 0xFE
Expand Down
9 changes: 9 additions & 0 deletions samples/modules/pmci/mctp/usb_endpoint/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(mctp_usb_endpoint)

include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake)

target_sources(app PRIVATE src/main.c)
9 changes: 9 additions & 0 deletions samples/modules/pmci/mctp/usb_endpoint/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2023 Nordic Semiconductor ASA
Copy link
Contributor

Choose a reason for hiding this comment

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

I am confused, is PMCI/MCTP not part of the Zephyr but an external module? If so then I do not think you can add any dependency on it to the USB subsystem.

Copy link
Author

Choose a reason for hiding this comment

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

The way I looked at it is that MCTP is called out as a base class on usb.org, so the device class implementation can exists in Zephyr, even if the higher-level MCTP protocol management comes from an external module. Right now it comes from libmctp (https://github.com/openbmc/libmctp).

I understand this concern. Is there something you think would create such a dependency? Again, I'm new to Zephyr, so maybe I don't fully understand something.

Copy link
Member

Choose a reason for hiding this comment

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

I am confused, is PMCI/MCTP not part of the Zephyr but an external module?

mctp is not an external module, it is part of the main manifest and there are dependencies on it already.

Copy link
Contributor

Choose a reason for hiding this comment

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

I am confused, is PMCI/MCTP not part of the Zephyr but an external module?

mctp is not an external module, it is part of the main manifest and there are dependencies on it already.

Anyway, the implementation cannot be part of subsys/usb, and has to go to the modules.

Copy link
Author

Choose a reason for hiding this comment

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

The fact that MCTP is listed on usb.org doesn't matter then?

Copy link
Author

Choose a reason for hiding this comment

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

@teburd ok, I'll explore this.

Regarding dependency in general, I want to clarify something since it may not be clear from this initial PR. The re-worked PR I have locally has cleaner lines of separation...

Besides the reference to the MCTP sample in usb_device.rst, the USB device class has no dependency on libmctp. Yes, libmctp uses it, but any other MCTP implementation can as well. You can remove libmctp and the device class stands on its own.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you post the re-worked PR? Would that come as separate PR or a force-push here?

Copy link
Author

Choose a reason for hiding this comment

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

Sure, I'll try to find some time to get it done today. The plan was for force push.

Copy link
Member

@nashif nashif Oct 3, 2025

Choose a reason for hiding this comment

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

@jfischer-no

What in Zephyr depends on libmctp?

 git grep  libmctp.h subsys/ include/
include/zephyr/pmci/mctp/mctp_i2c_gpio_controller.h:#include <libmctp.h>
include/zephyr/pmci/mctp/mctp_i2c_gpio_target.h:#include <libmctp.h>
include/zephyr/pmci/mctp/mctp_uart.h:#include <libmctp.h>
subsys/pmci/mctp/mctp_memory.c:#include <libmctp.h>

Copy link
Member

Choose a reason for hiding this comment

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

Even MCTP samples are only located in samples/modules.

is this your issue? really? #96995

# SPDX-License-Identifier: Apache-2.0

# Source common USB sample options used to initialize new experimental USB
# device stack. The scope of these options is limited to USB samples in project
# tree, you cannot use them in your own application.
source "samples/subsys/usb/common/Kconfig.sample_usbd"

source "Kconfig.zephyr"
56 changes: 56 additions & 0 deletions samples/modules/pmci/mctp/usb_endpoint/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
.. zephyr:code-sample:: mctp-usb-endpoint
:name: MCTP USB Endpoint Node Sample
:relevant-api: usbd_api

Create an MCTP endpoint node using the USB device interface.

Overview
********
Sets up an MCTP endpoint node that listens for messages from the MCTP bus owner with EID 20.
Responds with "Hello, bus owner" message.

Requirements
************
A board and SoC that provide support for USB device capability (either FS or HS). Testing requires
a USB host that has the ability to enumerate the MCTP interface and interact with the board using
the MCTP protocol. An easy way to do this is a Python script.

An example script to test this interface is provided with this sample application. To run the
script, you must first install pyusb.

.. code-block:: console

pip install requirements.txt
python usb_host_tester.py

If the test is successful, you will see the following output from the script:

.. code-block:: console

Sending message with size smaller than USB FS MPS (<64b)
Received: b'\x1a\xb4\x00\x15\x01\x14\n\xc0Hello, bus owner\x00'
Sending message spanning two USB FS packets (>64b)
Received: b'\x1a\xb4\x00\x15\x01\x14\n\xc0Hello, bus owner\x00'
Sending message with two MCTP messages in a single USB FS packet
Received: b'\x1a\xb4\x00\x15\x01\x14\n\xc0Hello, bus owner\x00'
Received: b'\x1a\xb4\x00\x15\x01\x14\n\xc0Hello, bus owner\x00'

Wiring
******
Connect a USB cable between the host (likely a PC) and the board. The type of cable (mini, micro,
type C) depends on the host and board connectors.

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

.. zephyr-app-commands::
:zephyr-app: samples/modules/pmci/mctp/usb_endpoint
:host-os: unix
:board: frdm_mcxn947_mcxn947_cpu0
:goals: run
:compact:

References
**********

`MCTP Base Specification 2019 <https://www.dmtf.org/sites/default/files/standards/documents/DSP0236_1.3.1.pdf>`_
12 changes: 12 additions & 0 deletions samples/modules/pmci/mctp/usb_endpoint/app.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright 2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/

/ {
mctp_usb0: mctp_usb0 {
compatible = "zephyr,mctp-usb";
endpoint-id = <10>;
};
};
11 changes: 11 additions & 0 deletions samples/modules/pmci/mctp/usb_endpoint/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CONFIG_USB_DEVICE_STACK_NEXT=y
CONFIG_USBD_MCTP_CLASS=y

CONFIG_MCTP=y
CONFIG_MCTP_USB=y

CONFIG_LOG=y
CONFIG_MCTP_LOG_LEVEL_ERR=y
CONFIG_USBD_MCTP_LOG_LEVEL_DBG=y
CONFIG_USBD_LOG_LEVEL_ERR=y
CONFIG_UDC_DRIVER_LOG_LEVEL_ERR=y
2 changes: 2 additions & 0 deletions samples/modules/pmci/mctp/usb_endpoint/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Needed to run USB host test script.

Check warning on line 1 in samples/modules/pmci/mctp/usb_endpoint/requirements.txt

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

Copyright missing

samples/modules/pmci/mctp/usb_endpoint/requirements.txt:1 File has no SPDX-FileCopyrightText header, consider adding one.

Check warning on line 1 in samples/modules/pmci/mctp/usb_endpoint/requirements.txt

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

License missing

samples/modules/pmci/mctp/usb_endpoint/requirements.txt:1 File has no SPDX-License-Identifier header, consider adding one.
pyusb
Loading
Loading