diff options
author | Ohad Ben-Cohen <ohad@wizery.com> | 2010-05-05 11:33:09 -0400 |
---|---|---|
committer | Hiroshi DOYU <Hiroshi.DOYU@nokia.com> | 2010-08-04 08:50:17 -0400 |
commit | b5bebe410204cf84337b54c372cceda2d6b27de6 (patch) | |
tree | ef64f9a9836c05d21c7e65d6d6429beb174956a6 /arch/arm/plat-omap | |
parent | 01072d8f4b9911047ef435a807cfd7223c94d94d (diff) |
omap: mailbox: convert block api to kfifo
The underlying buffering implementation of mailbox
is converted from block API to kfifo due to the simplicity
and speed of kfifo.
The default size of the kfifo buffer is set to 256 bytes.
This value is configurable at compile time (via
CONFIG_OMAP_MBOX_KFIFO_SIZE), and can be changed at
runtime (via the mbox_kfifo_size module parameter).
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com>
Signed-off-by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
Diffstat (limited to 'arch/arm/plat-omap')
-rw-r--r-- | arch/arm/plat-omap/Kconfig | 9 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/mailbox.h | 4 | ||||
-rw-r--r-- | arch/arm/plat-omap/mailbox.c | 119 |
3 files changed, 64 insertions, 68 deletions
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 78b49a626d06..111d39a47ad1 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig | |||
@@ -106,6 +106,15 @@ config OMAP_MBOX_FWK | |||
106 | Say Y here if you want to use OMAP Mailbox framework support for | 106 | Say Y here if you want to use OMAP Mailbox framework support for |
107 | DSP, IVA1.0 and IVA2 in OMAP1/2/3. | 107 | DSP, IVA1.0 and IVA2 in OMAP1/2/3. |
108 | 108 | ||
109 | config OMAP_MBOX_KFIFO_SIZE | ||
110 | int "Mailbox kfifo default buffer size (bytes)" | ||
111 | depends on OMAP_MBOX_FWK | ||
112 | default 256 | ||
113 | help | ||
114 | Specify the default size of mailbox's kfifo buffers (bytes). | ||
115 | This can also be changed at runtime (via the mbox_kfifo_size | ||
116 | module parameter). | ||
117 | |||
109 | config OMAP_IOMMU | 118 | config OMAP_IOMMU |
110 | tristate | 119 | tristate |
111 | 120 | ||
diff --git a/arch/arm/plat-omap/include/plat/mailbox.h b/arch/arm/plat-omap/include/plat/mailbox.h index 729166b76a7c..0c3c4a5f4b42 100644 --- a/arch/arm/plat-omap/include/plat/mailbox.h +++ b/arch/arm/plat-omap/include/plat/mailbox.h | |||
@@ -5,8 +5,8 @@ | |||
5 | 5 | ||
6 | #include <linux/wait.h> | 6 | #include <linux/wait.h> |
7 | #include <linux/workqueue.h> | 7 | #include <linux/workqueue.h> |
8 | #include <linux/blkdev.h> | ||
9 | #include <linux/interrupt.h> | 8 | #include <linux/interrupt.h> |
9 | #include <linux/kfifo.h> | ||
10 | 10 | ||
11 | typedef u32 mbox_msg_t; | 11 | typedef u32 mbox_msg_t; |
12 | struct omap_mbox; | 12 | struct omap_mbox; |
@@ -42,7 +42,7 @@ struct omap_mbox_ops { | |||
42 | 42 | ||
43 | struct omap_mbox_queue { | 43 | struct omap_mbox_queue { |
44 | spinlock_t lock; | 44 | spinlock_t lock; |
45 | struct request_queue *queue; | 45 | struct kfifo fifo; |
46 | struct work_struct work; | 46 | struct work_struct work; |
47 | struct tasklet_struct tasklet; | 47 | struct tasklet_struct tasklet; |
48 | int (*callback)(void *); | 48 | int (*callback)(void *); |
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); |