drivers/mbox: Add mailbox framework and PL320 driver#18859
drivers/mbox: Add mailbox framework and PL320 driver#18859Jiaqi-YP7 wants to merge 1 commit intoapache:masterfrom
Conversation
8c3ca1a to
4a92248
Compare
acassis
left a comment
There was a problem hiding this comment.
@Jiaqi-YP7 nice work! Please provide some basic Documentation about this new feature
|
@acassis Thanks for the review and kind words! I’ll add basic documentation as soon as possible. |
|
Hi: Could you Rebase your PR with the Master Branch? We fixed the Config Error for esp32p4-function-ev-board. Thanks :-) |
Add a generic mailbox framework under drivers/mbox with an upper-half API for channel lookup, TX/RX callback handling, blocking and non-blocking sends, timeout handling, queued TX messages, and optional trace statistics. Add the first lower-half implementation for the ARM PL320 IPCM. The driver programs channel source, destination, and mask registers, transfers payloads through the PL320 data registers, handles ACK/completion flow, and exposes pl320_initialize() for board code. This provides a reusable mailbox abstraction for SoCs that need kernel-level inter-processor communication without duplicating controller-independent TX/RX state management in each lower-half driver. Signed-off-by: yaojiaqi <yaojiaqi@lixiang.com>
4a92248 to
3346831
Compare
Thanks for the heads-up and the fix! :-) I've rebased my PR with the master branch. |
| #define MBOX_REGISTER_CALLBACK(d,c,cb,a) \ | ||
| ((d)->ops->registercallback(d,c,cb,a)) | ||
| #define MBOX_REGISTER_CALLBACK(c, cb, a) \ | ||
| ((c)->dev->ops->setcallback(c, cb, a)) |
There was a problem hiding this comment.
why use the different name for macro and field
| static int mbox_enqueue_data(FAR struct mbox_chan_s *chan, | ||
| FAR const void *data, size_t size) | ||
| { | ||
| if (size > MBOX_MAX_MSG_SIZE) |
There was a problem hiding this comment.
why limit msg size
| } | ||
|
|
||
| circbuf_write(&chan->txbuf, (FAR void *)&size, sizeof(size_t)); | ||
| circbuf_write(&chan->txbuf, (FAR void *)data, size); |
There was a problem hiding this comment.
remove ALL cast to circbuf_write
| return -ENODATA; | ||
| } | ||
|
|
||
| circbuf_read(&chan->txbuf, (FAR void *)size, sizeof(size_t)); |
There was a problem hiding this comment.
remove ALL cast to circbuf_read
| { | ||
| int ret; | ||
|
|
||
| ret = chan->dev->ops->send(chan, data, size); |
There was a problem hiding this comment.
call macro instead
|
|
||
| if (chan->dir == MBOX_TX) | ||
| { | ||
| if (WDOG_ISACTIVE(&chan->timer)) |
| { | ||
| if (WDOG_ISACTIVE(&chan->timer)) | ||
| { | ||
| wd_cancel(&chan->timer); |
There was a problem hiding this comment.
do you need wd_cancel_sync
| #define IPCMXMCLEAR(m) (((m) * 0x40) + 0x018) | ||
| #define IPCMXMSTATUS(m) (((m) * 0x40) + 0x01C) | ||
| #define IPCMXSEND(m) (((m) * 0x40) + 0x020) | ||
| #define IPCMXDR(m, dr) (((m) * 0x40) + ((dr) * 4) + 0x024) |
There was a problem hiding this comment.
| #define IPCMXDR(m, dr) (((m) * 0x40) + ((dr) * 4) + 0x024) | |
| #define IPCMXDR(m, dr) (((m) * 0x40) + 0x024+ ((dr) * 4)) |
| } | ||
|
|
||
| priv->base.ops = &g_pl320mbox_ops; | ||
| priv->base.chans = (FAR struct mbox_chan_s *)config->chans; |
There was a problem hiding this comment.
why set to base.chans, you can't safely access each element through base.chans since pl320_chan has the different size than mbox_chan
| * non-blocking receiving methods. It is designed based on the state transfer | ||
| * of lower-half ops as follows. | ||
| * | ||
| * ----------------------------------------------------------------- |
There was a problem hiding this comment.
the new model is even complex than linux, why not simplify it?
https://github.com/torvalds/linux/blob/master/include/linux/mailbox_controller.h#L54-L60
|
Thanks a lot @xiaoxiang781216 for the detailed review. This PR is a relatively large piece of work, and several comments involve the overall framework design, so I need some time to carefully evaluate each point. I’ll first handle the straightforward cleanup items, then take a closer look at the design and simplification suggestions before updating the PR. |
drivers/mbox: Add mailbox framework and PL320 driver
Summary
This change adds a generic mailbox (MBOX) framework under
drivers/mboxand an initial ARM PL320 IPCM lower-half driver.
The motivation is to provide a small, reusable kernel-level abstraction for
SoC mailbox controllers. Many multicore SoCs provide mailbox/IPCM hardware for
short inter-processor messages, event notifications, and resource coordination,
but each controller usually has slightly different register layout and
completion semantics. Without a common framework, each user has to duplicate
channel lookup, send/receive state handling, timeout handling, callbacks, and
controller-specific glue.
This patch introduces an upper-half/lower-half split:
struct mbox_dev_s,struct mbox_chan_s,struct mbox_sender_s,struct mbox_receiver_s, and the public mailboxAPIs in
include/nuttx/mbox/mbox.h.struct mbox_ops_sto handle controllerdetails such as channel setup, message send/receive, ACK generation, TX
completion, and hardware ready/available checks.
interface and exposes
pl320_initialize()throughinclude/nuttx/mbox/pl320.h.The generic framework supports the following TX/RX flow:
struct mbox_sender_s.configured timeout expires.
mbox_chan_tx_done()when an ACK/completion isobserved, either from an interrupt handler or from polling logic.
mbox_chan_rx_data()when data is available. Thegeneric layer receives the message, sends an ACK when supported, and invokes
the registered RX callback.
CONFIG_MBOX_TRACEstatistics are provided for sent, received,acknowledged, buffered, and timed-out messages.
For PL320, the driver maps each configured mailbox to an
mbox_chan_s,programs the source/destination/mask registers during setup, transfers payloads
through the PL320 data registers, and routes IRQ events to the generic TX
completion or RX receive paths.
Design
The design separates common mailbox semantics from hardware-specific control.
The framework only assumes that a mailbox channel can report whether TX is
ready, whether RX data is available, and whether a TX message has completed or
been acknowledged. The exact hardware mechanism remains in the lower-half
driver.
The generic channel object stores common runtime state:
MBOX_TXorMBOX_RX)This keeps board/controller drivers small. A lower-half driver only needs to
provide the hardware operations:
getchan()to resolve a platform-specific channel argumentsetup()/shutdown()for channel ownership and configurationsend()/recv()for payload transferacknowledge()for RX-side ACK generation when the hardware supports ittxfinish()to clear completion state and prepare for the next transfersetcallback()for RX callback registrationrxavailable(),txready(), andtxacked()for status checksThe PL320 implementation follows this model directly. Board code supplies a
struct pl320_config_swith the local IPCM interrupt index, IRQ number, and anarray of configured PL320 channels. Each
struct pl320_chan_sdescribes themailbox index, source core, destination core, whether the channel should be
configured by this side, and the TX buffer used by the generic framework.
Impact
This is additive and gated by Kconfig:
CONFIG_MBOXenables the generic mailbox framework.CONFIG_MBOX_PL320enables the ARM PL320 lower-half driver.CONFIG_MBOX_TRACEoptionally enables per-channel statistics.There is no intended behavior change for existing drivers or boards unless
they enable and instantiate the new mailbox driver.
Build impact is limited to the new
drivers/mboxdirectory and the newdrivers/Kconfig/drivers/Makefileintegration. Existing IPCC, RPMsg, andother driver users are not changed by this patch.
Hardware impact is limited to boards that explicitly initialize a PL320
controller and provide a channel table. The PL320 lower half supports up to 32
mailboxes and transfers up to 28 bytes per PL320 message, matching the seven
32-bit PL320 data registers.
Compatibility impact should be low because the new APIs are introduced under a
new
include/nuttx/mboxnamespace. No existing public mailbox API is replaced.Basic Usage
Enable the framework and lower-half driver in Kconfig:
Optionally enable trace statistics:
Board or SoC initialization code should define PL320 channels and initialize
the controller. A TX channel needs a TX buffer for the framework queue:
After initialization, client code can resolve a channel and send a message:
For a bounded wait, use
mbox_ticksend():For a non-blocking send, pass a zero timeout. If the channel is active, the
message can be buffered for later transmission. If the hardware is idle but not
ready, the API returns
-EAGAIN.RX clients register a callback on an RX channel:
The lower-half interrupt handler or polling path should notify the framework:
When a channel is no longer used, platform code can release framework-owned
resources with:
Testing
Test background:
This was tested on a downstream private SoC platform. The SoC has multiple
processor cores that communicate through mailbox hardware based on ARM PL320.
For this validation, one RISC-V core and one Arm R52 core were selected to
verify PL320-based mailbox communication through the new generic MBOX framework
and PL320 lower-half driver.
A downstream
ipcmtesttest application was developed for this validation.The test application uses the public MBOX APIs added by this patch and covers:
timeout == 0Configuration and board initialization evidence:
The downstream board configuration enabled the generic MBOX framework, the
PL320 lower-half driver, and the
ipcmtesttest app:Our board/vendor layer provides the PL320 channel table used by the test.
For the tested RISC-V <-> R52 pair, PL320 channel 16 is used for
RISC-V-to-R52 messages, and PL320 channel 17 is used for R52-to-RISC-V
messages:
The board/vendor layer also provides the
struct pl320_config_spassed topl320_initialize(). The localipcmintand IRQ number are selected for thecore that is currently booting:
PL320 is initialized during board mailbox initialization. The returned
struct mbox_dev_sis stored by board code and later used byipcmtest:Test application initialization:
Both cores initialize the PL320 mailbox device, resolve the configured channel,
and register an RX callback with the generic MBOX API.
RISC-V side RX initialization for messages sent from the R52 core:
R52 side RX initialization for messages sent from the RISC-V core:
Callback:
The RX callback checks the lower-half result, verifies that a payload was
provided, increments the RX counter, and prints the received PL320 payload.
Send-flow:
R52-to-RISC-V send path. The R52 core resolves PL320 TX channel 17 and sends
one 28-byte PL320 payload with
mbox_send().RISC-V-to-R52 send path. The RISC-V core resolves PL320 TX channel 16 and sends
one 28-byte PL320 payload with
mbox_send().Non-blocking send path:
Timed send path:
Test results:
R52-to-RISC-V one-way PL320 send
R52 shell output:
RISC-V shell output:
RISC-V-to-R52 one-way PL320 send
RISC-V shell output:
R52 shell output:
Non-blocking send
R52 shell output:
RISC-V shell output:
Trace
R52 shell output:
Timeout
I made riscv crash to make no-ack scene, r52 send by mbox_ticksend();
R52 shell output: