Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 70 additions & 80 deletions drivers/mailbox/mailbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@
* Author: Jassi Brar <jassisinghbrar@gmail.com>
*/

#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/mailbox_client.h>
#include <linux/mailbox_controller.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/property.h>
#include <linux/spinlock.h>

#include "mailbox.h"

Expand Down Expand Up @@ -325,7 +324,7 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
int ret;

if (chan->cl || !try_module_get(chan->mbox->dev->driver->owner)) {
dev_dbg(dev, "%s: mailbox not free\n", __func__);
dev_err(dev, "%s: mailbox not free\n", __func__);
return -EBUSY;
}

Expand Down Expand Up @@ -373,13 +372,9 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
*/
int mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
{
int ret;

mutex_lock(&con_mutex);
ret = __mbox_bind_client(chan, cl);
mutex_unlock(&con_mutex);
guard(mutex)(&con_mutex);

return ret;
return __mbox_bind_client(chan, cl);
}
EXPORT_SYMBOL_GPL(mbox_bind_client);

Expand All @@ -402,79 +397,80 @@ EXPORT_SYMBOL_GPL(mbox_bind_client);
*/
struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
{
struct device *dev = cl->dev;
struct fwnode_reference_args fwspec;
struct fwnode_handle *fwnode;
struct mbox_controller *mbox;
struct of_phandle_args spec;
struct mbox_chan *chan;
struct device *dev;
unsigned int i;
int ret;

if (!dev || !dev->of_node) {
pr_debug("%s: No owner device node\n", __func__);
dev = cl->dev;
if (!dev) {
pr_debug("No owner device\n");
return ERR_PTR(-ENODEV);
}

mutex_lock(&con_mutex);
fwnode = dev_fwnode(dev);
if (!fwnode) {
dev_dbg(dev, "No owner fwnode\n");
return ERR_PTR(-ENODEV);
}

ret = of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells",
index, &spec);
ret = fwnode_property_get_reference_args(fwnode, "mboxes", "#mbox-cells",
0, index, &fwspec);
if (ret) {
dev_dbg(dev, "%s: can't parse \"mboxes\" property\n", __func__);
mutex_unlock(&con_mutex);
dev_err(dev, "%s: can't parse \"%s\" property\n", __func__, "mboxes");
return ERR_PTR(ret);
}

chan = ERR_PTR(-EPROBE_DEFER);
list_for_each_entry(mbox, &mbox_cons, node)
if (mbox->dev->of_node == spec.np) {
chan = mbox->of_xlate(mbox, &spec);
if (!IS_ERR(chan))
break;
spec.np = to_of_node(fwspec.fwnode);
spec.args_count = fwspec.nargs;
for (i = 0; i < spec.args_count; i++)
spec.args[i] = fwspec.args[i];

scoped_guard(mutex, &con_mutex) {
chan = ERR_PTR(-EPROBE_DEFER);
list_for_each_entry(mbox, &mbox_cons, node) {
if (device_match_fwnode(mbox->dev, fwspec.fwnode)) {
if (mbox->fw_xlate) {
chan = mbox->fw_xlate(mbox, &fwspec);
if (!IS_ERR(chan))
break;
} else if (mbox->of_xlate) {
chan = mbox->of_xlate(mbox, &spec);
if (!IS_ERR(chan))
break;
}
}
}

of_node_put(spec.np);
fwnode_handle_put(fwspec.fwnode);

if (IS_ERR(chan)) {
mutex_unlock(&con_mutex);
return chan;
}
if (IS_ERR(chan))
return chan;

ret = __mbox_bind_client(chan, cl);
if (ret)
chan = ERR_PTR(ret);
ret = __mbox_bind_client(chan, cl);
if (ret)
chan = ERR_PTR(ret);
}

mutex_unlock(&con_mutex);
return chan;
}
EXPORT_SYMBOL_GPL(mbox_request_channel);

struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,
const char *name)
{
struct device_node *np = cl->dev->of_node;
struct property *prop;
const char *mbox_name;
int index = 0;
int index = device_property_match_string(cl->dev, "mbox-names", name);

if (!np) {
dev_err(cl->dev, "%s() currently only supports DT\n", __func__);
if (index < 0) {
dev_err(cl->dev, "%s() could not locate channel named \"%s\"\n",
__func__, name);
return ERR_PTR(-EINVAL);
}

if (!of_get_property(np, "mbox-names", NULL)) {
dev_err(cl->dev,
"%s() requires an \"mbox-names\" property\n", __func__);
return ERR_PTR(-EINVAL);
}

of_property_for_each_string(np, "mbox-names", prop, mbox_name) {
if (!strncmp(name, mbox_name, strlen(name)))
return mbox_request_channel(cl, index);
index++;
}

dev_err(cl->dev, "%s() could not locate channel named \"%s\"\n",
__func__, name);
return ERR_PTR(-EINVAL);
return mbox_request_channel(cl, index);
}
EXPORT_SYMBOL_GPL(mbox_request_channel_byname);

Expand Down Expand Up @@ -505,16 +501,13 @@ void mbox_free_channel(struct mbox_chan *chan)
}
EXPORT_SYMBOL_GPL(mbox_free_channel);

static struct mbox_chan *
of_mbox_index_xlate(struct mbox_controller *mbox,
const struct of_phandle_args *sp)
static struct mbox_chan *fw_mbox_index_xlate(struct mbox_controller *mbox,
const struct fwnode_reference_args *sp)
{
int ind = sp->args[0];

if (ind >= mbox->num_chans)
if (sp->nargs < 1 || sp->args[0] >= mbox->num_chans)
return ERR_PTR(-EINVAL);

return &mbox->chans[ind];
return &mbox->chans[sp->args[0]];
}

/**
Expand Down Expand Up @@ -560,12 +553,11 @@ int mbox_controller_register(struct mbox_controller *mbox)
spin_lock_init(&chan->lock);
}

if (!mbox->of_xlate)
mbox->of_xlate = of_mbox_index_xlate;
if (!mbox->fw_xlate && !mbox->of_xlate)
mbox->fw_xlate = fw_mbox_index_xlate;

mutex_lock(&con_mutex);
list_add_tail(&mbox->node, &mbox_cons);
mutex_unlock(&con_mutex);
scoped_guard(mutex, &con_mutex)
list_add_tail(&mbox->node, &mbox_cons);

return 0;
}
Expand All @@ -582,17 +574,15 @@ void mbox_controller_unregister(struct mbox_controller *mbox)
if (!mbox)
return;

mutex_lock(&con_mutex);
scoped_guard(mutex, &con_mutex) {
list_del(&mbox->node);

list_del(&mbox->node);
for (i = 0; i < mbox->num_chans; i++)
mbox_free_channel(&mbox->chans[i]);

for (i = 0; i < mbox->num_chans; i++)
mbox_free_channel(&mbox->chans[i]);

if (mbox->txdone_poll)
hrtimer_cancel(&mbox->poll_hrt);

mutex_unlock(&con_mutex);
if (mbox->txdone_poll)
hrtimer_cancel(&mbox->poll_hrt);
}
}
EXPORT_SYMBOL_GPL(mbox_controller_unregister);

Expand Down
2 changes: 1 addition & 1 deletion include/linux/mailbox_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
#ifndef __MAILBOX_CLIENT_H
#define __MAILBOX_CLIENT_H

#include <linux/of.h>
#include <linux/device.h>
#include <linux/of.h>

struct mbox_chan;

Expand Down
9 changes: 6 additions & 3 deletions include/linux/mailbox_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
#ifndef __MAILBOX_CONTROLLER_H
#define __MAILBOX_CONTROLLER_H

#include <linux/completion.h>
#include <linux/device.h>
#include <linux/hrtimer.h>
#include <linux/of.h>
#include <linux/types.h>
#include <linux/hrtimer.h>
#include <linux/device.h>
#include <linux/completion.h>

struct mbox_chan;

Expand Down Expand Up @@ -66,6 +66,7 @@ struct mbox_chan_ops {
* no interrupt rises. Ignored if 'txdone_irq' is set.
* @txpoll_period: If 'txdone_poll' is in effect, the API polls for
* last TX's status after these many millisecs
* @fw_xlate: Controller driver specific mapping of channel via fwnode
* @of_xlate: Controller driver specific mapping of channel via DT
* @poll_hrt: API private. hrtimer used to poll for TXDONE on all
* channels.
Expand All @@ -79,6 +80,8 @@ struct mbox_controller {
bool txdone_irq;
bool txdone_poll;
unsigned txpoll_period;
struct mbox_chan *(*fw_xlate)(struct mbox_controller *mbox,
const struct fwnode_reference_args *sp);
struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox,
const struct of_phandle_args *sp);
/* Internal to API */
Expand Down
Loading