diff options
Diffstat (limited to 'arch/arm/plat-omap/mailbox.c')
| -rw-r--r-- | arch/arm/plat-omap/mailbox.c | 248 |
1 files changed, 118 insertions, 130 deletions
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index 08a2df766289..d2fafb892f7f 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c | |||
| @@ -21,19 +21,26 @@ | |||
| 21 | * | 21 | * |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
| 26 | #include <linux/device.h> | 25 | #include <linux/spinlock.h> |
| 26 | #include <linux/mutex.h> | ||
| 27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
| 28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
| 29 | #include <linux/kfifo.h> | ||
| 30 | #include <linux/err.h> | ||
| 29 | 31 | ||
| 30 | #include <plat/mailbox.h> | 32 | #include <plat/mailbox.h> |
| 31 | 33 | ||
| 32 | static struct workqueue_struct *mboxd; | 34 | static struct workqueue_struct *mboxd; |
| 33 | static struct omap_mbox *mboxes; | 35 | static struct omap_mbox **mboxes; |
| 34 | static DEFINE_RWLOCK(mboxes_lock); | 36 | static bool rq_full; |
| 35 | 37 | ||
| 36 | static int mbox_configured; | 38 | static int mbox_configured; |
| 39 | static DEFINE_MUTEX(mbox_configured_lock); | ||
| 40 | |||
| 41 | static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE; | ||
| 42 | module_param(mbox_kfifo_size, uint, S_IRUGO); | ||
| 43 | MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)"); | ||
| 37 | 44 | ||
| 38 | /* Mailbox FIFO handle functions */ | 45 | /* Mailbox FIFO handle functions */ |
| 39 | static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) | 46 | static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) |
| @@ -67,7 +74,7 @@ static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | |||
| 67 | /* | 74 | /* |
| 68 | * message sender | 75 | * message sender |
| 69 | */ | 76 | */ |
| 70 | static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) | 77 | static int __mbox_poll_for_space(struct omap_mbox *mbox) |
| 71 | { | 78 | { |
| 72 | int ret = 0, i = 1000; | 79 | int ret = 0, i = 1000; |
| 73 | 80 | ||
| @@ -78,49 +85,50 @@ static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) | |||
| 78 | return -1; | 85 | return -1; |
| 79 | udelay(1); | 86 | udelay(1); |
| 80 | } | 87 | } |
| 81 | mbox_fifo_write(mbox, msg); | ||
| 82 | return ret; | 88 | return ret; |
| 83 | } | 89 | } |
| 84 | 90 | ||
| 85 | |||
| 86 | int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) | 91 | int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) |
| 87 | { | 92 | { |
| 93 | struct omap_mbox_queue *mq = mbox->txq; | ||
| 94 | int ret = 0, len; | ||
| 88 | 95 | ||
| 89 | struct request *rq; | 96 | spin_lock(&mq->lock); |
| 90 | struct request_queue *q = mbox->txq->queue; | ||
| 91 | 97 | ||
| 92 | rq = blk_get_request(q, WRITE, GFP_ATOMIC); | 98 | if (kfifo_avail(&mq->fifo) < sizeof(msg)) { |
| 93 | if (unlikely(!rq)) | 99 | ret = -ENOMEM; |
| 94 | return -ENOMEM; | 100 | goto out; |
| 101 | } | ||
| 102 | |||
| 103 | len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); | ||
| 104 | WARN_ON(len != sizeof(msg)); | ||
| 95 | 105 | ||
| 96 | blk_insert_request(q, rq, 0, (void *) msg); | ||
| 97 | tasklet_schedule(&mbox->txq->tasklet); | 106 | tasklet_schedule(&mbox->txq->tasklet); |
| 98 | 107 | ||
| 99 | return 0; | 108 | out: |
| 109 | spin_unlock(&mq->lock); | ||
| 110 | return ret; | ||
| 100 | } | 111 | } |
| 101 | EXPORT_SYMBOL(omap_mbox_msg_send); | 112 | EXPORT_SYMBOL(omap_mbox_msg_send); |
| 102 | 113 | ||
| 103 | static void mbox_tx_tasklet(unsigned long tx_data) | 114 | static void mbox_tx_tasklet(unsigned long tx_data) |
| 104 | { | 115 | { |
| 105 | int ret; | ||
| 106 | struct request *rq; | ||
| 107 | struct omap_mbox *mbox = (struct omap_mbox *)tx_data; | 116 | struct omap_mbox *mbox = (struct omap_mbox *)tx_data; |
| 108 | struct request_queue *q = mbox->txq->queue; | 117 | struct omap_mbox_queue *mq = mbox->txq; |
| 109 | 118 | mbox_msg_t msg; | |
| 110 | while (1) { | 119 | int ret; |
| 111 | |||
| 112 | rq = blk_fetch_request(q); | ||
| 113 | |||
| 114 | if (!rq) | ||
| 115 | break; | ||
| 116 | 120 | ||
| 117 | ret = __mbox_msg_send(mbox, (mbox_msg_t)rq->special); | 121 | while (kfifo_len(&mq->fifo)) { |
| 118 | if (ret) { | 122 | if (__mbox_poll_for_space(mbox)) { |
| 119 | omap_mbox_enable_irq(mbox, IRQ_TX); | 123 | omap_mbox_enable_irq(mbox, IRQ_TX); |
| 120 | blk_requeue_request(q, rq); | 124 | break; |
| 121 | return; | ||
| 122 | } | 125 | } |
| 123 | blk_end_request_all(rq, 0); | 126 | |
| 127 | ret = kfifo_out(&mq->fifo, (unsigned char *)&msg, | ||
| 128 | sizeof(msg)); | ||
| 129 | WARN_ON(ret != sizeof(msg)); | ||
| 130 | |||
| 131 | mbox_fifo_write(mbox, msg); | ||
| 124 | } | 132 | } |
| 125 | } | 133 | } |
| 126 | 134 | ||
| @@ -131,36 +139,21 @@ static void mbox_rx_work(struct work_struct *work) | |||
| 131 | { | 139 | { |
| 132 | struct omap_mbox_queue *mq = | 140 | struct omap_mbox_queue *mq = |
| 133 | container_of(work, struct omap_mbox_queue, work); | 141 | container_of(work, struct omap_mbox_queue, work); |
| 134 | struct omap_mbox *mbox = mq->queue->queuedata; | ||
| 135 | struct request_queue *q = mbox->rxq->queue; | ||
| 136 | struct request *rq; | ||
| 137 | mbox_msg_t msg; | 142 | mbox_msg_t msg; |
| 138 | unsigned long flags; | 143 | int len; |
| 139 | 144 | ||
| 140 | while (1) { | 145 | while (kfifo_len(&mq->fifo) >= sizeof(msg)) { |
| 141 | spin_lock_irqsave(q->queue_lock, flags); | 146 | len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); |
| 142 | rq = blk_fetch_request(q); | 147 | WARN_ON(len != sizeof(msg)); |
| 143 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
| 144 | if (!rq) | ||
| 145 | break; | ||
| 146 | 148 | ||
| 147 | msg = (mbox_msg_t)rq->special; | 149 | if (mq->callback) |
| 148 | blk_end_request_all(rq, 0); | 150 | mq->callback((void *)msg); |
| 149 | mbox->rxq->callback((void *)msg); | ||
| 150 | } | 151 | } |
| 151 | } | 152 | } |
| 152 | 153 | ||
| 153 | /* | 154 | /* |
| 154 | * Mailbox interrupt handler | 155 | * Mailbox interrupt handler |
| 155 | */ | 156 | */ |
| 156 | static void mbox_txq_fn(struct request_queue *q) | ||
| 157 | { | ||
| 158 | } | ||
| 159 | |||
| 160 | static void mbox_rxq_fn(struct request_queue *q) | ||
| 161 | { | ||
| 162 | } | ||
| 163 | |||
| 164 | static void __mbox_tx_interrupt(struct omap_mbox *mbox) | 157 | static void __mbox_tx_interrupt(struct omap_mbox *mbox) |
| 165 | { | 158 | { |
| 166 | omap_mbox_disable_irq(mbox, IRQ_TX); | 159 | omap_mbox_disable_irq(mbox, IRQ_TX); |
| @@ -170,19 +163,22 @@ static void __mbox_tx_interrupt(struct omap_mbox *mbox) | |||
| 170 | 163 | ||
| 171 | static void __mbox_rx_interrupt(struct omap_mbox *mbox) | 164 | static void __mbox_rx_interrupt(struct omap_mbox *mbox) |
| 172 | { | 165 | { |
| 173 | struct request *rq; | 166 | struct omap_mbox_queue *mq = mbox->rxq; |
| 174 | mbox_msg_t msg; | 167 | mbox_msg_t msg; |
| 175 | struct request_queue *q = mbox->rxq->queue; | 168 | int len; |
| 176 | 169 | ||
| 177 | while (!mbox_fifo_empty(mbox)) { | 170 | while (!mbox_fifo_empty(mbox)) { |
| 178 | rq = blk_get_request(q, WRITE, GFP_ATOMIC); | 171 | if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { |
| 179 | if (unlikely(!rq)) | 172 | omap_mbox_disable_irq(mbox, IRQ_RX); |
| 173 | rq_full = true; | ||
| 180 | goto nomem; | 174 | goto nomem; |
| 175 | } | ||
| 181 | 176 | ||
| 182 | msg = mbox_fifo_read(mbox); | 177 | msg = mbox_fifo_read(mbox); |
| 183 | 178 | ||
| 179 | len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); | ||
| 180 | WARN_ON(len != sizeof(msg)); | ||
| 184 | 181 | ||
| 185 | blk_insert_request(q, rq, 0, (void *)msg); | ||
| 186 | if (mbox->ops->type == OMAP_MBOX_TYPE1) | 182 | if (mbox->ops->type == OMAP_MBOX_TYPE1) |
| 187 | break; | 183 | break; |
| 188 | } | 184 | } |
| @@ -207,11 +203,9 @@ static irqreturn_t mbox_interrupt(int irq, void *p) | |||
| 207 | } | 203 | } |
| 208 | 204 | ||
| 209 | static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, | 205 | static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, |
| 210 | request_fn_proc *proc, | ||
| 211 | void (*work) (struct work_struct *), | 206 | void (*work) (struct work_struct *), |
| 212 | void (*tasklet)(unsigned long)) | 207 | void (*tasklet)(unsigned long)) |
| 213 | { | 208 | { |
| 214 | struct request_queue *q; | ||
| 215 | struct omap_mbox_queue *mq; | 209 | struct omap_mbox_queue *mq; |
| 216 | 210 | ||
| 217 | mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL); | 211 | mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL); |
| @@ -220,11 +214,8 @@ static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, | |||
| 220 | 214 | ||
| 221 | spin_lock_init(&mq->lock); | 215 | spin_lock_init(&mq->lock); |
| 222 | 216 | ||
| 223 | q = blk_init_queue(proc, &mq->lock); | 217 | if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL)) |
| 224 | if (!q) | ||
| 225 | goto error; | 218 | goto error; |
| 226 | q->queuedata = mbox; | ||
| 227 | mq->queue = q; | ||
| 228 | 219 | ||
| 229 | if (work) | 220 | if (work) |
| 230 | INIT_WORK(&mq->work, work); | 221 | INIT_WORK(&mq->work, work); |
| @@ -239,7 +230,7 @@ error: | |||
| 239 | 230 | ||
| 240 | static void mbox_queue_free(struct omap_mbox_queue *q) | 231 | static void mbox_queue_free(struct omap_mbox_queue *q) |
| 241 | { | 232 | { |
| 242 | blk_cleanup_queue(q->queue); | 233 | kfifo_free(&q->fifo); |
| 243 | kfree(q); | 234 | kfree(q); |
| 244 | } | 235 | } |
| 245 | 236 | ||
| @@ -248,35 +239,35 @@ static int omap_mbox_startup(struct omap_mbox *mbox) | |||
| 248 | int ret = 0; | 239 | int ret = 0; |
| 249 | struct omap_mbox_queue *mq; | 240 | struct omap_mbox_queue *mq; |
| 250 | 241 | ||
| 251 | if (likely(mbox->ops->startup)) { | 242 | if (mbox->ops->startup) { |
| 252 | write_lock(&mboxes_lock); | 243 | mutex_lock(&mbox_configured_lock); |
| 253 | if (!mbox_configured) | 244 | if (!mbox_configured) |
| 254 | ret = mbox->ops->startup(mbox); | 245 | ret = mbox->ops->startup(mbox); |
| 255 | 246 | ||
| 256 | if (unlikely(ret)) { | 247 | if (ret) { |
| 257 | write_unlock(&mboxes_lock); | 248 | mutex_unlock(&mbox_configured_lock); |
| 258 | return ret; | 249 | return ret; |
| 259 | } | 250 | } |
| 260 | mbox_configured++; | 251 | mbox_configured++; |
| 261 | write_unlock(&mboxes_lock); | 252 | mutex_unlock(&mbox_configured_lock); |
| 262 | } | 253 | } |
| 263 | 254 | ||
| 264 | ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, | 255 | ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, |
| 265 | mbox->name, mbox); | 256 | mbox->name, mbox); |
| 266 | if (unlikely(ret)) { | 257 | if (ret) { |
| 267 | printk(KERN_ERR | 258 | printk(KERN_ERR |
| 268 | "failed to register mailbox interrupt:%d\n", ret); | 259 | "failed to register mailbox interrupt:%d\n", ret); |
| 269 | goto fail_request_irq; | 260 | goto fail_request_irq; |
| 270 | } | 261 | } |
| 271 | 262 | ||
| 272 | mq = mbox_queue_alloc(mbox, mbox_txq_fn, NULL, mbox_tx_tasklet); | 263 | mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet); |
| 273 | if (!mq) { | 264 | if (!mq) { |
| 274 | ret = -ENOMEM; | 265 | ret = -ENOMEM; |
| 275 | goto fail_alloc_txq; | 266 | goto fail_alloc_txq; |
| 276 | } | 267 | } |
| 277 | mbox->txq = mq; | 268 | mbox->txq = mq; |
| 278 | 269 | ||
| 279 | mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work, NULL); | 270 | mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL); |
| 280 | if (!mq) { | 271 | if (!mq) { |
| 281 | ret = -ENOMEM; | 272 | ret = -ENOMEM; |
| 282 | goto fail_alloc_rxq; | 273 | goto fail_alloc_rxq; |
| @@ -290,7 +281,7 @@ static int omap_mbox_startup(struct omap_mbox *mbox) | |||
| 290 | fail_alloc_txq: | 281 | fail_alloc_txq: |
| 291 | free_irq(mbox->irq, mbox); | 282 | free_irq(mbox->irq, mbox); |
| 292 | fail_request_irq: | 283 | fail_request_irq: |
| 293 | if (unlikely(mbox->ops->shutdown)) | 284 | if (mbox->ops->shutdown) |
| 294 | mbox->ops->shutdown(mbox); | 285 | mbox->ops->shutdown(mbox); |
| 295 | 286 | ||
| 296 | return ret; | 287 | return ret; |
| @@ -298,31 +289,20 @@ static int omap_mbox_startup(struct omap_mbox *mbox) | |||
| 298 | 289 | ||
| 299 | static void omap_mbox_fini(struct omap_mbox *mbox) | 290 | static void omap_mbox_fini(struct omap_mbox *mbox) |
| 300 | { | 291 | { |
| 292 | free_irq(mbox->irq, mbox); | ||
| 293 | tasklet_kill(&mbox->txq->tasklet); | ||
| 294 | flush_work(&mbox->rxq->work); | ||
| 301 | mbox_queue_free(mbox->txq); | 295 | mbox_queue_free(mbox->txq); |
| 302 | mbox_queue_free(mbox->rxq); | 296 | mbox_queue_free(mbox->rxq); |
| 303 | 297 | ||
| 304 | free_irq(mbox->irq, mbox); | 298 | if (mbox->ops->shutdown) { |
| 305 | 299 | mutex_lock(&mbox_configured_lock); | |
| 306 | if (unlikely(mbox->ops->shutdown)) { | ||
| 307 | write_lock(&mboxes_lock); | ||
| 308 | if (mbox_configured > 0) | 300 | if (mbox_configured > 0) |
| 309 | mbox_configured--; | 301 | mbox_configured--; |
| 310 | if (!mbox_configured) | 302 | if (!mbox_configured) |
| 311 | mbox->ops->shutdown(mbox); | 303 | mbox->ops->shutdown(mbox); |
| 312 | write_unlock(&mboxes_lock); | 304 | mutex_unlock(&mbox_configured_lock); |
| 313 | } | ||
| 314 | } | ||
| 315 | |||
| 316 | static struct omap_mbox **find_mboxes(const char *name) | ||
| 317 | { | ||
| 318 | struct omap_mbox **p; | ||
| 319 | |||
| 320 | for (p = &mboxes; *p; p = &(*p)->next) { | ||
| 321 | if (strcmp((*p)->name, name) == 0) | ||
| 322 | break; | ||
| 323 | } | 305 | } |
| 324 | |||
| 325 | return p; | ||
| 326 | } | 306 | } |
| 327 | 307 | ||
| 328 | struct omap_mbox *omap_mbox_get(const char *name) | 308 | struct omap_mbox *omap_mbox_get(const char *name) |
| @@ -330,14 +310,15 @@ struct omap_mbox *omap_mbox_get(const char *name) | |||
| 330 | struct omap_mbox *mbox; | 310 | struct omap_mbox *mbox; |
| 331 | int ret; | 311 | int ret; |
| 332 | 312 | ||
| 333 | read_lock(&mboxes_lock); | 313 | if (!mboxes) |
| 334 | mbox = *(find_mboxes(name)); | 314 | return ERR_PTR(-EINVAL); |
| 335 | if (mbox == NULL) { | ||
| 336 | read_unlock(&mboxes_lock); | ||
| 337 | return ERR_PTR(-ENOENT); | ||
| 338 | } | ||
| 339 | 315 | ||
| 340 | read_unlock(&mboxes_lock); | 316 | for (mbox = *mboxes; mbox; mbox++) |
| 317 | if (!strcmp(mbox->name, name)) | ||
| 318 | break; | ||
| 319 | |||
| 320 | if (!mbox) | ||
| 321 | return ERR_PTR(-ENOENT); | ||
| 341 | 322 | ||
| 342 | ret = omap_mbox_startup(mbox); | 323 | ret = omap_mbox_startup(mbox); |
| 343 | if (ret) | 324 | if (ret) |
| @@ -353,70 +334,77 @@ void omap_mbox_put(struct omap_mbox *mbox) | |||
| 353 | } | 334 | } |
| 354 | EXPORT_SYMBOL(omap_mbox_put); | 335 | EXPORT_SYMBOL(omap_mbox_put); |
| 355 | 336 | ||
| 356 | int omap_mbox_register(struct device *parent, struct omap_mbox *mbox) | 337 | static struct class omap_mbox_class = { .name = "mbox", }; |
| 338 | |||
| 339 | int omap_mbox_register(struct device *parent, struct omap_mbox **list) | ||
| 357 | { | 340 | { |
| 358 | int ret = 0; | 341 | int ret; |
| 359 | struct omap_mbox **tmp; | 342 | int i; |
| 360 | 343 | ||
| 361 | if (!mbox) | 344 | mboxes = list; |
| 345 | if (!mboxes) | ||
| 362 | return -EINVAL; | 346 | return -EINVAL; |
| 363 | if (mbox->next) | ||
| 364 | return -EBUSY; | ||
| 365 | |||
| 366 | write_lock(&mboxes_lock); | ||
| 367 | tmp = find_mboxes(mbox->name); | ||
| 368 | if (*tmp) { | ||
| 369 | ret = -EBUSY; | ||
| 370 | write_unlock(&mboxes_lock); | ||
| 371 | goto err_find; | ||
| 372 | } | ||
| 373 | *tmp = mbox; | ||
| 374 | write_unlock(&mboxes_lock); | ||
| 375 | 347 | ||
| 348 | for (i = 0; mboxes[i]; i++) { | ||
| 349 | struct omap_mbox *mbox = mboxes[i]; | ||
| 350 | mbox->dev = device_create(&omap_mbox_class, | ||
| 351 | parent, 0, mbox, "%s", mbox->name); | ||
| 352 | if (IS_ERR(mbox->dev)) { | ||
| 353 | ret = PTR_ERR(mbox->dev); | ||
| 354 | goto err_out; | ||
| 355 | } | ||
| 356 | } | ||
| 376 | return 0; | 357 | return 0; |
| 377 | 358 | ||
| 378 | err_find: | 359 | err_out: |
| 360 | while (i--) | ||
| 361 | device_unregister(mboxes[i]->dev); | ||
| 379 | return ret; | 362 | return ret; |
| 380 | } | 363 | } |
| 381 | EXPORT_SYMBOL(omap_mbox_register); | 364 | EXPORT_SYMBOL(omap_mbox_register); |
| 382 | 365 | ||
| 383 | int omap_mbox_unregister(struct omap_mbox *mbox) | 366 | int omap_mbox_unregister(void) |
| 384 | { | 367 | { |
| 385 | struct omap_mbox **tmp; | 368 | int i; |
| 386 | 369 | ||
| 387 | write_lock(&mboxes_lock); | 370 | if (!mboxes) |
| 388 | tmp = &mboxes; | 371 | return -EINVAL; |
| 389 | while (*tmp) { | ||
| 390 | if (mbox == *tmp) { | ||
| 391 | *tmp = mbox->next; | ||
| 392 | mbox->next = NULL; | ||
| 393 | write_unlock(&mboxes_lock); | ||
| 394 | return 0; | ||
| 395 | } | ||
| 396 | tmp = &(*tmp)->next; | ||
| 397 | } | ||
| 398 | write_unlock(&mboxes_lock); | ||
| 399 | 372 | ||
| 400 | return -EINVAL; | 373 | for (i = 0; mboxes[i]; i++) |
| 374 | device_unregister(mboxes[i]->dev); | ||
| 375 | mboxes = NULL; | ||
| 376 | return 0; | ||
| 401 | } | 377 | } |
| 402 | EXPORT_SYMBOL(omap_mbox_unregister); | 378 | EXPORT_SYMBOL(omap_mbox_unregister); |
| 403 | 379 | ||
| 404 | static int __init omap_mbox_init(void) | 380 | static int __init omap_mbox_init(void) |
| 405 | { | 381 | { |
| 382 | int err; | ||
| 383 | |||
| 384 | err = class_register(&omap_mbox_class); | ||
| 385 | if (err) | ||
| 386 | return err; | ||
| 387 | |||
| 406 | mboxd = create_workqueue("mboxd"); | 388 | mboxd = create_workqueue("mboxd"); |
| 407 | if (!mboxd) | 389 | if (!mboxd) |
| 408 | return -ENOMEM; | 390 | return -ENOMEM; |
| 409 | 391 | ||
| 392 | /* kfifo size sanity check: alignment and minimal size */ | ||
| 393 | mbox_kfifo_size = ALIGN(mbox_kfifo_size, sizeof(mbox_msg_t)); | ||
| 394 | mbox_kfifo_size = max_t(unsigned int, mbox_kfifo_size, sizeof(mbox_msg_t)); | ||
| 395 | |||
| 410 | return 0; | 396 | return 0; |
| 411 | } | 397 | } |
| 412 | module_init(omap_mbox_init); | 398 | subsys_initcall(omap_mbox_init); |
| 413 | 399 | ||
| 414 | static void __exit omap_mbox_exit(void) | 400 | static void __exit omap_mbox_exit(void) |
| 415 | { | 401 | { |
| 416 | destroy_workqueue(mboxd); | 402 | destroy_workqueue(mboxd); |
| 403 | class_unregister(&omap_mbox_class); | ||
| 417 | } | 404 | } |
| 418 | module_exit(omap_mbox_exit); | 405 | module_exit(omap_mbox_exit); |
| 419 | 406 | ||
| 420 | MODULE_LICENSE("GPL v2"); | 407 | MODULE_LICENSE("GPL v2"); |
| 421 | MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); | 408 | MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); |
| 422 | MODULE_AUTHOR("Toshihiro Kobayashi and Hiroshi DOYU"); | 409 | MODULE_AUTHOR("Toshihiro Kobayashi"); |
| 410 | MODULE_AUTHOR("Hiroshi DOYU"); | ||
