cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

imx-dsp.c (4276B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright 2019 NXP
      4 *  Author: Daniel Baluta <daniel.baluta@nxp.com>
      5 *
      6 * Implementation of the DSP IPC interface (host side)
      7 */
      8
      9#include <linux/firmware/imx/dsp.h>
     10#include <linux/kernel.h>
     11#include <linux/mailbox_client.h>
     12#include <linux/module.h>
     13#include <linux/of_platform.h>
     14#include <linux/platform_device.h>
     15#include <linux/slab.h>
     16
     17/*
     18 * imx_dsp_ring_doorbell - triggers an interrupt on the other side (DSP)
     19 *
     20 * @dsp: DSP IPC handle
     21 * @chan_idx: index of the channel where to trigger the interrupt
     22 *
     23 * Returns non-negative value for success, negative value for error
     24 */
     25int imx_dsp_ring_doorbell(struct imx_dsp_ipc *ipc, unsigned int idx)
     26{
     27	int ret;
     28	struct imx_dsp_chan *dsp_chan;
     29
     30	if (idx >= DSP_MU_CHAN_NUM)
     31		return -EINVAL;
     32
     33	dsp_chan = &ipc->chans[idx];
     34	ret = mbox_send_message(dsp_chan->ch, NULL);
     35	if (ret < 0)
     36		return ret;
     37
     38	return 0;
     39}
     40EXPORT_SYMBOL(imx_dsp_ring_doorbell);
     41
     42/*
     43 * imx_dsp_handle_rx - rx callback used by imx mailbox
     44 *
     45 * @c: mbox client
     46 * @msg: message received
     47 *
     48 * Users of DSP IPC will need to privde handle_reply and handle_request
     49 * callbacks.
     50 */
     51static void imx_dsp_handle_rx(struct mbox_client *c, void *msg)
     52{
     53	struct imx_dsp_chan *chan = container_of(c, struct imx_dsp_chan, cl);
     54
     55	if (chan->idx == 0) {
     56		chan->ipc->ops->handle_reply(chan->ipc);
     57	} else {
     58		chan->ipc->ops->handle_request(chan->ipc);
     59		imx_dsp_ring_doorbell(chan->ipc, 1);
     60	}
     61}
     62
     63struct mbox_chan *imx_dsp_request_channel(struct imx_dsp_ipc *dsp_ipc, int idx)
     64{
     65	struct imx_dsp_chan *dsp_chan;
     66
     67	if (idx >= DSP_MU_CHAN_NUM)
     68		return ERR_PTR(-EINVAL);
     69
     70	dsp_chan = &dsp_ipc->chans[idx];
     71	dsp_chan->ch = mbox_request_channel_byname(&dsp_chan->cl, dsp_chan->name);
     72	return dsp_chan->ch;
     73}
     74EXPORT_SYMBOL(imx_dsp_request_channel);
     75
     76void imx_dsp_free_channel(struct imx_dsp_ipc *dsp_ipc, int idx)
     77{
     78	struct imx_dsp_chan *dsp_chan;
     79
     80	if (idx >= DSP_MU_CHAN_NUM)
     81		return;
     82
     83	dsp_chan = &dsp_ipc->chans[idx];
     84	mbox_free_channel(dsp_chan->ch);
     85}
     86EXPORT_SYMBOL(imx_dsp_free_channel);
     87
     88static int imx_dsp_setup_channels(struct imx_dsp_ipc *dsp_ipc)
     89{
     90	struct device *dev = dsp_ipc->dev;
     91	struct imx_dsp_chan *dsp_chan;
     92	struct mbox_client *cl;
     93	char *chan_name;
     94	int ret;
     95	int i, j;
     96
     97	for (i = 0; i < DSP_MU_CHAN_NUM; i++) {
     98		if (i < 2)
     99			chan_name = kasprintf(GFP_KERNEL, "txdb%d", i);
    100		else
    101			chan_name = kasprintf(GFP_KERNEL, "rxdb%d", i - 2);
    102
    103		if (!chan_name)
    104			return -ENOMEM;
    105
    106		dsp_chan = &dsp_ipc->chans[i];
    107		dsp_chan->name = chan_name;
    108		cl = &dsp_chan->cl;
    109		cl->dev = dev;
    110		cl->tx_block = false;
    111		cl->knows_txdone = true;
    112		cl->rx_callback = imx_dsp_handle_rx;
    113
    114		dsp_chan->ipc = dsp_ipc;
    115		dsp_chan->idx = i % 2;
    116		dsp_chan->ch = mbox_request_channel_byname(cl, chan_name);
    117		if (IS_ERR(dsp_chan->ch)) {
    118			ret = PTR_ERR(dsp_chan->ch);
    119			if (ret != -EPROBE_DEFER)
    120				dev_err(dev, "Failed to request mbox chan %s ret %d\n",
    121					chan_name, ret);
    122			goto out;
    123		}
    124
    125		dev_dbg(dev, "request mbox chan %s\n", chan_name);
    126	}
    127
    128	return 0;
    129out:
    130	for (j = 0; j < i; j++) {
    131		dsp_chan = &dsp_ipc->chans[j];
    132		mbox_free_channel(dsp_chan->ch);
    133		kfree(dsp_chan->name);
    134	}
    135
    136	return ret;
    137}
    138
    139static int imx_dsp_probe(struct platform_device *pdev)
    140{
    141	struct device *dev = &pdev->dev;
    142	struct imx_dsp_ipc *dsp_ipc;
    143	int ret;
    144
    145	device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
    146
    147	dsp_ipc = devm_kzalloc(dev, sizeof(*dsp_ipc), GFP_KERNEL);
    148	if (!dsp_ipc)
    149		return -ENOMEM;
    150
    151	dsp_ipc->dev = dev;
    152	dev_set_drvdata(dev, dsp_ipc);
    153
    154	ret = imx_dsp_setup_channels(dsp_ipc);
    155	if (ret < 0)
    156		return ret;
    157
    158	dev_info(dev, "NXP i.MX DSP IPC initialized\n");
    159
    160	return 0;
    161}
    162
    163static int imx_dsp_remove(struct platform_device *pdev)
    164{
    165	struct imx_dsp_chan *dsp_chan;
    166	struct imx_dsp_ipc *dsp_ipc;
    167	int i;
    168
    169	dsp_ipc = dev_get_drvdata(&pdev->dev);
    170
    171	for (i = 0; i < DSP_MU_CHAN_NUM; i++) {
    172		dsp_chan = &dsp_ipc->chans[i];
    173		mbox_free_channel(dsp_chan->ch);
    174		kfree(dsp_chan->name);
    175	}
    176
    177	return 0;
    178}
    179
    180static struct platform_driver imx_dsp_driver = {
    181	.driver = {
    182		.name = "imx-dsp",
    183	},
    184	.probe = imx_dsp_probe,
    185	.remove = imx_dsp_remove,
    186};
    187builtin_platform_driver(imx_dsp_driver);
    188
    189MODULE_AUTHOR("Daniel Baluta <daniel.baluta@nxp.com>");
    190MODULE_DESCRIPTION("IMX DSP IPC protocol driver");
    191MODULE_LICENSE("GPL v2");