Documentation/driver-api/mailbox.rst GitHub 원문 ↗

Linux 6.18.37 · Driver API

The Common Mailbox Framework

Platform-specific remote protocol을 common controller·client API로 연결하고 IRQ·polling 완료 감지와 sync·async send를 구성하는 방법입니다.

Source pathDocumentation/driver-api/mailbox.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

mailbox.rst:1-129

Common Mailbox Framework는 controller transport code의 중복을 줄이지만 remote packet protocol은 client driver 책임으로 남깁니다. Controller는 IRQ·polling·client-known completion 중 하나를 명시하고, client는 `tx_block`, callback, timeout과 channel index로 sync·async semantics를 구성합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 ============================
2 The Common Mailbox Framework
3 ============================
4
5 :Author: Jassi Brar <[email protected]>
6
7 This document aims to help developers write client and controller
8 drivers for the API. But before we start, let us note that the
9 client (especially) and controller drivers are likely going to be
10 very platform specific because the remote firmware is likely to be
11 proprietary and implement non-standard protocol. So even if two
12 platforms employ, say, PL320 controller, the client drivers can't
13 be shared across them. Even the PL320 driver might need to accommodate
14 some platform specific quirks. So the API is meant mainly to avoid
15 similar copies of code written for each platform. Having said that,
16 nothing prevents the remote f/w to also be Linux based and use the
17 same api there. However none of that helps us locally because we only
18 ever deal at client's protocol level.
19
20 Some of the choices made during implementation are the result of this
21 peculiarity of this "common" framework.
22
23
24
25 Controller Driver (See include/linux/mailbox_controller.h)
26 ==========================================================
27
28
29 Allocate mbox_controller and the array of mbox_chan.
30 Populate mbox_chan_ops, except peek_data() all are mandatory.
31 The controller driver might know a message has been consumed
32 by the remote by getting an IRQ or polling some hardware flag
33 or it can never know (the client knows by way of the protocol).
34 The method in order of preference is IRQ -> Poll -> None, which
35 the controller driver should set via 'txdone_irq' or 'txdone_poll'
36 or neither.
37
38
39 Client Driver (See include/linux/mailbox_client.h)
40 ==================================================
41
42
43 The client might want to operate in blocking mode (synchronously
44 send a message through before returning) or non-blocking/async mode (submit
45 a message and a callback function to the API and return immediately).
46
47 ::
48
49 struct demo_client {
50 struct mbox_client cl;
51 struct mbox_chan *mbox;
52 struct completion c;
53 bool async;
54 /* ... */
55 };
56
57 /*
58 * This is the handler for data received from remote. The behaviour is purely
59 * dependent upon the protocol. This is just an example.
60 */
61 static void message_from_remote(struct mbox_client *cl, void *mssg)
62 {
63 struct demo_client *dc = container_of(cl, struct demo_client, cl);
64 if (dc->async) {
65 if (is_an_ack(mssg)) {
66 /* An ACK to our last sample sent */
67 return; /* Or do something else here */
68 } else { /* A new message from remote */
69 queue_req(mssg);
70 }
71 } else {
72 /* Remote f/w sends only ACK packets on this channel */
73 return;
74 }
75 }
76
77 static void sample_sent(struct mbox_client *cl, void *mssg, int r)
78 {
79 struct demo_client *dc = container_of(cl, struct demo_client, cl);
80 complete(&dc->c);
81 }
82
83 static void client_demo(struct platform_device *pdev)
84 {
85 struct demo_client *dc_sync, *dc_async;
86 /* The controller already knows async_pkt and sync_pkt */
87 struct async_pkt ap;
88 struct sync_pkt sp;
89
90 dc_sync = kzalloc(sizeof(*dc_sync), GFP_KERNEL);
91 dc_async = kzalloc(sizeof(*dc_async), GFP_KERNEL);
92
93 /* Populate non-blocking mode client */
94 dc_async->cl.dev = &pdev->dev;
95 dc_async->cl.rx_callback = message_from_remote;
96 dc_async->cl.tx_done = sample_sent;
97 dc_async->cl.tx_block = false;
98 dc_async->cl.tx_tout = 0; /* doesn't matter here */
99 dc_async->cl.knows_txdone = false; /* depending upon protocol */
100 dc_async->async = true;
101 init_completion(&dc_async->c);
102
103 /* Populate blocking mode client */
104 dc_sync->cl.dev = &pdev->dev;
105 dc_sync->cl.rx_callback = message_from_remote;
106 dc_sync->cl.tx_done = NULL; /* operate in blocking mode */
107 dc_sync->cl.tx_block = true;
108 dc_sync->cl.tx_tout = 500; /* by half a second */
109 dc_sync->cl.knows_txdone = false; /* depending upon protocol */
110 dc_sync->async = false;
111
112 /* ASync mailbox is listed second in 'mboxes' property */
113 dc_async->mbox = mbox_request_channel(&dc_async->cl, 1);
114 /* Populate data packet */
115 /* ap.xxx = 123; etc */
116 /* Send async message to remote */
117 mbox_send_message(dc_async->mbox, &ap);
118
119 /* Sync mailbox is listed first in 'mboxes' property */
120 dc_sync->mbox = mbox_request_channel(&dc_sync->cl, 0);
121 /* Populate data packet */
122 /* sp.abc = 123; etc */
123 /* Send message to remote in blocking mode */
124 mbox_send_message(dc_sync->mbox, &sp);
125 /* At this point 'sp' has been sent */
126
127 /* Now wait for async chan to be done */
128 wait_for_completion(&dc_async->c);
129 }
130

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

Common Mailbox Framework 개요

1-24

문서 제목은 `The Common Mailbox Framework`이며 저자는 Jassi Brar입니다. 이 문서는 API용 client driver와 controller driver 작성자를 돕습니다.

Remote firmware가 proprietary이고 non-standard protocol을 구현하는 경우가 많으므로 client driver와 controller driver는 대체로 platform-specific입니다. 두 platform이 같은 PL320 controller를 사용해도 client driver를 공유할 수 없고 PL320 driver 자체에도 platform quirk 처리가 필요할 수 있습니다.

이 API의 주목적은 platform마다 비슷한 code copy를 반복하는 일을 줄이는 것입니다. Remote firmware가 Linux와 같은 API를 사용할 수도 있지만 local side는 client protocol level만 다루므로 그 사실만으로 local implementation을 공유할 수는 없습니다. Framework 구현 선택 일부는 이런 특성에서 비롯됩니다.

Mailbox abstraction boundary
Platform-specific client protocolCommon mailbox client APIMailbox controller driverHardware mailboxProprietary 또는 Linux remote firmware

Common framework가 transport API를 통합하지만 protocol은 client에 남깁니다.

Controller driver

25-38

Controller driver는 `include/linux/mailbox_controller.h`를 따릅니다. `mbox_controller`와 `mbox_chan` array를 allocate하고 `mbox_chan_ops`를 채웁니다. `peek_data()`만 optional이고 나머지 operation은 필수입니다.

Remote가 message를 consume했다는 사실을 controller가 IRQ로 알거나 hardware flag polling으로 알 수 있으며, protocol을 아는 client만 완료를 알고 controller는 전혀 모를 수도 있습니다. 선호 순서는 IRQ, polling, none입니다. Driver는 각각 `txdone_irq`, `txdone_poll`, 둘 다 설정하지 않음으로 표시합니다.

Controller 준비 항목
항목규칙
mbox_controllerController instance allocate
mbox_chan[]Channel array allocate
mbox_chan_opspeek_data 외 모두 mandatory
Completion sourcetxdone_irq 또는 txdone_poll 또는 neither

Allocation과 mandatory operation을 정리했습니다.

TX completion 감지 우선순위
Remote consume 감지 방법 확인IRQ 가능?예: txdone_irq아니오: hardware polling 가능?예: txdone_poll아니오: neither, client protocol이 완료 판단

Controller가 선택해야 할 가장 신뢰도 높은 방식입니다.

Client driver mode

39-46

Client driver는 `include/linux/mailbox_client.h`를 사용합니다. Blocking mode에서는 message 전송을 완료한 뒤 caller로 돌아옵니다. Non-blocking 또는 asynchronous mode에서는 message와 callback을 API에 제출하고 즉시 반환합니다.

Client send mode
ModeSend call returnCompletion
Blocking / synchronousMessage가 전송된 뒤Call 내부 wait·timeout
Non-blocking / asyncSubmit 직후tx_done callback 또는 client completion

Return 시점과 completion notification 차이입니다.

Client structure와 callback 예제

47-82

예제 `struct demo_client`는 `struct mbox_client`, channel pointer, completion, async flag를 보관합니다. 실제 packet format과 ACK 구분은 framework가 아니라 remote protocol에 달려 있습니다.

`message_from_remote()`는 async client에서 ACK면 마지막 sample의 acknowledgment로 처리하고, 새 remote message면 `queue_req()`로 넘깁니다. Synchronous channel 예시는 remote firmware가 ACK packet만 보낸다고 가정합니다.

`sample_sent()`는 async transmission이 끝나면 client의 completion을 signal합니다.

struct demo_client {
        struct mbox_client cl;
        struct mbox_chan *mbox;
        struct completion c;
        bool async;
        /* ... */
};

/*
* This is the handler for data received from remote. The behaviour is purely
* dependent upon the protocol. This is just an example.
*/
static void message_from_remote(struct mbox_client *cl, void *mssg)
{
        struct demo_client *dc = container_of(cl, struct demo_client, cl);
        if (dc->async) {
                if (is_an_ack(mssg)) {
                        /* An ACK to our last sample sent */
                        return; /* Or do something else here */
                } else { /* A new message from remote */
                        queue_req(mssg);
                }
        } else {
                /* Remote f/w sends only ACK packets on this channel */
                return;
        }
}

static void sample_sent(struct mbox_client *cl, void *mssg, int r)
{
        struct demo_client *dc = container_of(cl, struct demo_client, cl);
        complete(&dc->c);
}
RX callback protocol dispatch
message_from_remoteClient가 async인가?예: is_an_ack?ACK면 return새 message면 queue_reqSync channel이면 protocol상 ACK만 처리

Framework callback 안에서 client protocol이 ACK와 새 request를 구분합니다.

demo_client state
Field역할
clMailbox client configuration·callback
mboxRequested channel
completion cAsync TX 완료 wait
asyncProtocol handling mode

예제에서 필요한 client-side state입니다.

Sync·async channel 사용 예제

83-129

`client_demo()`는 synchronous client와 asynchronous client를 각각 allocate합니다. Controller는 `async_pkt`과 `sync_pkt`의 format을 이미 알고 있다고 가정합니다.

Async client는 `rx_callback=message_from_remote`, `tx_done=sample_sent`, `tx_block=false`, `tx_tout=0`, protocol에 따라 `knows_txdone=false`, `async=true`로 설정하고 completion을 initialize합니다.

Blocking client는 같은 RX callback을 쓰지만 `tx_done=NULL`, `tx_block=true`, timeout 500ms, `knows_txdone=false`, `async=false`로 설정합니다.

Device tree 등의 `mboxes` property에서 async mailbox가 두 번째이므로 channel index 1을, sync mailbox가 첫 번째이므로 index 0을 `mbox_request_channel()`로 요청합니다. 각 packet을 채운 뒤 `mbox_send_message()`로 전송합니다.

Blocking send가 반환한 시점에는 `sp`가 전송된 상태입니다. Async channel은 별도로 `wait_for_completion()`을 호출해 `sample_sent()`의 signal을 기다립니다.

static void client_demo(struct platform_device *pdev)
{
        struct demo_client *dc_sync, *dc_async;
        /* The controller already knows async_pkt and sync_pkt */
        struct async_pkt ap;
        struct sync_pkt sp;

        dc_sync = kzalloc(sizeof(*dc_sync), GFP_KERNEL);
        dc_async = kzalloc(sizeof(*dc_async), GFP_KERNEL);

        /* Populate non-blocking mode client */
        dc_async->cl.dev = &pdev->dev;
        dc_async->cl.rx_callback = message_from_remote;
        dc_async->cl.tx_done = sample_sent;
        dc_async->cl.tx_block = false;
        dc_async->cl.tx_tout = 0; /* doesn't matter here */
        dc_async->cl.knows_txdone = false; /* depending upon protocol */
        dc_async->async = true;
        init_completion(&dc_async->c);

        /* Populate blocking mode client */
        dc_sync->cl.dev = &pdev->dev;
        dc_sync->cl.rx_callback = message_from_remote;
        dc_sync->cl.tx_done = NULL; /* operate in blocking mode */
        dc_sync->cl.tx_block = true;
        dc_sync->cl.tx_tout = 500; /* by half a second */
        dc_sync->cl.knows_txdone = false; /* depending upon protocol */
        dc_sync->async = false;

        /* ASync mailbox is listed second in 'mboxes' property */
        dc_async->mbox = mbox_request_channel(&dc_async->cl, 1);
        /* Populate data packet */
        /* ap.xxx = 123; etc */
        /* Send async message to remote */
        mbox_send_message(dc_async->mbox, &ap);

        /* Sync mailbox is listed first in 'mboxes' property */
        dc_sync->mbox = mbox_request_channel(&dc_sync->cl, 0);
        /* Populate data packet */
        /* sp.abc = 123; etc */
        /* Send message to remote in blocking mode */
        mbox_send_message(dc_sync->mbox, &sp);
        /* At this point 'sp' has been sent */

        /* Now wait for async chan to be done */
        wait_for_completion(&dc_async->c);
}
예제 client configuration
FieldAsync clientSync client
tx_donesample_sentNULL
tx_blockfalsetrue
tx_tout0, 사용 안 함500ms
async flagtruefalse
Channel index10

동일 API에서 blocking과 async 설정을 비교합니다.

Asynchronous send
mbox_request_channel(index 1)Packet ap 구성mbox_send_message즉시 returnsample_sent callbackcomplete(&c)wait_for_completion 해제

Submit과 completion wait가 분리됩니다.

Blocking send
mbox_request_channel(index 0)Packet sp 구성mbox_send_messageFramework가 최대 500ms waitReturn 시 sp 전송 완료

Send call의 반환 자체가 전송 완료 boundary입니다.