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