diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-21 14:21:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-21 14:21:19 -0400 |
commit | 43d451f163c1b615c1bedef95258c49712679eeb (patch) | |
tree | 52ed78b04435ffbd663a902bbd5bdb69a65ad584 | |
parent | 21d2271fd0812ebe3716cab0b48356837485a74d (diff) | |
parent | 9f3e3cacb2ffdefe28c7cf490bf543e4dcb2770a (diff) |
Merge branch 'mailbox-for-linus' of git://git.linaro.org/landing-teams/working/fujitsu/integration
Pull mailbox framework from Jassi Brar:
"A framework for Mailbox controllers and clients have been cooking for
more than a year now.
Everybody in the CC list had been copied on patchset revisions and
most of them have made sounds of approval, though just one concrete
Reviewed-by. The patchset has also been in linux-next for a couple of
weeks now and no conflict has been reported. The framework has the
backing of at least 5 platforms, though I can't say if/when they
upstream their drivers (some businesses have 'changed')"
(Further acked-by by Arnd Bergmann and Suman Anna in the pull request
thread)
* 'mailbox-for-linus' of git://git.linaro.org/landing-teams/working/fujitsu/integration:
dt: mailbox: add generic bindings
doc: add documentation for mailbox framework
mailbox: Introduce framework for mailbox
mailbox: rename pl320-ipc specific mailbox.h
-rw-r--r-- | Documentation/devicetree/bindings/mailbox/mailbox.txt | 38 | ||||
-rw-r--r-- | Documentation/mailbox.txt | 122 | ||||
-rw-r--r-- | MAINTAINERS | 8 | ||||
-rw-r--r-- | arch/arm/mach-highbank/highbank.c | 2 | ||||
-rw-r--r-- | drivers/cpufreq/highbank-cpufreq.c | 2 | ||||
-rw-r--r-- | drivers/mailbox/Makefile | 4 | ||||
-rw-r--r-- | drivers/mailbox/mailbox.c | 465 | ||||
-rw-r--r-- | drivers/mailbox/pl320-ipc.c | 2 | ||||
-rw-r--r-- | include/linux/mailbox_client.h | 46 | ||||
-rw-r--r-- | include/linux/mailbox_controller.h | 133 | ||||
-rw-r--r-- | include/linux/pl320-ipc.h (renamed from include/linux/mailbox.h) | 0 |
11 files changed, 819 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/mailbox/mailbox.txt b/Documentation/devicetree/bindings/mailbox/mailbox.txt new file mode 100644 index 000000000000..1a2cd3d266db --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/mailbox.txt | |||
@@ -0,0 +1,38 @@ | |||
1 | * Generic Mailbox Controller and client driver bindings | ||
2 | |||
3 | Generic binding to provide a way for Mailbox controller drivers to | ||
4 | assign appropriate mailbox channel to client drivers. | ||
5 | |||
6 | * Mailbox Controller | ||
7 | |||
8 | Required property: | ||
9 | - #mbox-cells: Must be at least 1. Number of cells in a mailbox | ||
10 | specifier. | ||
11 | |||
12 | Example: | ||
13 | mailbox: mailbox { | ||
14 | ... | ||
15 | #mbox-cells = <1>; | ||
16 | }; | ||
17 | |||
18 | |||
19 | * Mailbox Client | ||
20 | |||
21 | Required property: | ||
22 | - mboxes: List of phandle and mailbox channel specifiers. | ||
23 | |||
24 | Optional property: | ||
25 | - mbox-names: List of identifier strings for each mailbox channel | ||
26 | required by the client. The use of this property | ||
27 | is discouraged in favor of using index in list of | ||
28 | 'mboxes' while requesting a mailbox. Instead the | ||
29 | platforms may define channel indices, in DT headers, | ||
30 | to something legible. | ||
31 | |||
32 | Example: | ||
33 | pwr_cntrl: power { | ||
34 | ... | ||
35 | mbox-names = "pwr-ctrl", "rpc"; | ||
36 | mboxes = <&mailbox 0 | ||
37 | &mailbox 1>; | ||
38 | }; | ||
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 | } | ||
diff --git a/MAINTAINERS b/MAINTAINERS index a20df9bf8ab0..b4b05dd4ffe3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -5834,6 +5834,14 @@ S: Maintained | |||
5834 | F: drivers/net/macvlan.c | 5834 | F: drivers/net/macvlan.c |
5835 | F: include/linux/if_macvlan.h | 5835 | F: include/linux/if_macvlan.h |
5836 | 5836 | ||
5837 | MAILBOX API | ||
5838 | M: Jassi Brar <jassisinghbrar@gmail.com> | ||
5839 | L: linux-kernel@vger.kernel.org | ||
5840 | S: Maintained | ||
5841 | F: drivers/mailbox/ | ||
5842 | F: include/linux/mailbox_client.h | ||
5843 | F: include/linux/mailbox_controller.h | ||
5844 | |||
5837 | MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7 | 5845 | MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7 |
5838 | M: Michael Kerrisk <mtk.manpages@gmail.com> | 5846 | M: Michael Kerrisk <mtk.manpages@gmail.com> |
5839 | W: http://www.kernel.org/doc/man-pages | 5847 | W: http://www.kernel.org/doc/man-pages |
diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c index 8c35ae4ff176..07a09570175d 100644 --- a/arch/arm/mach-highbank/highbank.c +++ b/arch/arm/mach-highbank/highbank.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/input.h> | 20 | #include <linux/input.h> |
21 | #include <linux/io.h> | 21 | #include <linux/io.h> |
22 | #include <linux/irqchip.h> | 22 | #include <linux/irqchip.h> |
23 | #include <linux/mailbox.h> | 23 | #include <linux/pl320-ipc.h> |
24 | #include <linux/of.h> | 24 | #include <linux/of.h> |
25 | #include <linux/of_irq.h> | 25 | #include <linux/of_irq.h> |
26 | #include <linux/of_platform.h> | 26 | #include <linux/of_platform.h> |
diff --git a/drivers/cpufreq/highbank-cpufreq.c b/drivers/cpufreq/highbank-cpufreq.c index ec399ad2f059..1608f7105c9f 100644 --- a/drivers/cpufreq/highbank-cpufreq.c +++ b/drivers/cpufreq/highbank-cpufreq.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include <linux/cpu.h> | 19 | #include <linux/cpu.h> |
20 | #include <linux/err.h> | 20 | #include <linux/err.h> |
21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
22 | #include <linux/mailbox.h> | 22 | #include <linux/pl320-ipc.h> |
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | 24 | ||
25 | #define HB_CPUFREQ_CHANGE_NOTE 0x80000001 | 25 | #define HB_CPUFREQ_CHANGE_NOTE 0x80000001 |
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 6d184dbcaca8..94ed7cefb14d 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile | |||
@@ -1,3 +1,7 @@ | |||
1 | # Generic MAILBOX API | ||
2 | |||
3 | obj-$(CONFIG_MAILBOX) += mailbox.o | ||
4 | |||
1 | obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o | 5 | obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o |
2 | 6 | ||
3 | obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o | 7 | obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o |
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c new file mode 100644 index 000000000000..afcb430508ec --- /dev/null +++ b/drivers/mailbox/mailbox.c | |||
@@ -0,0 +1,465 @@ | |||
1 | /* | ||
2 | * Mailbox: Common code for Mailbox controllers and users | ||
3 | * | ||
4 | * Copyright (C) 2013-2014 Linaro Ltd. | ||
5 | * Author: Jassi Brar <jassisinghbrar@gmail.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <linux/mutex.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/bitops.h> | ||
21 | #include <linux/mailbox_client.h> | ||
22 | #include <linux/mailbox_controller.h> | ||
23 | |||
24 | #define TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */ | ||
25 | #define TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */ | ||
26 | #define TXDONE_BY_ACK BIT(2) /* S/W ACK recevied by Client ticks the TX */ | ||
27 | |||
28 | static LIST_HEAD(mbox_cons); | ||
29 | static DEFINE_MUTEX(con_mutex); | ||
30 | |||
31 | static int add_to_rbuf(struct mbox_chan *chan, void *mssg) | ||
32 | { | ||
33 | int idx; | ||
34 | unsigned long flags; | ||
35 | |||
36 | spin_lock_irqsave(&chan->lock, flags); | ||
37 | |||
38 | /* See if there is any space left */ | ||
39 | if (chan->msg_count == MBOX_TX_QUEUE_LEN) { | ||
40 | spin_unlock_irqrestore(&chan->lock, flags); | ||
41 | return -ENOBUFS; | ||
42 | } | ||
43 | |||
44 | idx = chan->msg_free; | ||
45 | chan->msg_data[idx] = mssg; | ||
46 | chan->msg_count++; | ||
47 | |||
48 | if (idx == MBOX_TX_QUEUE_LEN - 1) | ||
49 | chan->msg_free = 0; | ||
50 | else | ||
51 | chan->msg_free++; | ||
52 | |||
53 | spin_unlock_irqrestore(&chan->lock, flags); | ||
54 | |||
55 | return idx; | ||
56 | } | ||
57 | |||
58 | static void msg_submit(struct mbox_chan *chan) | ||
59 | { | ||
60 | unsigned count, idx; | ||
61 | unsigned long flags; | ||
62 | void *data; | ||
63 | int err; | ||
64 | |||
65 | spin_lock_irqsave(&chan->lock, flags); | ||
66 | |||
67 | if (!chan->msg_count || chan->active_req) | ||
68 | goto exit; | ||
69 | |||
70 | count = chan->msg_count; | ||
71 | idx = chan->msg_free; | ||
72 | if (idx >= count) | ||
73 | idx -= count; | ||
74 | else | ||
75 | idx += MBOX_TX_QUEUE_LEN - count; | ||
76 | |||
77 | data = chan->msg_data[idx]; | ||
78 | |||
79 | /* Try to submit a message to the MBOX controller */ | ||
80 | err = chan->mbox->ops->send_data(chan, data); | ||
81 | if (!err) { | ||
82 | chan->active_req = data; | ||
83 | chan->msg_count--; | ||
84 | } | ||
85 | exit: | ||
86 | spin_unlock_irqrestore(&chan->lock, flags); | ||
87 | } | ||
88 | |||
89 | static void tx_tick(struct mbox_chan *chan, int r) | ||
90 | { | ||
91 | unsigned long flags; | ||
92 | void *mssg; | ||
93 | |||
94 | spin_lock_irqsave(&chan->lock, flags); | ||
95 | mssg = chan->active_req; | ||
96 | chan->active_req = NULL; | ||
97 | spin_unlock_irqrestore(&chan->lock, flags); | ||
98 | |||
99 | /* Submit next message */ | ||
100 | msg_submit(chan); | ||
101 | |||
102 | /* Notify the client */ | ||
103 | if (mssg && chan->cl->tx_done) | ||
104 | chan->cl->tx_done(chan->cl, mssg, r); | ||
105 | |||
106 | if (chan->cl->tx_block) | ||
107 | complete(&chan->tx_complete); | ||
108 | } | ||
109 | |||
110 | static void poll_txdone(unsigned long data) | ||
111 | { | ||
112 | struct mbox_controller *mbox = (struct mbox_controller *)data; | ||
113 | bool txdone, resched = false; | ||
114 | int i; | ||
115 | |||
116 | for (i = 0; i < mbox->num_chans; i++) { | ||
117 | struct mbox_chan *chan = &mbox->chans[i]; | ||
118 | |||
119 | if (chan->active_req && chan->cl) { | ||
120 | resched = true; | ||
121 | txdone = chan->mbox->ops->last_tx_done(chan); | ||
122 | if (txdone) | ||
123 | tx_tick(chan, 0); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | if (resched) | ||
128 | mod_timer(&mbox->poll, jiffies + | ||
129 | msecs_to_jiffies(mbox->txpoll_period)); | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * mbox_chan_received_data - A way for controller driver to push data | ||
134 | * received from remote to the upper layer. | ||
135 | * @chan: Pointer to the mailbox channel on which RX happened. | ||
136 | * @mssg: Client specific message typecasted as void * | ||
137 | * | ||
138 | * After startup and before shutdown any data received on the chan | ||
139 | * is passed on to the API via atomic mbox_chan_received_data(). | ||
140 | * The controller should ACK the RX only after this call returns. | ||
141 | */ | ||
142 | void mbox_chan_received_data(struct mbox_chan *chan, void *mssg) | ||
143 | { | ||
144 | /* No buffering the received data */ | ||
145 | if (chan->cl->rx_callback) | ||
146 | chan->cl->rx_callback(chan->cl, mssg); | ||
147 | } | ||
148 | EXPORT_SYMBOL_GPL(mbox_chan_received_data); | ||
149 | |||
150 | /** | ||
151 | * mbox_chan_txdone - A way for controller driver to notify the | ||
152 | * framework that the last TX has completed. | ||
153 | * @chan: Pointer to the mailbox chan on which TX happened. | ||
154 | * @r: Status of last TX - OK or ERROR | ||
155 | * | ||
156 | * The controller that has IRQ for TX ACK calls this atomic API | ||
157 | * to tick the TX state machine. It works only if txdone_irq | ||
158 | * is set by the controller. | ||
159 | */ | ||
160 | void mbox_chan_txdone(struct mbox_chan *chan, int r) | ||
161 | { | ||
162 | if (unlikely(!(chan->txdone_method & TXDONE_BY_IRQ))) { | ||
163 | dev_err(chan->mbox->dev, | ||
164 | "Controller can't run the TX ticker\n"); | ||
165 | return; | ||
166 | } | ||
167 | |||
168 | tx_tick(chan, r); | ||
169 | } | ||
170 | EXPORT_SYMBOL_GPL(mbox_chan_txdone); | ||
171 | |||
172 | /** | ||
173 | * mbox_client_txdone - The way for a client to run the TX state machine. | ||
174 | * @chan: Mailbox channel assigned to this client. | ||
175 | * @r: Success status of last transmission. | ||
176 | * | ||
177 | * The client/protocol had received some 'ACK' packet and it notifies | ||
178 | * the API that the last packet was sent successfully. This only works | ||
179 | * if the controller can't sense TX-Done. | ||
180 | */ | ||
181 | void mbox_client_txdone(struct mbox_chan *chan, int r) | ||
182 | { | ||
183 | if (unlikely(!(chan->txdone_method & TXDONE_BY_ACK))) { | ||
184 | dev_err(chan->mbox->dev, "Client can't run the TX ticker\n"); | ||
185 | return; | ||
186 | } | ||
187 | |||
188 | tx_tick(chan, r); | ||
189 | } | ||
190 | EXPORT_SYMBOL_GPL(mbox_client_txdone); | ||
191 | |||
192 | /** | ||
193 | * mbox_client_peek_data - A way for client driver to pull data | ||
194 | * received from remote by the controller. | ||
195 | * @chan: Mailbox channel assigned to this client. | ||
196 | * | ||
197 | * A poke to controller driver for any received data. | ||
198 | * The data is actually passed onto client via the | ||
199 | * mbox_chan_received_data() | ||
200 | * The call can be made from atomic context, so the controller's | ||
201 | * implementation of peek_data() must not sleep. | ||
202 | * | ||
203 | * Return: True, if controller has, and is going to push after this, | ||
204 | * some data. | ||
205 | * False, if controller doesn't have any data to be read. | ||
206 | */ | ||
207 | bool mbox_client_peek_data(struct mbox_chan *chan) | ||
208 | { | ||
209 | if (chan->mbox->ops->peek_data) | ||
210 | return chan->mbox->ops->peek_data(chan); | ||
211 | |||
212 | return false; | ||
213 | } | ||
214 | EXPORT_SYMBOL_GPL(mbox_client_peek_data); | ||
215 | |||
216 | /** | ||
217 | * mbox_send_message - For client to submit a message to be | ||
218 | * sent to the remote. | ||
219 | * @chan: Mailbox channel assigned to this client. | ||
220 | * @mssg: Client specific message typecasted. | ||
221 | * | ||
222 | * For client to submit data to the controller destined for a remote | ||
223 | * processor. If the client had set 'tx_block', the call will return | ||
224 | * either when the remote receives the data or when 'tx_tout' millisecs | ||
225 | * run out. | ||
226 | * In non-blocking mode, the requests are buffered by the API and a | ||
227 | * non-negative token is returned for each queued request. If the request | ||
228 | * is not queued, a negative token is returned. Upon failure or successful | ||
229 | * TX, the API calls 'tx_done' from atomic context, from which the client | ||
230 | * could submit yet another request. | ||
231 | * The pointer to message should be preserved until it is sent | ||
232 | * over the chan, i.e, tx_done() is made. | ||
233 | * This function could be called from atomic context as it simply | ||
234 | * queues the data and returns a token against the request. | ||
235 | * | ||
236 | * Return: Non-negative integer for successful submission (non-blocking mode) | ||
237 | * or transmission over chan (blocking mode). | ||
238 | * Negative value denotes failure. | ||
239 | */ | ||
240 | int mbox_send_message(struct mbox_chan *chan, void *mssg) | ||
241 | { | ||
242 | int t; | ||
243 | |||
244 | if (!chan || !chan->cl) | ||
245 | return -EINVAL; | ||
246 | |||
247 | t = add_to_rbuf(chan, mssg); | ||
248 | if (t < 0) { | ||
249 | dev_err(chan->mbox->dev, "Try increasing MBOX_TX_QUEUE_LEN\n"); | ||
250 | return t; | ||
251 | } | ||
252 | |||
253 | msg_submit(chan); | ||
254 | |||
255 | if (chan->txdone_method == TXDONE_BY_POLL) | ||
256 | poll_txdone((unsigned long)chan->mbox); | ||
257 | |||
258 | if (chan->cl->tx_block && chan->active_req) { | ||
259 | unsigned long wait; | ||
260 | int ret; | ||
261 | |||
262 | if (!chan->cl->tx_tout) /* wait forever */ | ||
263 | wait = msecs_to_jiffies(3600000); | ||
264 | else | ||
265 | wait = msecs_to_jiffies(chan->cl->tx_tout); | ||
266 | |||
267 | ret = wait_for_completion_timeout(&chan->tx_complete, wait); | ||
268 | if (ret == 0) { | ||
269 | t = -EIO; | ||
270 | tx_tick(chan, -EIO); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | return t; | ||
275 | } | ||
276 | EXPORT_SYMBOL_GPL(mbox_send_message); | ||
277 | |||
278 | /** | ||
279 | * mbox_request_channel - Request a mailbox channel. | ||
280 | * @cl: Identity of the client requesting the channel. | ||
281 | * @index: Index of mailbox specifier in 'mboxes' property. | ||
282 | * | ||
283 | * The Client specifies its requirements and capabilities while asking for | ||
284 | * a mailbox channel. It can't be called from atomic context. | ||
285 | * The channel is exclusively allocated and can't be used by another | ||
286 | * client before the owner calls mbox_free_channel. | ||
287 | * After assignment, any packet received on this channel will be | ||
288 | * handed over to the client via the 'rx_callback'. | ||
289 | * The framework holds reference to the client, so the mbox_client | ||
290 | * structure shouldn't be modified until the mbox_free_channel returns. | ||
291 | * | ||
292 | * Return: Pointer to the channel assigned to the client if successful. | ||
293 | * ERR_PTR for request failure. | ||
294 | */ | ||
295 | struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index) | ||
296 | { | ||
297 | struct device *dev = cl->dev; | ||
298 | struct mbox_controller *mbox; | ||
299 | struct of_phandle_args spec; | ||
300 | struct mbox_chan *chan; | ||
301 | unsigned long flags; | ||
302 | int ret; | ||
303 | |||
304 | if (!dev || !dev->of_node) { | ||
305 | pr_debug("%s: No owner device node\n", __func__); | ||
306 | return ERR_PTR(-ENODEV); | ||
307 | } | ||
308 | |||
309 | mutex_lock(&con_mutex); | ||
310 | |||
311 | if (of_parse_phandle_with_args(dev->of_node, "mboxes", | ||
312 | "#mbox-cells", index, &spec)) { | ||
313 | dev_dbg(dev, "%s: can't parse \"mboxes\" property\n", __func__); | ||
314 | mutex_unlock(&con_mutex); | ||
315 | return ERR_PTR(-ENODEV); | ||
316 | } | ||
317 | |||
318 | chan = NULL; | ||
319 | list_for_each_entry(mbox, &mbox_cons, node) | ||
320 | if (mbox->dev->of_node == spec.np) { | ||
321 | chan = mbox->of_xlate(mbox, &spec); | ||
322 | break; | ||
323 | } | ||
324 | |||
325 | of_node_put(spec.np); | ||
326 | |||
327 | if (!chan || chan->cl || !try_module_get(mbox->dev->driver->owner)) { | ||
328 | dev_dbg(dev, "%s: mailbox not free\n", __func__); | ||
329 | mutex_unlock(&con_mutex); | ||
330 | return ERR_PTR(-EBUSY); | ||
331 | } | ||
332 | |||
333 | spin_lock_irqsave(&chan->lock, flags); | ||
334 | chan->msg_free = 0; | ||
335 | chan->msg_count = 0; | ||
336 | chan->active_req = NULL; | ||
337 | chan->cl = cl; | ||
338 | init_completion(&chan->tx_complete); | ||
339 | |||
340 | if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone) | ||
341 | chan->txdone_method |= TXDONE_BY_ACK; | ||
342 | |||
343 | spin_unlock_irqrestore(&chan->lock, flags); | ||
344 | |||
345 | ret = chan->mbox->ops->startup(chan); | ||
346 | if (ret) { | ||
347 | dev_err(dev, "Unable to startup the chan (%d)\n", ret); | ||
348 | mbox_free_channel(chan); | ||
349 | chan = ERR_PTR(ret); | ||
350 | } | ||
351 | |||
352 | mutex_unlock(&con_mutex); | ||
353 | return chan; | ||
354 | } | ||
355 | EXPORT_SYMBOL_GPL(mbox_request_channel); | ||
356 | |||
357 | /** | ||
358 | * mbox_free_channel - The client relinquishes control of a mailbox | ||
359 | * channel by this call. | ||
360 | * @chan: The mailbox channel to be freed. | ||
361 | */ | ||
362 | void mbox_free_channel(struct mbox_chan *chan) | ||
363 | { | ||
364 | unsigned long flags; | ||
365 | |||
366 | if (!chan || !chan->cl) | ||
367 | return; | ||
368 | |||
369 | chan->mbox->ops->shutdown(chan); | ||
370 | |||
371 | /* The queued TX requests are simply aborted, no callbacks are made */ | ||
372 | spin_lock_irqsave(&chan->lock, flags); | ||
373 | chan->cl = NULL; | ||
374 | chan->active_req = NULL; | ||
375 | if (chan->txdone_method == (TXDONE_BY_POLL | TXDONE_BY_ACK)) | ||
376 | chan->txdone_method = TXDONE_BY_POLL; | ||
377 | |||
378 | module_put(chan->mbox->dev->driver->owner); | ||
379 | spin_unlock_irqrestore(&chan->lock, flags); | ||
380 | } | ||
381 | EXPORT_SYMBOL_GPL(mbox_free_channel); | ||
382 | |||
383 | static struct mbox_chan * | ||
384 | of_mbox_index_xlate(struct mbox_controller *mbox, | ||
385 | const struct of_phandle_args *sp) | ||
386 | { | ||
387 | int ind = sp->args[0]; | ||
388 | |||
389 | if (ind >= mbox->num_chans) | ||
390 | return NULL; | ||
391 | |||
392 | return &mbox->chans[ind]; | ||
393 | } | ||
394 | |||
395 | /** | ||
396 | * mbox_controller_register - Register the mailbox controller | ||
397 | * @mbox: Pointer to the mailbox controller. | ||
398 | * | ||
399 | * The controller driver registers its communication channels | ||
400 | */ | ||
401 | int mbox_controller_register(struct mbox_controller *mbox) | ||
402 | { | ||
403 | int i, txdone; | ||
404 | |||
405 | /* Sanity check */ | ||
406 | if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) | ||
407 | return -EINVAL; | ||
408 | |||
409 | if (mbox->txdone_irq) | ||
410 | txdone = TXDONE_BY_IRQ; | ||
411 | else if (mbox->txdone_poll) | ||
412 | txdone = TXDONE_BY_POLL; | ||
413 | else /* It has to be ACK then */ | ||
414 | txdone = TXDONE_BY_ACK; | ||
415 | |||
416 | if (txdone == TXDONE_BY_POLL) { | ||
417 | mbox->poll.function = &poll_txdone; | ||
418 | mbox->poll.data = (unsigned long)mbox; | ||
419 | init_timer(&mbox->poll); | ||
420 | } | ||
421 | |||
422 | for (i = 0; i < mbox->num_chans; i++) { | ||
423 | struct mbox_chan *chan = &mbox->chans[i]; | ||
424 | |||
425 | chan->cl = NULL; | ||
426 | chan->mbox = mbox; | ||
427 | chan->txdone_method = txdone; | ||
428 | spin_lock_init(&chan->lock); | ||
429 | } | ||
430 | |||
431 | if (!mbox->of_xlate) | ||
432 | mbox->of_xlate = of_mbox_index_xlate; | ||
433 | |||
434 | mutex_lock(&con_mutex); | ||
435 | list_add_tail(&mbox->node, &mbox_cons); | ||
436 | mutex_unlock(&con_mutex); | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | EXPORT_SYMBOL_GPL(mbox_controller_register); | ||
441 | |||
442 | /** | ||
443 | * mbox_controller_unregister - Unregister the mailbox controller | ||
444 | * @mbox: Pointer to the mailbox controller. | ||
445 | */ | ||
446 | void mbox_controller_unregister(struct mbox_controller *mbox) | ||
447 | { | ||
448 | int i; | ||
449 | |||
450 | if (!mbox) | ||
451 | return; | ||
452 | |||
453 | mutex_lock(&con_mutex); | ||
454 | |||
455 | list_del(&mbox->node); | ||
456 | |||
457 | for (i = 0; i < mbox->num_chans; i++) | ||
458 | mbox_free_channel(&mbox->chans[i]); | ||
459 | |||
460 | if (mbox->txdone_poll) | ||
461 | del_timer_sync(&mbox->poll); | ||
462 | |||
463 | mutex_unlock(&con_mutex); | ||
464 | } | ||
465 | EXPORT_SYMBOL_GPL(mbox_controller_unregister); | ||
diff --git a/drivers/mailbox/pl320-ipc.c b/drivers/mailbox/pl320-ipc.c index d873cbae2fbb..f3755e0aa935 100644 --- a/drivers/mailbox/pl320-ipc.c +++ b/drivers/mailbox/pl320-ipc.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include <linux/device.h> | 26 | #include <linux/device.h> |
27 | #include <linux/amba/bus.h> | 27 | #include <linux/amba/bus.h> |
28 | 28 | ||
29 | #include <linux/mailbox.h> | 29 | #include <linux/pl320-ipc.h> |
30 | 30 | ||
31 | #define IPCMxSOURCE(m) ((m) * 0x40) | 31 | #define IPCMxSOURCE(m) ((m) * 0x40) |
32 | #define IPCMxDSET(m) (((m) * 0x40) + 0x004) | 32 | #define IPCMxDSET(m) (((m) * 0x40) + 0x004) |
diff --git a/include/linux/mailbox_client.h b/include/linux/mailbox_client.h new file mode 100644 index 000000000000..307d9cab2026 --- /dev/null +++ b/include/linux/mailbox_client.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013-2014 Linaro Ltd. | ||
3 | * Author: Jassi Brar <jassisinghbrar@gmail.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #ifndef __MAILBOX_CLIENT_H | ||
11 | #define __MAILBOX_CLIENT_H | ||
12 | |||
13 | #include <linux/of.h> | ||
14 | #include <linux/device.h> | ||
15 | |||
16 | struct mbox_chan; | ||
17 | |||
18 | /** | ||
19 | * struct mbox_client - User of a mailbox | ||
20 | * @dev: The client device | ||
21 | * @tx_block: If the mbox_send_message should block until data is | ||
22 | * transmitted. | ||
23 | * @tx_tout: Max block period in ms before TX is assumed failure | ||
24 | * @knows_txdone: If the client could run the TX state machine. Usually | ||
25 | * if the client receives some ACK packet for transmission. | ||
26 | * Unused if the controller already has TX_Done/RTR IRQ. | ||
27 | * @rx_callback: Atomic callback to provide client the data received | ||
28 | * @tx_done: Atomic callback to tell client of data transmission | ||
29 | */ | ||
30 | struct mbox_client { | ||
31 | struct device *dev; | ||
32 | bool tx_block; | ||
33 | unsigned long tx_tout; | ||
34 | bool knows_txdone; | ||
35 | |||
36 | void (*rx_callback)(struct mbox_client *cl, void *mssg); | ||
37 | void (*tx_done)(struct mbox_client *cl, void *mssg, int r); | ||
38 | }; | ||
39 | |||
40 | struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index); | ||
41 | int mbox_send_message(struct mbox_chan *chan, void *mssg); | ||
42 | void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */ | ||
43 | bool mbox_client_peek_data(struct mbox_chan *chan); /* atomic */ | ||
44 | void mbox_free_channel(struct mbox_chan *chan); /* may sleep */ | ||
45 | |||
46 | #endif /* __MAILBOX_CLIENT_H */ | ||
diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h new file mode 100644 index 000000000000..d4cf96f07cfc --- /dev/null +++ b/include/linux/mailbox_controller.h | |||
@@ -0,0 +1,133 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | */ | ||
6 | |||
7 | #ifndef __MAILBOX_CONTROLLER_H | ||
8 | #define __MAILBOX_CONTROLLER_H | ||
9 | |||
10 | #include <linux/of.h> | ||
11 | #include <linux/types.h> | ||
12 | #include <linux/timer.h> | ||
13 | #include <linux/device.h> | ||
14 | #include <linux/completion.h> | ||
15 | |||
16 | struct mbox_chan; | ||
17 | |||
18 | /** | ||
19 | * struct mbox_chan_ops - methods to control mailbox channels | ||
20 | * @send_data: The API asks the MBOX controller driver, in atomic | ||
21 | * context try to transmit a message on the bus. Returns 0 if | ||
22 | * data is accepted for transmission, -EBUSY while rejecting | ||
23 | * if the remote hasn't yet read the last data sent. Actual | ||
24 | * transmission of data is reported by the controller via | ||
25 | * mbox_chan_txdone (if it has some TX ACK irq). It must not | ||
26 | * sleep. | ||
27 | * @startup: Called when a client requests the chan. The controller | ||
28 | * could ask clients for additional parameters of communication | ||
29 | * to be provided via client's chan_data. This call may | ||
30 | * block. After this call the Controller must forward any | ||
31 | * data received on the chan by calling mbox_chan_received_data. | ||
32 | * The controller may do stuff that need to sleep. | ||
33 | * @shutdown: Called when a client relinquishes control of a chan. | ||
34 | * This call may block too. The controller must not forward | ||
35 | * any received data anymore. | ||
36 | * The controller may do stuff that need to sleep. | ||
37 | * @last_tx_done: If the controller sets 'txdone_poll', the API calls | ||
38 | * this to poll status of last TX. The controller must | ||
39 | * give priority to IRQ method over polling and never | ||
40 | * set both txdone_poll and txdone_irq. Only in polling | ||
41 | * mode 'send_data' is expected to return -EBUSY. | ||
42 | * The controller may do stuff that need to sleep/block. | ||
43 | * Used only if txdone_poll:=true && txdone_irq:=false | ||
44 | * @peek_data: Atomic check for any received data. Return true if controller | ||
45 | * has some data to push to the client. False otherwise. | ||
46 | */ | ||
47 | struct mbox_chan_ops { | ||
48 | int (*send_data)(struct mbox_chan *chan, void *data); | ||
49 | int (*startup)(struct mbox_chan *chan); | ||
50 | void (*shutdown)(struct mbox_chan *chan); | ||
51 | bool (*last_tx_done)(struct mbox_chan *chan); | ||
52 | bool (*peek_data)(struct mbox_chan *chan); | ||
53 | }; | ||
54 | |||
55 | /** | ||
56 | * struct mbox_controller - Controller of a class of communication channels | ||
57 | * @dev: Device backing this controller | ||
58 | * @ops: Operators that work on each communication chan | ||
59 | * @chans: Array of channels | ||
60 | * @num_chans: Number of channels in the 'chans' array. | ||
61 | * @txdone_irq: Indicates if the controller can report to API when | ||
62 | * the last transmitted data was read by the remote. | ||
63 | * Eg, if it has some TX ACK irq. | ||
64 | * @txdone_poll: If the controller can read but not report the TX | ||
65 | * done. Ex, some register shows the TX status but | ||
66 | * no interrupt rises. Ignored if 'txdone_irq' is set. | ||
67 | * @txpoll_period: If 'txdone_poll' is in effect, the API polls for | ||
68 | * last TX's status after these many millisecs | ||
69 | * @of_xlate: Controller driver specific mapping of channel via DT | ||
70 | * @poll: API private. Used to poll for TXDONE on all channels. | ||
71 | * @node: API private. To hook into list of controllers. | ||
72 | */ | ||
73 | struct mbox_controller { | ||
74 | struct device *dev; | ||
75 | struct mbox_chan_ops *ops; | ||
76 | struct mbox_chan *chans; | ||
77 | int num_chans; | ||
78 | bool txdone_irq; | ||
79 | bool txdone_poll; | ||
80 | unsigned txpoll_period; | ||
81 | struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox, | ||
82 | const struct of_phandle_args *sp); | ||
83 | /* Internal to API */ | ||
84 | struct timer_list poll; | ||
85 | struct list_head node; | ||
86 | }; | ||
87 | |||
88 | /* | ||
89 | * The length of circular buffer for queuing messages from a client. | ||
90 | * 'msg_count' tracks the number of buffered messages while 'msg_free' | ||
91 | * is the index where the next message would be buffered. | ||
92 | * We shouldn't need it too big because every transfer is interrupt | ||
93 | * triggered and if we have lots of data to transfer, the interrupt | ||
94 | * latencies are going to be the bottleneck, not the buffer length. | ||
95 | * Besides, mbox_send_message could be called from atomic context and | ||
96 | * the client could also queue another message from the notifier 'tx_done' | ||
97 | * of the last transfer done. | ||
98 | * REVISIT: If too many platforms see the "Try increasing MBOX_TX_QUEUE_LEN" | ||
99 | * print, it needs to be taken from config option or somesuch. | ||
100 | */ | ||
101 | #define MBOX_TX_QUEUE_LEN 20 | ||
102 | |||
103 | /** | ||
104 | * struct mbox_chan - s/w representation of a communication chan | ||
105 | * @mbox: Pointer to the parent/provider of this channel | ||
106 | * @txdone_method: Way to detect TXDone chosen by the API | ||
107 | * @cl: Pointer to the current owner of this channel | ||
108 | * @tx_complete: Transmission completion | ||
109 | * @active_req: Currently active request hook | ||
110 | * @msg_count: No. of mssg currently queued | ||
111 | * @msg_free: Index of next available mssg slot | ||
112 | * @msg_data: Hook for data packet | ||
113 | * @lock: Serialise access to the channel | ||
114 | * @con_priv: Hook for controller driver to attach private data | ||
115 | */ | ||
116 | struct mbox_chan { | ||
117 | struct mbox_controller *mbox; | ||
118 | unsigned txdone_method; | ||
119 | struct mbox_client *cl; | ||
120 | struct completion tx_complete; | ||
121 | void *active_req; | ||
122 | unsigned msg_count, msg_free; | ||
123 | void *msg_data[MBOX_TX_QUEUE_LEN]; | ||
124 | spinlock_t lock; /* Serialise access to the channel */ | ||
125 | void *con_priv; | ||
126 | }; | ||
127 | |||
128 | int mbox_controller_register(struct mbox_controller *mbox); /* can sleep */ | ||
129 | void mbox_controller_unregister(struct mbox_controller *mbox); /* can sleep */ | ||
130 | void mbox_chan_received_data(struct mbox_chan *chan, void *data); /* atomic */ | ||
131 | void mbox_chan_txdone(struct mbox_chan *chan, int r); /* atomic */ | ||
132 | |||
133 | #endif /* __MAILBOX_CONTROLLER_H */ | ||
diff --git a/include/linux/mailbox.h b/include/linux/pl320-ipc.h index 5161f63ec1c8..5161f63ec1c8 100644 --- a/include/linux/mailbox.h +++ b/include/linux/pl320-ipc.h | |||