| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Mailbox: Common code for Mailbox controllers and users |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2013-2014 Linaro Ltd. |
|---|
| 5 | 6 | * Author: Jassi Brar <jassisinghbrar@gmail.com> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 8 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 9 | | - * published by the Free Software Foundation. |
|---|
| 10 | 7 | */ |
|---|
| 11 | 8 | |
|---|
| 12 | 9 | #include <linux/interrupt.h> |
|---|
| .. | .. |
|---|
| 53 | 50 | return idx; |
|---|
| 54 | 51 | } |
|---|
| 55 | 52 | |
|---|
| 56 | | -static int __msg_submit(struct mbox_chan *chan) |
|---|
| 53 | +static void msg_submit(struct mbox_chan *chan) |
|---|
| 57 | 54 | { |
|---|
| 58 | 55 | unsigned count, idx; |
|---|
| 59 | 56 | unsigned long flags; |
|---|
| .. | .. |
|---|
| 84 | 81 | } |
|---|
| 85 | 82 | exit: |
|---|
| 86 | 83 | spin_unlock_irqrestore(&chan->lock, flags); |
|---|
| 87 | | - |
|---|
| 88 | | - return err; |
|---|
| 89 | | -} |
|---|
| 90 | | - |
|---|
| 91 | | -static void msg_submit(struct mbox_chan *chan) |
|---|
| 92 | | -{ |
|---|
| 93 | | - int err = 0; |
|---|
| 94 | | - |
|---|
| 95 | | - /* |
|---|
| 96 | | - * If the controller returns -EAGAIN, then it means, our spinlock |
|---|
| 97 | | - * here is preventing the controller from receiving its interrupt, |
|---|
| 98 | | - * that would help clear the controller channels that are currently |
|---|
| 99 | | - * blocked waiting on the interrupt response. |
|---|
| 100 | | - * Retry again. |
|---|
| 101 | | - */ |
|---|
| 102 | | - do { |
|---|
| 103 | | - err = __msg_submit(chan); |
|---|
| 104 | | - } while (err == -EAGAIN); |
|---|
| 105 | 84 | |
|---|
| 106 | 85 | /* kick start the timer immediately to avoid delays */ |
|---|
| 107 | 86 | if (!err && (chan->txdone_method & TXDONE_BY_POLL)) { |
|---|
| .. | .. |
|---|
| 304 | 283 | EXPORT_SYMBOL_GPL(mbox_send_message); |
|---|
| 305 | 284 | |
|---|
| 306 | 285 | /** |
|---|
| 286 | + * mbox_flush - flush a mailbox channel |
|---|
| 287 | + * @chan: mailbox channel to flush |
|---|
| 288 | + * @timeout: time, in milliseconds, to allow the flush operation to succeed |
|---|
| 289 | + * |
|---|
| 290 | + * Mailbox controllers that need to work in atomic context can implement the |
|---|
| 291 | + * ->flush() callback to busy loop until a transmission has been completed. |
|---|
| 292 | + * The implementation must call mbox_chan_txdone() upon success. Clients can |
|---|
| 293 | + * call the mbox_flush() function at any time after mbox_send_message() to |
|---|
| 294 | + * flush the transmission. After the function returns success, the mailbox |
|---|
| 295 | + * transmission is guaranteed to have completed. |
|---|
| 296 | + * |
|---|
| 297 | + * Returns: 0 on success or a negative error code on failure. |
|---|
| 298 | + */ |
|---|
| 299 | +int mbox_flush(struct mbox_chan *chan, unsigned long timeout) |
|---|
| 300 | +{ |
|---|
| 301 | + int ret; |
|---|
| 302 | + |
|---|
| 303 | + if (!chan->mbox->ops->flush) |
|---|
| 304 | + return -ENOTSUPP; |
|---|
| 305 | + |
|---|
| 306 | + ret = chan->mbox->ops->flush(chan, timeout); |
|---|
| 307 | + if (ret < 0) |
|---|
| 308 | + tx_tick(chan, ret); |
|---|
| 309 | + |
|---|
| 310 | + return ret; |
|---|
| 311 | +} |
|---|
| 312 | +EXPORT_SYMBOL_GPL(mbox_flush); |
|---|
| 313 | + |
|---|
| 314 | +/** |
|---|
| 307 | 315 | * mbox_request_channel - Request a mailbox channel. |
|---|
| 308 | 316 | * @cl: Identity of the client requesting the channel. |
|---|
| 309 | 317 | * @index: Index of mailbox specifier in 'mboxes' property. |
|---|
| .. | .. |
|---|
| 347 | 355 | list_for_each_entry(mbox, &mbox_cons, node) |
|---|
| 348 | 356 | if (mbox->dev->of_node == spec.np) { |
|---|
| 349 | 357 | chan = mbox->of_xlate(mbox, &spec); |
|---|
| 350 | | - break; |
|---|
| 358 | + if (!IS_ERR(chan)) |
|---|
| 359 | + break; |
|---|
| 351 | 360 | } |
|---|
| 352 | 361 | |
|---|
| 353 | 362 | of_node_put(spec.np); |
|---|
| .. | .. |
|---|
| 537 | 546 | mutex_unlock(&con_mutex); |
|---|
| 538 | 547 | } |
|---|
| 539 | 548 | EXPORT_SYMBOL_GPL(mbox_controller_unregister); |
|---|
| 549 | + |
|---|
| 550 | +static void __devm_mbox_controller_unregister(struct device *dev, void *res) |
|---|
| 551 | +{ |
|---|
| 552 | + struct mbox_controller **mbox = res; |
|---|
| 553 | + |
|---|
| 554 | + mbox_controller_unregister(*mbox); |
|---|
| 555 | +} |
|---|
| 556 | + |
|---|
| 557 | +static int devm_mbox_controller_match(struct device *dev, void *res, void *data) |
|---|
| 558 | +{ |
|---|
| 559 | + struct mbox_controller **mbox = res; |
|---|
| 560 | + |
|---|
| 561 | + if (WARN_ON(!mbox || !*mbox)) |
|---|
| 562 | + return 0; |
|---|
| 563 | + |
|---|
| 564 | + return *mbox == data; |
|---|
| 565 | +} |
|---|
| 566 | + |
|---|
| 567 | +/** |
|---|
| 568 | + * devm_mbox_controller_register() - managed mbox_controller_register() |
|---|
| 569 | + * @dev: device owning the mailbox controller being registered |
|---|
| 570 | + * @mbox: mailbox controller being registered |
|---|
| 571 | + * |
|---|
| 572 | + * This function adds a device-managed resource that will make sure that the |
|---|
| 573 | + * mailbox controller, which is registered using mbox_controller_register() |
|---|
| 574 | + * as part of this function, will be unregistered along with the rest of |
|---|
| 575 | + * device-managed resources upon driver probe failure or driver removal. |
|---|
| 576 | + * |
|---|
| 577 | + * Returns 0 on success or a negative error code on failure. |
|---|
| 578 | + */ |
|---|
| 579 | +int devm_mbox_controller_register(struct device *dev, |
|---|
| 580 | + struct mbox_controller *mbox) |
|---|
| 581 | +{ |
|---|
| 582 | + struct mbox_controller **ptr; |
|---|
| 583 | + int err; |
|---|
| 584 | + |
|---|
| 585 | + ptr = devres_alloc(__devm_mbox_controller_unregister, sizeof(*ptr), |
|---|
| 586 | + GFP_KERNEL); |
|---|
| 587 | + if (!ptr) |
|---|
| 588 | + return -ENOMEM; |
|---|
| 589 | + |
|---|
| 590 | + err = mbox_controller_register(mbox); |
|---|
| 591 | + if (err < 0) { |
|---|
| 592 | + devres_free(ptr); |
|---|
| 593 | + return err; |
|---|
| 594 | + } |
|---|
| 595 | + |
|---|
| 596 | + devres_add(dev, ptr); |
|---|
| 597 | + *ptr = mbox; |
|---|
| 598 | + |
|---|
| 599 | + return 0; |
|---|
| 600 | +} |
|---|
| 601 | +EXPORT_SYMBOL_GPL(devm_mbox_controller_register); |
|---|
| 602 | + |
|---|
| 603 | +/** |
|---|
| 604 | + * devm_mbox_controller_unregister() - managed mbox_controller_unregister() |
|---|
| 605 | + * @dev: device owning the mailbox controller being unregistered |
|---|
| 606 | + * @mbox: mailbox controller being unregistered |
|---|
| 607 | + * |
|---|
| 608 | + * This function unregisters the mailbox controller and removes the device- |
|---|
| 609 | + * managed resource that was set up to automatically unregister the mailbox |
|---|
| 610 | + * controller on driver probe failure or driver removal. It's typically not |
|---|
| 611 | + * necessary to call this function. |
|---|
| 612 | + */ |
|---|
| 613 | +void devm_mbox_controller_unregister(struct device *dev, struct mbox_controller *mbox) |
|---|
| 614 | +{ |
|---|
| 615 | + WARN_ON(devres_release(dev, __devm_mbox_controller_unregister, |
|---|
| 616 | + devm_mbox_controller_match, mbox)); |
|---|
| 617 | +} |
|---|
| 618 | +EXPORT_SYMBOL_GPL(devm_mbox_controller_unregister); |
|---|