Linux IPI Mailbox Driver

Linux IPI Mailbox Driver

Introduction

This page gives an overview of IPI Mailbox driver which is available as part of the Xilinx Linux distribution or Open source linux as drivers/mailbox/zynqmp-ipi-mailbox.c

This information corresponds to the IPI Mailbox driver that is the main branch of the Git tree.
This driver supports IPI in ZynqMP, Versal Gen 1 and Versal Gen 2 devices.

HW/IP Features

  • Cross-processor communication interrupts with message passing

    • Source agent (a processor)

    • Destination agent (a processor)

  • Number of Agents:

    • Three hardwired agents: PMC with and without a message buffer, and PSM with buffer

    • Five software selectable agents with message buffer

    • One software selectable agent without message buffer

  • Agent assignments

    • System management ID (SMID) tags in the IPI registers are used for message buffer and interrupt register access

    • System interrupt routing

  • IPI agent interrupt registers

    • Protected by 64 KB apertures in LPD_XPPU

  • IPI software message filtering

  • Message buffers are protected by hardware, and aperture controls using the SMIDs

    • 64 request message buffers, 32 bytes each

    • 64 response message buffers, 32 bytes each

 

Features supported in driver

  • Supports cross-processor communication and message passing using IPI hardware.

  • Allows configuration of source and destination agents (processors) for communication.

  • Handles multiple IPI agents, including both hardwired and software-selectable agents.

  • Manages both transmit (TX) and receive (RX) mailbox channels for each agent.

  • Integrates with the Linux mailbox framework, providing standard mailbox controller and channel operations.

  • Uses ARM SMC or HVC calls to interact with platform firmware for mailbox operations.

  • Handles IPI interrupts, including both system IRQs and per-CPU SGIs, with proper registration and cleanup.

  • Validates message sizes against hardware buffer limits (typically 32 bytes per buffer).

  • Configures all agent IDs, buffer regions, and interrupts via device tree bindings for flexible integration.

  • Supports CPU hotplug events and proper resource management, including per-CPU IRQ handling and dynamic device registration/unregistration.

Missing features, Known Issues and Limitations

  • Advanced software message filtering is not implemented; only basic message checks are performed.

  • Fine-grained SMID-based access control and aperture configuration for message buffers and interrupt registers are not managed by the driver.

  • The driver does not configure or manage the 64 KB LPD_XPPU apertures for IPI register protection; this is assumed to be handled by hardware or firmware.

  • Dynamic agent assignment or runtime reconfiguration of agent IDs is not supported; agent IDs are fixed via device tree.

  • The driver does not provide APIs to enumerate, allocate, or manage all 64 request/response buffers in hardware.

  • Explicit support for multiple bufferless agents or mixed buffer/bufferless configurations is limited.

  • Not all IPI hardware features (such as acceptance filters, advanced interrupt routing, or buffer protection settings) are exposed to user space or higher-level software.

  • Fine-grained or programmable interrupt routing between agents is not provided by the driver.

  • Programmable acceptance filters for message reception are not implemented.

  • Detailed error reporting, logging, and diagnostics for all IPI hardware events are not fully supported.

Kernel Configuration

 

Symbol: ZYNQMP_IPI_MBOX [=y] │ │ Type : tristate │ │ Defined at drivers/mailbox/Kconfig:253 │ │ Prompt: Xilinx ZynqMP IPI Mailbox │ │ Depends on: MAILBOX [=y] && ARCH_ZYNQMP [=y] && OF [=y] │ │ Location: │ │ -> Device Drivers │ │ -> Mailbox Hardware Support (MAILBOX [=y]) │ │ (1) -> Xilinx ZynqMP IPI Mailbox (ZYNQMP_IPI_MBOX [=y]) │ │ Selected by [y]: │ │ - XLNX_R5_REMOTEPROC [=y] && REMOTEPROC [=y] && PM [=y] && ARCH_ZYNQMP [=y] │ │ - ZYNQMP_POWER [=y] && PM [=y] && ZYNQMP_FIRMWARE [=y]

 

The driver is available at,
https://github.com/Xilinx/linux-xlnx/blob/master/drivers/mailbox/zynqmp-ipi-mailbox.c

Device Tree

For More details about the device tree bindings doc please refer to the Documentation/devicetree/bindings/mailbox/xlnx%2Czynqmp-ipi-mailbox.yaml

For ZynqMP: amba { #address-cells = <0x2>; #size-cells = <0x2>; zynqmp-mailbox { compatible = "xlnx,zynqmp-ipi-mailbox"; interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; xlnx,ipi-id = <0>; #address-cells = <2>; #size-cells = <2>; ranges; mailbox: mailbox@ff9905c0 { compatible = "xlnx,zynqmp-ipi-dest-mailbox"; reg = <0x0 0xff9905c0 0x0 0x20>, <0x0 0xff9905e0 0x0 0x20>, <0x0 0xff990e80 0x0 0x20>, <0x0 0xff990ea0 0x0 0x20>; reg-names = "local_request_region", "local_response_region", "remote_request_region", "remote_response_region"; #mbox-cells = <1>; xlnx,ipi-id = <4>; }; }; }; For Versal: bus { #address-cells = <2>; #size-cells = <2>; mailbox@ff300000 { compatible = "xlnx,versal-ipi-mailbox"; interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>; #address-cells = <2>; #size-cells = <2>; reg = <0x0 0xff300000 0x0 0x1000>, <0x0 0xff990000 0x0 0x1ff>; reg-names = "ctrl", "msg"; xlnx,ipi-id = <0>; ranges; /* buffered IPI */ mailbox@ff340000 { compatible = "xlnx,versal-ipi-dest-mailbox"; reg = <0x0 0xff340000 0x0 0x1000>, <0x0 0xff990400 0x0 0x1ff>; reg-names = "ctrl", "msg"; #mbox-cells = <1>; xlnx,ipi-id = <4>; }; /* bufferless IPI */ mailbox@ff370000 { compatible = "xlnx,versal-ipi-dest-mailbox"; reg = <0x0 0xff370000 0x0 0x1000>; reg-names = "ctrl"; #mbox-cells = <1>; xlnx,ipi-id = <7>; }; }; };

Test Procedure

IPI Mailbox Client Driver Example

struct ipi_mbox_demo_client { struct mbox_client cl; struct mbox_chan *mchan; struct completion c; /* ... */ }; /* * This is the rx callback for data (data in IPI source request buffer) received from remote. */ static void ipi_rx_callback(struct mbox_client *cl, void *mssg) { struct ipi_mbox_demo_client *dc = container_of(cl, struct ipi_mbox_demo_client, cl); /* A new message is received, depends on your application, handler the received data. */ queue_req(mssg); } /* * This is tx done callback. This is only required if the user needs to be notified if the message * has been sent. */ static void ipi_tx_done(struct mbox_client *cl, void *active_request, int r) { struct ipi_mbox_demo_client *dc = container_of(cl, struct ipi_mbox_demo_client, cl); /* In case you want to get the IPI response from the IPI response buffer */ struct ipi_mbox_channel *ipi_chnl = (struct ipi_mbox_channel *)dc->mchan->con_priv; /* active_request indicates which request has been sent */ if (!active_request) { /* get the IPI response from ipi_chnl response data */ kfree(active_request); } complete(&dc->c); } static void ipi_mbox_client_demo() { struct ipi_mbox_demo_client *dc; uint8_t *data; dc = kzalloc(sizeof(*dc), GFP_KERNEL); data = kzalloc(sizeof(*dc), GFP_KERNEL); #ifdef TX_DONE_REQUESTED /* Populate client needs to know when TX is done */ dc->cl.dev = &pdev->dev; dc->cl.rx_callback = ipi_rx_callback; dc->cl.tx_done = ipi_tx_done; dc->cl.tx_block = true; dc->cl.tx_tout = 1; /* by 1 miniseconds */ dc->cl.knows_txdone = false; /* mailbox is listed second in 'mboxes' property */ dc->mchan = mbox_request_channel_byname(&dc->cl, "rpu0"); mbox_send_message(dc_async->mchan, &data); /* If I just want to kick without message */ mbox_send_message(dc_async->mchan, NULL); /* Now wait for async chan to be done */ wait_for_completion(&dc_async->c); #else /* Populate client doesn't need to know when TX is done */ dc->cl.dev = &pdev->dev; dc->cl.rx_callback = ipi_rx_callback; dc->cl.tx_done = NULL; dc->cl.tx_block = false; dc->cl.tx_tout = 0; /* Doesn't matter in this case */ dc->cl.knows_txdone = false; /* Async mailbox is listed second in 'mboxes' property */ dc->mchan = mbox_request_channel_byname(&dc->cl, "rpu1"); mbox_send_message(dc->mchan, &data); /* If I just want to kick without message */ mbox_send_message(dc->mchan, NULL); #endif }

IPI MailBox Driver Userspace APIs

ioctl APIs for channel requesting.

  • when requesting an IPI channel, it will do the following verification

    • target cannot be PMU

    • target cannot be already requested

    • If it has passed verification, it will

    • create a char device for the requested channel

    • create a mbox client for  the requested channel

      • the mbox client will register rx_callback, the rx_callback will put the received data into the socket buffer queue

each API channel is a char device

  • open()

    • request the IPI mailbox channel

  • release()

    • shutdown the IPI mailbox channel

  • wirte()

    • len > 0, it will write data to IPI request buffer, if it is more than 32bytes, it will only write the first 32bytes to the IPI request buffer, and set IPI target bit of the trigger register.

    • len == 0, it will set IPI target bit of trigger register.

  • read()

    • copy data from the received IPI request data socket buffer queue if there is data ready.

Mainline status

This driver is currently in sync with mainline kernel driver.

Change Log

2025.1

2024.2

2024.1

2023.2

  • None

© Copyright 2019 - 2022 Xilinx Inc. Privacy Policy