in ti_sci.c [3294:3436]
static int ti_sci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct of_device_id *of_id;
const struct ti_sci_desc *desc;
struct ti_sci_xfer *xfer;
struct ti_sci_info *info = NULL;
struct ti_sci_xfers_info *minfo;
struct mbox_client *cl;
int ret = -EINVAL;
int i;
int reboot = 0;
u32 h_id;
of_id = of_match_device(ti_sci_of_match, dev);
if (!of_id) {
dev_err(dev, "OF data missing\n");
return -EINVAL;
}
desc = of_id->data;
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->dev = dev;
info->desc = desc;
ret = of_property_read_u32(dev->of_node, "ti,host-id", &h_id);
/* if the property is not present in DT, use a default from desc */
if (ret < 0) {
info->host_id = info->desc->default_host_id;
} else {
if (!h_id) {
dev_warn(dev, "Host ID 0 is reserved for firmware\n");
info->host_id = info->desc->default_host_id;
} else {
info->host_id = h_id;
}
}
reboot = of_property_read_bool(dev->of_node,
"ti,system-reboot-controller");
INIT_LIST_HEAD(&info->node);
minfo = &info->minfo;
/*
* Pre-allocate messages
* NEVER allocate more than what we can indicate in hdr.seq
* if we have data description bug, force a fix..
*/
if (WARN_ON(desc->max_msgs >=
1 << 8 * sizeof(((struct ti_sci_msg_hdr *)0)->seq)))
return -EINVAL;
minfo->xfer_block = devm_kcalloc(dev,
desc->max_msgs,
sizeof(*minfo->xfer_block),
GFP_KERNEL);
if (!minfo->xfer_block)
return -ENOMEM;
minfo->xfer_alloc_table = devm_kcalloc(dev,
BITS_TO_LONGS(desc->max_msgs),
sizeof(unsigned long),
GFP_KERNEL);
if (!minfo->xfer_alloc_table)
return -ENOMEM;
bitmap_zero(minfo->xfer_alloc_table, desc->max_msgs);
/* Pre-initialize the buffer pointer to pre-allocated buffers */
for (i = 0, xfer = minfo->xfer_block; i < desc->max_msgs; i++, xfer++) {
xfer->xfer_buf = devm_kcalloc(dev, 1, desc->max_msg_size,
GFP_KERNEL);
if (!xfer->xfer_buf)
return -ENOMEM;
xfer->tx_message.buf = xfer->xfer_buf;
init_completion(&xfer->done);
}
ret = ti_sci_debugfs_create(pdev, info);
if (ret)
dev_warn(dev, "Failed to create debug file\n");
platform_set_drvdata(pdev, info);
cl = &info->cl;
cl->dev = dev;
cl->tx_block = false;
cl->rx_callback = ti_sci_rx_callback;
cl->knows_txdone = true;
spin_lock_init(&minfo->xfer_lock);
sema_init(&minfo->sem_xfer_count, desc->max_msgs);
info->chan_rx = mbox_request_channel_byname(cl, "rx");
if (IS_ERR(info->chan_rx)) {
ret = PTR_ERR(info->chan_rx);
goto out;
}
info->chan_tx = mbox_request_channel_byname(cl, "tx");
if (IS_ERR(info->chan_tx)) {
ret = PTR_ERR(info->chan_tx);
goto out;
}
ret = ti_sci_cmd_get_revision(info);
if (ret) {
dev_err(dev, "Unable to communicate with TISCI(%d)\n", ret);
goto out;
}
ti_sci_setup_ops(info);
if (reboot) {
info->nb.notifier_call = tisci_reboot_handler;
info->nb.priority = 128;
ret = register_restart_handler(&info->nb);
if (ret) {
dev_err(dev, "reboot registration fail(%d)\n", ret);
return ret;
}
}
dev_info(dev, "ABI: %d.%d (firmware rev 0x%04x '%s')\n",
info->handle.version.abi_major, info->handle.version.abi_minor,
info->handle.version.firmware_revision,
info->handle.version.firmware_description);
mutex_lock(&ti_sci_list_mutex);
list_add_tail(&info->node, &ti_sci_list);
mutex_unlock(&ti_sci_list_mutex);
return of_platform_populate(dev->of_node, NULL, NULL, dev);
out:
if (!IS_ERR(info->chan_tx))
mbox_free_channel(info->chan_tx);
if (!IS_ERR(info->chan_rx))
mbox_free_channel(info->chan_rx);
debugfs_remove(info->d);
return ret;
}