aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/mailbox.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-omap/mailbox.c')
-rw-r--r--arch/arm/plat-omap/mailbox.c119
1 files changed, 53 insertions, 66 deletions
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
index 81076b54d37b..ec0e1596b4f3 100644
--- a/arch/arm/plat-omap/mailbox.c
+++ b/arch/arm/plat-omap/mailbox.c
@@ -21,11 +21,14 @@
21 * 21 *
22 */ 22 */
23 23
24#include <linux/kernel.h>
24#include <linux/module.h> 25#include <linux/module.h>
25#include <linux/interrupt.h> 26#include <linux/interrupt.h>
26#include <linux/device.h> 27#include <linux/device.h>
27#include <linux/delay.h> 28#include <linux/delay.h>
28#include <linux/slab.h> 29#include <linux/slab.h>
30#include <linux/kfifo.h>
31#include <linux/err.h>
29 32
30#include <plat/mailbox.h> 33#include <plat/mailbox.h>
31 34
@@ -37,6 +40,10 @@ static bool rq_full;
37static int mbox_configured; 40static int mbox_configured;
38static DEFINE_MUTEX(mbox_configured_lock); 41static DEFINE_MUTEX(mbox_configured_lock);
39 42
43static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE;
44module_param(mbox_kfifo_size, uint, S_IRUGO);
45MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)");
46
40/* Mailbox FIFO handle functions */ 47/* Mailbox FIFO handle functions */
41static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) 48static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
42{ 49{
@@ -69,7 +76,7 @@ static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
69/* 76/*
70 * message sender 77 * message sender
71 */ 78 */
72static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) 79static int __mbox_poll_for_space(struct omap_mbox *mbox)
73{ 80{
74 int ret = 0, i = 1000; 81 int ret = 0, i = 1000;
75 82
@@ -80,49 +87,50 @@ static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
80 return -1; 87 return -1;
81 udelay(1); 88 udelay(1);
82 } 89 }
83 mbox_fifo_write(mbox, msg);
84 return ret; 90 return ret;
85} 91}
86 92
87
88int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) 93int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
89{ 94{
95 struct omap_mbox_queue *mq = mbox->txq;
96 int ret = 0, len;
90 97
91 struct request *rq; 98 spin_lock(&mq->lock);
92 struct request_queue *q = mbox->txq->queue;
93 99
94 rq = blk_get_request(q, WRITE, GFP_ATOMIC); 100 if (kfifo_avail(&mq->fifo) < sizeof(msg)) {
95 if (unlikely(!rq)) 101 ret = -ENOMEM;
96 return -ENOMEM; 102 goto out;
103 }
104
105 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
106 WARN_ON(len != sizeof(msg));
97 107
98 blk_insert_request(q, rq, 0, (void *) msg);
99 tasklet_schedule(&mbox->txq->tasklet); 108 tasklet_schedule(&mbox->txq->tasklet);
100 109
101 return 0; 110out:
111 spin_unlock(&mq->lock);
112 return ret;
102} 113}
103EXPORT_SYMBOL(omap_mbox_msg_send); 114EXPORT_SYMBOL(omap_mbox_msg_send);
104 115
105static void mbox_tx_tasklet(unsigned long tx_data) 116static void mbox_tx_tasklet(unsigned long tx_data)
106{ 117{
107 int ret;
108 struct request *rq;
109 struct omap_mbox *mbox = (struct omap_mbox *)tx_data; 118 struct omap_mbox *mbox = (struct omap_mbox *)tx_data;
110 struct request_queue *q = mbox->txq->queue; 119 struct omap_mbox_queue *mq = mbox->txq;
111 120 mbox_msg_t msg;
112 while (1) { 121 int ret;
113
114 rq = blk_fetch_request(q);
115
116 if (!rq)
117 break;
118 122
119 ret = __mbox_msg_send(mbox, (mbox_msg_t)rq->special); 123 while (kfifo_len(&mq->fifo)) {
120 if (ret) { 124 if (__mbox_poll_for_space(mbox)) {
121 omap_mbox_enable_irq(mbox, IRQ_TX); 125 omap_mbox_enable_irq(mbox, IRQ_TX);
122 blk_requeue_request(q, rq); 126 break;
123 return;
124 } 127 }
125 blk_end_request_all(rq, 0); 128
129 ret = kfifo_out(&mq->fifo, (unsigned char *)&msg,
130 sizeof(msg));
131 WARN_ON(ret != sizeof(msg));
132
133 mbox_fifo_write(mbox, msg);
126 } 134 }
127} 135}
128 136
@@ -133,41 +141,21 @@ static void mbox_rx_work(struct work_struct *work)
133{ 141{
134 struct omap_mbox_queue *mq = 142 struct omap_mbox_queue *mq =
135 container_of(work, struct omap_mbox_queue, work); 143 container_of(work, struct omap_mbox_queue, work);
136 struct omap_mbox *mbox = mq->queue->queuedata;
137 struct request_queue *q = mbox->rxq->queue;
138 struct request *rq;
139 mbox_msg_t msg; 144 mbox_msg_t msg;
140 unsigned long flags; 145 int len;
141 146
142 while (1) { 147 while (kfifo_len(&mq->fifo) >= sizeof(msg)) {
143 spin_lock_irqsave(q->queue_lock, flags); 148 len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
144 rq = blk_fetch_request(q); 149 WARN_ON(len != sizeof(msg));
145 if (rq_full) {
146 omap_mbox_enable_irq(mbox, IRQ_RX);
147 rq_full = false;
148 }
149 spin_unlock_irqrestore(q->queue_lock, flags);
150 if (!rq)
151 break;
152 150
153 msg = (mbox_msg_t)rq->special; 151 if (mq->callback)
154 blk_end_request_all(rq, 0); 152 mq->callback((void *)msg);
155 if (mbox->rxq->callback)
156 mbox->rxq->callback((void *)msg);
157 } 153 }
158} 154}
159 155
160/* 156/*
161 * Mailbox interrupt handler 157 * Mailbox interrupt handler
162 */ 158 */
163static void mbox_txq_fn(struct request_queue *q)
164{
165}
166
167static void mbox_rxq_fn(struct request_queue *q)
168{
169}
170
171static void __mbox_tx_interrupt(struct omap_mbox *mbox) 159static void __mbox_tx_interrupt(struct omap_mbox *mbox)
172{ 160{
173 omap_mbox_disable_irq(mbox, IRQ_TX); 161 omap_mbox_disable_irq(mbox, IRQ_TX);
@@ -177,13 +165,12 @@ static void __mbox_tx_interrupt(struct omap_mbox *mbox)
177 165
178static void __mbox_rx_interrupt(struct omap_mbox *mbox) 166static void __mbox_rx_interrupt(struct omap_mbox *mbox)
179{ 167{
180 struct request *rq; 168 struct omap_mbox_queue *mq = mbox->rxq;
181 mbox_msg_t msg; 169 mbox_msg_t msg;
182 struct request_queue *q = mbox->rxq->queue; 170 int len;
183 171
184 while (!mbox_fifo_empty(mbox)) { 172 while (!mbox_fifo_empty(mbox)) {
185 rq = blk_get_request(q, WRITE, GFP_ATOMIC); 173 if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) {
186 if (unlikely(!rq)) {
187 omap_mbox_disable_irq(mbox, IRQ_RX); 174 omap_mbox_disable_irq(mbox, IRQ_RX);
188 rq_full = true; 175 rq_full = true;
189 goto nomem; 176 goto nomem;
@@ -191,8 +178,9 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
191 178
192 msg = mbox_fifo_read(mbox); 179 msg = mbox_fifo_read(mbox);
193 180
181 len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
182 WARN_ON(len != sizeof(msg));
194 183
195 blk_insert_request(q, rq, 0, (void *)msg);
196 if (mbox->ops->type == OMAP_MBOX_TYPE1) 184 if (mbox->ops->type == OMAP_MBOX_TYPE1)
197 break; 185 break;
198 } 186 }
@@ -217,11 +205,9 @@ static irqreturn_t mbox_interrupt(int irq, void *p)
217} 205}
218 206
219static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, 207static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
220 request_fn_proc *proc,
221 void (*work) (struct work_struct *), 208 void (*work) (struct work_struct *),
222 void (*tasklet)(unsigned long)) 209 void (*tasklet)(unsigned long))
223{ 210{
224 struct request_queue *q;
225 struct omap_mbox_queue *mq; 211 struct omap_mbox_queue *mq;
226 212
227 mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL); 213 mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
@@ -230,11 +216,8 @@ static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
230 216
231 spin_lock_init(&mq->lock); 217 spin_lock_init(&mq->lock);
232 218
233 q = blk_init_queue(proc, &mq->lock); 219 if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL))
234 if (!q)
235 goto error; 220 goto error;
236 q->queuedata = mbox;
237 mq->queue = q;
238 221
239 if (work) 222 if (work)
240 INIT_WORK(&mq->work, work); 223 INIT_WORK(&mq->work, work);
@@ -249,7 +232,7 @@ error:
249 232
250static void mbox_queue_free(struct omap_mbox_queue *q) 233static void mbox_queue_free(struct omap_mbox_queue *q)
251{ 234{
252 blk_cleanup_queue(q->queue); 235 kfifo_free(&q->fifo);
253 kfree(q); 236 kfree(q);
254} 237}
255 238
@@ -279,14 +262,14 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
279 goto fail_request_irq; 262 goto fail_request_irq;
280 } 263 }
281 264
282 mq = mbox_queue_alloc(mbox, mbox_txq_fn, NULL, mbox_tx_tasklet); 265 mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
283 if (!mq) { 266 if (!mq) {
284 ret = -ENOMEM; 267 ret = -ENOMEM;
285 goto fail_alloc_txq; 268 goto fail_alloc_txq;
286 } 269 }
287 mbox->txq = mq; 270 mbox->txq = mq;
288 271
289 mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work, NULL); 272 mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
290 if (!mq) { 273 if (!mq) {
291 ret = -ENOMEM; 274 ret = -ENOMEM;
292 goto fail_alloc_rxq; 275 goto fail_alloc_rxq;
@@ -418,6 +401,10 @@ static int __init omap_mbox_init(void)
418 if (!mboxd) 401 if (!mboxd)
419 return -ENOMEM; 402 return -ENOMEM;
420 403
404 /* kfifo size sanity check: alignment and minimal size */
405 mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t));
406 mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, sizeof(mbox_msg_t));
407
421 return 0; 408 return 0;
422} 409}
423module_init(omap_mbox_init); 410module_init(omap_mbox_init);