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

rzn1-dmamux.c (4047B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2022 Schneider-Electric
      4 * Author: Miquel Raynal <miquel.raynal@bootlin.com
      5 * Based on TI crossbar driver written by Peter Ujfalusi <peter.ujfalusi@ti.com>
      6 */
      7#include <linux/bitops.h>
      8#include <linux/of_device.h>
      9#include <linux/of_dma.h>
     10#include <linux/slab.h>
     11#include <linux/soc/renesas/r9a06g032-sysctrl.h>
     12#include <linux/types.h>
     13
     14#define RNZ1_DMAMUX_NCELLS 6
     15#define RZN1_DMAMUX_MAX_LINES 64
     16#define RZN1_DMAMUX_LINES_PER_CTLR 16
     17
     18struct rzn1_dmamux_data {
     19	struct dma_router dmarouter;
     20	DECLARE_BITMAP(used_chans, 2 * RZN1_DMAMUX_LINES_PER_CTLR);
     21};
     22
     23struct rzn1_dmamux_map {
     24	unsigned int req_idx;
     25};
     26
     27static void rzn1_dmamux_free(struct device *dev, void *route_data)
     28{
     29	struct rzn1_dmamux_data *dmamux = dev_get_drvdata(dev);
     30	struct rzn1_dmamux_map *map = route_data;
     31
     32	dev_dbg(dev, "Unmapping DMAMUX request %u\n", map->req_idx);
     33
     34	clear_bit(map->req_idx, dmamux->used_chans);
     35
     36	kfree(map);
     37}
     38
     39static void *rzn1_dmamux_route_allocate(struct of_phandle_args *dma_spec,
     40					struct of_dma *ofdma)
     41{
     42	struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
     43	struct rzn1_dmamux_data *dmamux = platform_get_drvdata(pdev);
     44	struct rzn1_dmamux_map *map;
     45	unsigned int dmac_idx, chan, val;
     46	u32 mask;
     47	int ret;
     48
     49	if (dma_spec->args_count != RNZ1_DMAMUX_NCELLS)
     50		return ERR_PTR(-EINVAL);
     51
     52	map = kzalloc(sizeof(*map), GFP_KERNEL);
     53	if (!map)
     54		return ERR_PTR(-ENOMEM);
     55
     56	chan = dma_spec->args[0];
     57	map->req_idx = dma_spec->args[4];
     58	val = dma_spec->args[5];
     59	dma_spec->args_count -= 2;
     60
     61	if (chan >= RZN1_DMAMUX_LINES_PER_CTLR) {
     62		dev_err(&pdev->dev, "Invalid DMA request line: %u\n", chan);
     63		ret = -EINVAL;
     64		goto free_map;
     65	}
     66
     67	if (map->req_idx >= RZN1_DMAMUX_MAX_LINES ||
     68	    (map->req_idx % RZN1_DMAMUX_LINES_PER_CTLR) != chan) {
     69		dev_err(&pdev->dev, "Invalid MUX request line: %u\n", map->req_idx);
     70		ret = -EINVAL;
     71		goto free_map;
     72	}
     73
     74	dmac_idx = map->req_idx >= RZN1_DMAMUX_LINES_PER_CTLR ? 1 : 0;
     75	dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", dmac_idx);
     76	if (!dma_spec->np) {
     77		dev_err(&pdev->dev, "Can't get DMA master\n");
     78		ret = -EINVAL;
     79		goto free_map;
     80	}
     81
     82	dev_dbg(&pdev->dev, "Mapping DMAMUX request %u to DMAC%u request %u\n",
     83		map->req_idx, dmac_idx, chan);
     84
     85	if (test_and_set_bit(map->req_idx, dmamux->used_chans)) {
     86		ret = -EBUSY;
     87		goto free_map;
     88	}
     89
     90	mask = BIT(map->req_idx);
     91	ret = r9a06g032_sysctrl_set_dmamux(mask, val ? mask : 0);
     92	if (ret)
     93		goto clear_bitmap;
     94
     95	return map;
     96
     97clear_bitmap:
     98	clear_bit(map->req_idx, dmamux->used_chans);
     99free_map:
    100	kfree(map);
    101
    102	return ERR_PTR(ret);
    103}
    104
    105static const struct of_device_id rzn1_dmac_match[] = {
    106	{ .compatible = "renesas,rzn1-dma" },
    107	{}
    108};
    109
    110static int rzn1_dmamux_probe(struct platform_device *pdev)
    111{
    112	struct device_node *mux_node = pdev->dev.of_node;
    113	const struct of_device_id *match;
    114	struct device_node *dmac_node;
    115	struct rzn1_dmamux_data *dmamux;
    116
    117	dmamux = devm_kzalloc(&pdev->dev, sizeof(*dmamux), GFP_KERNEL);
    118	if (!dmamux)
    119		return -ENOMEM;
    120
    121	dmac_node = of_parse_phandle(mux_node, "dma-masters", 0);
    122	if (!dmac_node)
    123		return dev_err_probe(&pdev->dev, -ENODEV, "Can't get DMA master node\n");
    124
    125	match = of_match_node(rzn1_dmac_match, dmac_node);
    126	of_node_put(dmac_node);
    127	if (!match)
    128		return dev_err_probe(&pdev->dev, -EINVAL, "DMA master is not supported\n");
    129
    130	dmamux->dmarouter.dev = &pdev->dev;
    131	dmamux->dmarouter.route_free = rzn1_dmamux_free;
    132
    133	platform_set_drvdata(pdev, dmamux);
    134
    135	return of_dma_router_register(mux_node, rzn1_dmamux_route_allocate,
    136				      &dmamux->dmarouter);
    137}
    138
    139static const struct of_device_id rzn1_dmamux_match[] = {
    140	{ .compatible = "renesas,rzn1-dmamux" },
    141	{}
    142};
    143
    144static struct platform_driver rzn1_dmamux_driver = {
    145	.driver = {
    146		.name = "renesas,rzn1-dmamux",
    147		.of_match_table = rzn1_dmamux_match,
    148	},
    149	.probe	= rzn1_dmamux_probe,
    150};
    151module_platform_driver(rzn1_dmamux_driver);
    152
    153MODULE_LICENSE("GPL");
    154MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com");
    155MODULE_DESCRIPTION("Renesas RZ/N1 DMAMUX driver");