Bus drivers

Where MCTP transport is the medium-independent packet layer, these drivers are the media. Each subsystem under src/nv/ owns one physical interface, and most follow the same shape: one FreeRTOS task per bus/port, an IPC Queue of request items, an ISR path that enqueues work, and a switch on the request type in the task’s main loop. The ones that carry MCTP call nv::mctp::Driver::mctp_send() on ingress and are the targets of nv::mctp::Driver::forward() on egress (see MCTP transport).

This is a catalog page; citations are directory-level except where a specific class or entry point is worth pinning. I2C is the largest driver and gets the most detail.

I2C / SMBus — src/nv/i2c/

The largest bus subsystem (49 files). nv::i2c::Task (src/nv/i2c/task.h:37) drives a hardware I2C controller (sys::i2c::Driver), one task instance per physical port (I2c0I2c8), and can act as both bus controller (master) and target (slave). It is the primary MCTP-over-SMBus binding: MCTP packets travel as SMBus block writes with a trailing PEC byte, and a per-task routing table bridges them between upstream and downstream ports. The directory also carries a library of on-bus device drivers (temperature sensors, hot-swap/power controllers, a Lattice CPLD programmer, EEPROM cache).

Role split: MCTP transport binding plus raw I2C request/response service for other tasks plus sensor/EEPROM polling. Completion is interrupt-driven, and it supports DMA-error reporting, bus recovery, and fault injection.

Key files:

  • src/nv/i2c/task.cpp / task.h — the bus task: MCTP tx/rx, routing, raw I2C dispatch, sensor/EEPROM polling, recovery.
  • src/nv/i2c/common.h — shared payload types (I2cRequest, I2cResponse, buffers).
  • src/nv/i2c/lattice_driver.cpp / .h — Lattice CPLD in-system programming over I2C.
  • src/nv/i2c/sensor.cpp / .hTempSensor base plus concrete drivers (nct75, tmp1075, tmp432/461/468, emc1812).
  • src/nv/i2c/powersensor/ — hot-swap controller (HSC/HSCC) manager.
  • src/nv/i2c/eeprom_cache.cpp, recovery.cpp, error_injection.cpp, smb_direct.cpp — EEPROM bridge cache, bus recovery, fault injection, and SMBus direct-command helpers.

Entry points:

  • Task::make()src/nv/i2c/task.cpp:81 (per-port factory).
  • Task::start()src/nv/i2c/task.cpp:408; the request dispatch is the switch (request.type) at src/nv/i2c/task.cpp:451 (MctpRx, MctpTx, MctpUpdateRoutingTable, raw I2C, sensor, recovery).
  • Task::tx(const nv::mctp::Packet&)src/nv/i2c/task.cpp:171, the MCTP send path (also called by the USB router).
  • Task::forward(nv::mctp::Packet&, uint8_t)src/nv/i2c/task.cpp:1231, the routing-table forward to USB / upstream I2C / downstream ports.
  • struct I2cRequestsrc/nv/i2c/common.h:35.
  • Device drivers: class LatticeCpld (src/nv/i2c/lattice_driver.h:181), class TempSensor (src/nv/i2c/sensor.h:74), class DeviceManager (src/nv/i2c/powersensor/device_manager.h:91).

The MCTP Client values UsI2c and DsI2c0..7 all resolve to this driver; nv::mctp::Driver::forward() reaches it via nv::i2c::Task::tx.

I3C — src/nv/i3c/

nv::i3c::Task (src/nv/i3c/task.h:40) drives an I3C controller (nv::i3c::Driver, src/nv/i3c/driver.h:31) as I3C master with an I2C-legacy fallback. It performs Dynamic Address Assignment and CCC commands and, crucially, receives In-Band Interrupts (IBIs) that serve two purposes: an IBI is the “MCTP packet available” signal for the GPU-facing MCTP endpoint, and a separate IBI subtype drives the GPU SMBus Post-Box Interface (SMBPBI) telemetry path.

Key files: task.cpp/task.h (IBI handling, MCTP routing, GPU reset, sensor polling); driver.h (DAA/CCC, IBI, GPU/OCP helpers); smbpbi.cpp/smbpbi.h (GPU SMBPBI protocol); gpu.cpp/gpu.h (GPU I2C address derivation); topology_info.cpp (FRU/NVLink topology).

Entry points:

  • Task::start() main loop — src/nv/i3c/task.cpp:345, dispatching on switch (request.type) at src/nv/i3c/task.cpp:374.
  • Task::on_ibi(...) ISR handler — src/nv/i3c/task.cpp:396, which splits into Task::handle_mctp_ibi(...) (src/nv/i3c/task.cpp:449) for MCTP and the GPU SMBPBI path.
  • nv::i3c::smbpbi::start_smbpbi(...)src/nv/i3c/smbpbi.cpp:41.

MCTP Client values DsI3c0/DsI3c1 resolve here; forwarded packets arrive via nv::i3c::Task::tx. The driver also bridges onto the I2C queues for legacy-addressed devices.

SPI — src/nv/spi/

nv::spi::Task (src/nv/spi/task.h:34) has two roles. As an MCTP transport it is SPI master to a “Glacier” slave EC, running a custom SPB (SPI Protocol Bus) mailbox protocol to carry MCTP packets. Separately, a flashrom passthrough path drives an external SPI-NOR flash over eDMA, fed from USB via LSTP framing (not MCTP).

Key files: task.cpp/task.h (MCTP-over-SPI task, up to ports Spi0..2); spb.cpp/spb.h (the SPB mailbox/posted-read/write engine); common.h (SPB constants and the MctpBinding SPI header); flashrom.cpp + flashrom_task.cpp (external-flash passthrough); ext_flash.cpp (JEDEC SPI-NOR abstraction).

Entry points:

  • Task::tx(const mctp::Packet&)src/nv/spi/task.cpp:166 (MCTP send, called by the USB MCTP router).
  • class Spbsrc/nv/spi/spb.h:99; spi_mctp_send/spi_mctp_recv wrap/unwrap MCTP packets in the SPI MctpBinding header.
  • class Flashromsrc/nv/spi/flashrom.h:65 (the non-MCTP flash tunnel over USB-LSTP).

MCTP Client values Spi0..2 resolve here.

UART — src/nv/uart/

A deliberately thin, transmit-only wrapper over the platform sys::uart::Driver, used as the serial console / logging output rather than a message transport. The whole subsystem is a single header, class Driver (src/nv/uart/driver.h:46) exposing Status tx(...) (src/nv/uart/driver.h:50); the method bodies are per-SoC. Consumers are the logger subsystem (fault logs, string logging). It carries no MCTP.

USB — src/nv/usb/

nv::usb::Task (src/nv/usb/task.h:67) is the USB device (target) driver and the primary upstream MCTP endpoint as well as the MCTP bridge to downstream buses. It multiplexes three functions over USB endpoints: MCTP-over-USB (DMTF binding, id 0xB41A), a CP2112-compatible HID-to-SMBus bridge, and LSTP (used to tunnel the SPI-flashrom traffic).

Key files: task.cpp/task.h (task loop, MCTP/HID/LSTP paths, vbus handling); mctp_router.cpp/.h (downstream routing shared with the proxy); hid_smb.cpp/.h (CP2112 HID-SMBus state machine); i2c_backend.cpp (virtual→physical I2C mapping); usb_mctp_header.h (UsbMctpHeader, UsbDmtfId); usb_stub.h (dual-core stub that proxies to usb_proxy).

Entry points:

  • Task::main() event loop — src/nv/usb/task.cpp:73.
  • Task::mctp_receive()src/nv/usb/task.cpp:257, which calls route_mctp_to_downstream(...) (src/nv/usb/mctp_router.cpp:34). On a routing-table hit it forwards to i2c::Task::tx / i3c::Task::tx / spi::Task::tx; otherwise it hands off to mctp::Driver::mctp_send with client UsUsb.
  • Task::usb_tx(...) outbound MCTP — the target of nv::mctp::Driver::forward() for Client::UsUsb.
  • struct UsbMctpHeadersrc/nv/usb/usb_mctp_header.h:28; class HidSmbsrc/nv/usb/hid_smb.h:26.

USB proxy — src/nv/usb_proxy/

On the dual-core (NCSI) build the bare-metal USB stack lives on core1; this core0 task services that traffic after it crosses the C2C link. nv::usb_proxy::Task (src/nv/usb_proxy/task.h:56) receives forwarded USB data and (a) parses/routes MCTP to the MCTP driver, (b) emulates the CP2112 HID-to-I2C bridge, and (c) forwards LSTP channels. The whole file is gated on #if NCSI_ENABLE.

Entry points:

  • Task::process_mctp_from_c2c(...)src/nv/usb_proxy/task.cpp:202, which builds an mctp::Packet with client UsUsb and calls mctp::Driver::mctp_send(...).
  • dispatch_c2c_data(...)src/nv/usb_proxy/task.cpp:622, the C2C fan-out that routes UsbTx→MCTP, UsbHid→HID, UsbAcm→UART bridge, and LstpRx→LSTP.

VCOM — src/nv/vcom/

USB Virtual COM endpoints. Two independent sub-drivers, neither of which carries MCTP:

  • src/nv/vcom/vruart/ — a UART↔USB bridge. nv::vruart::BridgeTask (src/nv/vcom/vruart/task.h:31) runs a compile-time-selected Bridge alias (src/nv/vcom/vruart/bridge.h:32): either CdcBridge (raw CDC-ACM serial) or LstpBridge (UART tunnelled inside NVIDIA LSTP framing), chosen by nv::ipc::UartOverUsbProtocol.
  • src/nv/vcom/gpio_mon/ — a diagnostic GPIO monitor (nv::gpio_mon::Task, src/nv/vcom/gpio_mon/task.h:41) that streams GPIO state over a CDC VCOM endpoint using a small bespoke binary record protocol (full dump per 100 ms scan tick, per-bank interrupt records from GPIO ISRs).

SSIF — src/nv/ssif/

Despite living beside the MCTP bindings, SSIF here is the IPMI SSIF (SMBus System Interface) slave, not MCTP-over-SMBus. nv::ssif::Ssif (src/nv/ssif/ssif.h:123) acts as an I2C/SMBus slave at the BMC address and implements the IPMI SSIF multi-part SMBus block-write / block-read command codes with PEC validation, assembling IPMI request/response messages up to 254 bytes.

Once an inbound IPMI message is fully assembled, Ssif::handle_rx() (src/nv/ssif/ssif.cpp:103) hands it up over LSTP via nv::lstp::LstpRouter::send_ipmi(...) — the IPMI payload is wrapped in an LstpHdr (struct Ssif::Packet, src/nv/ssif/ssif.h:130) and shipped over the USB/LSTP path. Outbound responses arrive back through the Ssif queue (Task::to_ssif, src/nv/ssif/task.cpp:62). SSIF is disabled by default — Task::is_default_enabled() returns false (src/nv/ssif/task.cpp:91) — and is enabled at runtime.

Interpretation: SSIF, the VCOM vruart LSTP path, and usb_proxy all converge on the NVIDIA LSTP router rather than MCTP. LSTP is OpenSMA’s own USB tunnelling layer; MCTP and IPMI/SSIF are distinct message worlds that happen to share the USB and SMBus media.

Summary

Driver Path Carries MCTP? Key entry
I2C/SMBus src/nv/i2c/ Yes (UsI2c, DsI2c0..7) Task::tx src/nv/i2c/task.cpp:171
I3C src/nv/i3c/ Yes (DsI3c0/1), via IBI Task::on_ibi src/nv/i3c/task.cpp:396
SPI src/nv/spi/ Yes (Spi0..2), SPB Task::tx src/nv/spi/task.cpp:166
UART src/nv/uart/ No (console/log) Driver::tx src/nv/uart/driver.h:50
USB src/nv/usb/ Yes (UsUsb), + HID/LSTP Task::mctp_receive src/nv/usb/task.cpp:257
USB proxy src/nv/usb_proxy/ Yes (Core1 → MCTP) dispatch_c2c_data src/nv/usb_proxy/task.cpp:622
VCOM src/nv/vcom/ No (CDC-ACM / LSTP / GPIO) BridgeTask src/nv/vcom/vruart/task.h:31
SSIF src/nv/ssif/ No (IPMI over SMBus → LSTP) Ssif::handle_rx src/nv/ssif/ssif.cpp:103

See MCTP transport for how the “Yes” rows plug into the transport core, and the section landing for the overview.


Built with Just the Docs. Source-traced against NVIDIA/OpenSMA at 9b183d3 (v02.0020.0000). Methodology under appendices/trace-methodology.

This site uses Just the Docs, a documentation theme for Jekyll.