diff options
| -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); |
