diff options
Diffstat (limited to 'arch/arm/plat-omap/mailbox.c')
-rw-r--r-- | arch/arm/plat-omap/mailbox.c | 119 |
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; | |||
37 | static int mbox_configured; | 40 | static int mbox_configured; |
38 | static DEFINE_MUTEX(mbox_configured_lock); | 41 | static DEFINE_MUTEX(mbox_configured_lock); |
39 | 42 | ||
43 | static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE; | ||
44 | module_param(mbox_kfifo_size, uint, S_IRUGO); | ||
45 | MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)"); | ||
46 | |||
40 | /* Mailbox FIFO handle functions */ | 47 | /* Mailbox FIFO handle functions */ |
41 | static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) | 48 | static 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 | */ |
72 | static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) | 79 | static 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 | |||
88 | int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) | 93 | int 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; | 110 | out: |
111 | spin_unlock(&mq->lock); | ||
112 | return ret; | ||
102 | } | 113 | } |
103 | EXPORT_SYMBOL(omap_mbox_msg_send); | 114 | EXPORT_SYMBOL(omap_mbox_msg_send); |
104 | 115 | ||
105 | static void mbox_tx_tasklet(unsigned long tx_data) | 116 | static 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 | */ |
163 | static void mbox_txq_fn(struct request_queue *q) | ||
164 | { | ||
165 | } | ||
166 | |||
167 | static void mbox_rxq_fn(struct request_queue *q) | ||
168 | { | ||
169 | } | ||
170 | |||
171 | static void __mbox_tx_interrupt(struct omap_mbox *mbox) | 159 | static 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 | ||
178 | static void __mbox_rx_interrupt(struct omap_mbox *mbox) | 166 | static 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 | ||
219 | static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, | 207 | static 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 | ||
250 | static void mbox_queue_free(struct omap_mbox_queue *q) | 233 | static 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 | } |
423 | module_init(omap_mbox_init); | 410 | module_init(omap_mbox_init); |