Back to home page

LXR

 
 

    


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