Back to home page

OSCL-LXR

 
 

    


0001 ============================
0002 The Common Mailbox Framework
0003 ============================
0004 
0005 :Author: Jassi Brar <jaswinder.singh@linaro.org>
0006 
0007 This document aims to help developers write client and controller
0008 drivers for the API. But before we start, let us note that the
0009 client (especially) and controller drivers are likely going to be
0010 very platform specific because the remote firmware is likely to be
0011 proprietary and implement non-standard protocol. So even if two
0012 platforms employ, say, PL320 controller, the client drivers can't
0013 be shared across them. Even the PL320 driver might need to accommodate
0014 some platform specific quirks. So the API is meant mainly to avoid
0015 similar copies of code written for each platform. Having said that,
0016 nothing prevents the remote f/w to also be Linux based and use the
0017 same api there. However none of that helps us locally because we only
0018 ever deal at client's protocol level.
0019 
0020 Some of the choices made during implementation are the result of this
0021 peculiarity of this "common" framework.
0022 
0023 
0024 
0025 Controller Driver (See include/linux/mailbox_controller.h)
0026 ==========================================================
0027 
0028 
0029 Allocate mbox_controller and the array of mbox_chan.
0030 Populate mbox_chan_ops, except peek_data() all are mandatory.
0031 The controller driver might know a message has been consumed
0032 by the remote by getting an IRQ or polling some hardware flag
0033 or it can never know (the client knows by way of the protocol).
0034 The method in order of preference is IRQ -> Poll -> None, which
0035 the controller driver should set via 'txdone_irq' or 'txdone_poll'
0036 or neither.
0037 
0038 
0039 Client Driver (See include/linux/mailbox_client.h)
0040 ==================================================
0041 
0042 
0043 The client might want to operate in blocking mode (synchronously
0044 send a message through before returning) or non-blocking/async mode (submit
0045 a message and a callback function to the API and return immediately).
0046 
0047 ::
0048 
0049         struct demo_client {
0050                 struct mbox_client cl;
0051                 struct mbox_chan *mbox;
0052                 struct completion c;
0053                 bool async;
0054                 /* ... */
0055         };
0056 
0057         /*
0058         * This is the handler for data received from remote. The behaviour is purely
0059         * dependent upon the protocol. This is just an example.
0060         */
0061         static void message_from_remote(struct mbox_client *cl, void *mssg)
0062         {
0063                 struct demo_client *dc = container_of(cl, struct demo_client, cl);
0064                 if (dc->async) {
0065                         if (is_an_ack(mssg)) {
0066                                 /* An ACK to our last sample sent */
0067                                 return; /* Or do something else here */
0068                         } else { /* A new message from remote */
0069                                 queue_req(mssg);
0070                         }
0071                 } else {
0072                         /* Remote f/w sends only ACK packets on this channel */
0073                         return;
0074                 }
0075         }
0076 
0077         static void sample_sent(struct mbox_client *cl, void *mssg, int r)
0078         {
0079                 struct demo_client *dc = container_of(cl, struct demo_client, cl);
0080                 complete(&dc->c);
0081         }
0082 
0083         static void client_demo(struct platform_device *pdev)
0084         {
0085                 struct demo_client *dc_sync, *dc_async;
0086                 /* The controller already knows async_pkt and sync_pkt */
0087                 struct async_pkt ap;
0088                 struct sync_pkt sp;
0089 
0090                 dc_sync = kzalloc(sizeof(*dc_sync), GFP_KERNEL);
0091                 dc_async = kzalloc(sizeof(*dc_async), GFP_KERNEL);
0092 
0093                 /* Populate non-blocking mode client */
0094                 dc_async->cl.dev = &pdev->dev;
0095                 dc_async->cl.rx_callback = message_from_remote;
0096                 dc_async->cl.tx_done = sample_sent;
0097                 dc_async->cl.tx_block = false;
0098                 dc_async->cl.tx_tout = 0; /* doesn't matter here */
0099                 dc_async->cl.knows_txdone = false; /* depending upon protocol */
0100                 dc_async->async = true;
0101                 init_completion(&dc_async->c);
0102 
0103                 /* Populate blocking mode client */
0104                 dc_sync->cl.dev = &pdev->dev;
0105                 dc_sync->cl.rx_callback = message_from_remote;
0106                 dc_sync->cl.tx_done = NULL; /* operate in blocking mode */
0107                 dc_sync->cl.tx_block = true;
0108                 dc_sync->cl.tx_tout = 500; /* by half a second */
0109                 dc_sync->cl.knows_txdone = false; /* depending upon protocol */
0110                 dc_sync->async = false;
0111 
0112                 /* ASync mailbox is listed second in 'mboxes' property */
0113                 dc_async->mbox = mbox_request_channel(&dc_async->cl, 1);
0114                 /* Populate data packet */
0115                 /* ap.xxx = 123; etc */
0116                 /* Send async message to remote */
0117                 mbox_send_message(dc_async->mbox, &ap);
0118 
0119                 /* Sync mailbox is listed first in 'mboxes' property */
0120                 dc_sync->mbox = mbox_request_channel(&dc_sync->cl, 0);
0121                 /* Populate data packet */
0122                 /* sp.abc = 123; etc */
0123                 /* Send message to remote in blocking mode */
0124                 mbox_send_message(dc_sync->mbox, &sp);
0125                 /* At this point 'sp' has been sent */
0126 
0127                 /* Now wait for async chan to be done */
0128                 wait_for_completion(&dc_async->c);
0129         }