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

keystone_remoteproc.c (14108B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * TI Keystone DSP remoteproc driver
      4 *
      5 * Copyright (C) 2015-2017 Texas Instruments Incorporated - http://www.ti.com/
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/slab.h>
     10#include <linux/io.h>
     11#include <linux/interrupt.h>
     12#include <linux/platform_device.h>
     13#include <linux/pm_runtime.h>
     14#include <linux/workqueue.h>
     15#include <linux/of_address.h>
     16#include <linux/of_reserved_mem.h>
     17#include <linux/of_gpio.h>
     18#include <linux/regmap.h>
     19#include <linux/mfd/syscon.h>
     20#include <linux/remoteproc.h>
     21#include <linux/reset.h>
     22
     23#include "remoteproc_internal.h"
     24
     25#define KEYSTONE_RPROC_LOCAL_ADDRESS_MASK	(SZ_16M - 1)
     26
     27/**
     28 * struct keystone_rproc_mem - internal memory structure
     29 * @cpu_addr: MPU virtual address of the memory region
     30 * @bus_addr: Bus address used to access the memory region
     31 * @dev_addr: Device address of the memory region from DSP view
     32 * @size: Size of the memory region
     33 */
     34struct keystone_rproc_mem {
     35	void __iomem *cpu_addr;
     36	phys_addr_t bus_addr;
     37	u32 dev_addr;
     38	size_t size;
     39};
     40
     41/**
     42 * struct keystone_rproc - keystone remote processor driver structure
     43 * @dev: cached device pointer
     44 * @rproc: remoteproc device handle
     45 * @mem: internal memory regions data
     46 * @num_mems: number of internal memory regions
     47 * @dev_ctrl: device control regmap handle
     48 * @reset: reset control handle
     49 * @boot_offset: boot register offset in @dev_ctrl regmap
     50 * @irq_ring: irq entry for vring
     51 * @irq_fault: irq entry for exception
     52 * @kick_gpio: gpio used for virtio kicks
     53 * @workqueue: workqueue for processing virtio interrupts
     54 */
     55struct keystone_rproc {
     56	struct device *dev;
     57	struct rproc *rproc;
     58	struct keystone_rproc_mem *mem;
     59	int num_mems;
     60	struct regmap *dev_ctrl;
     61	struct reset_control *reset;
     62	u32 boot_offset;
     63	int irq_ring;
     64	int irq_fault;
     65	int kick_gpio;
     66	struct work_struct workqueue;
     67};
     68
     69/* Put the DSP processor into reset */
     70static void keystone_rproc_dsp_reset(struct keystone_rproc *ksproc)
     71{
     72	reset_control_assert(ksproc->reset);
     73}
     74
     75/* Configure the boot address and boot the DSP processor */
     76static int keystone_rproc_dsp_boot(struct keystone_rproc *ksproc, u32 boot_addr)
     77{
     78	int ret;
     79
     80	if (boot_addr & (SZ_1K - 1)) {
     81		dev_err(ksproc->dev, "invalid boot address 0x%x, must be aligned on a 1KB boundary\n",
     82			boot_addr);
     83		return -EINVAL;
     84	}
     85
     86	ret = regmap_write(ksproc->dev_ctrl, ksproc->boot_offset, boot_addr);
     87	if (ret) {
     88		dev_err(ksproc->dev, "regmap_write of boot address failed, status = %d\n",
     89			ret);
     90		return ret;
     91	}
     92
     93	reset_control_deassert(ksproc->reset);
     94
     95	return 0;
     96}
     97
     98/*
     99 * Process the remoteproc exceptions
    100 *
    101 * The exception reporting on Keystone DSP remote processors is very simple
    102 * compared to the equivalent processors on the OMAP family, it is notified
    103 * through a software-designed specific interrupt source in the IPC interrupt
    104 * generation register.
    105 *
    106 * This function just invokes the rproc_report_crash to report the exception
    107 * to the remoteproc driver core, to trigger a recovery.
    108 */
    109static irqreturn_t keystone_rproc_exception_interrupt(int irq, void *dev_id)
    110{
    111	struct keystone_rproc *ksproc = dev_id;
    112
    113	rproc_report_crash(ksproc->rproc, RPROC_FATAL_ERROR);
    114
    115	return IRQ_HANDLED;
    116}
    117
    118/*
    119 * Main virtqueue message workqueue function
    120 *
    121 * This function is executed upon scheduling of the keystone remoteproc
    122 * driver's workqueue. The workqueue is scheduled by the vring ISR handler.
    123 *
    124 * There is no payload message indicating the virtqueue index as is the
    125 * case with mailbox-based implementations on OMAP family. As such, this
    126 * handler processes both the Tx and Rx virtqueue indices on every invocation.
    127 * The rproc_vq_interrupt function can detect if there are new unprocessed
    128 * messages or not (returns IRQ_NONE vs IRQ_HANDLED), but there is no need
    129 * to check for these return values. The index 0 triggering will process all
    130 * pending Rx buffers, and the index 1 triggering will process all newly
    131 * available Tx buffers and will wakeup any potentially blocked senders.
    132 *
    133 * NOTE:
    134 * 1. A payload could be added by using some of the source bits in the
    135 *    IPC interrupt generation registers, but this would need additional
    136 *    changes to the overall IPC stack, and currently there are no benefits
    137 *    of adapting that approach.
    138 * 2. The current logic is based on an inherent design assumption of supporting
    139 *    only 2 vrings, but this can be changed if needed.
    140 */
    141static void handle_event(struct work_struct *work)
    142{
    143	struct keystone_rproc *ksproc =
    144		container_of(work, struct keystone_rproc, workqueue);
    145
    146	rproc_vq_interrupt(ksproc->rproc, 0);
    147	rproc_vq_interrupt(ksproc->rproc, 1);
    148}
    149
    150/*
    151 * Interrupt handler for processing vring kicks from remote processor
    152 */
    153static irqreturn_t keystone_rproc_vring_interrupt(int irq, void *dev_id)
    154{
    155	struct keystone_rproc *ksproc = dev_id;
    156
    157	schedule_work(&ksproc->workqueue);
    158
    159	return IRQ_HANDLED;
    160}
    161
    162/*
    163 * Power up the DSP remote processor.
    164 *
    165 * This function will be invoked only after the firmware for this rproc
    166 * was loaded, parsed successfully, and all of its resource requirements
    167 * were met.
    168 */
    169static int keystone_rproc_start(struct rproc *rproc)
    170{
    171	struct keystone_rproc *ksproc = rproc->priv;
    172	int ret;
    173
    174	INIT_WORK(&ksproc->workqueue, handle_event);
    175
    176	ret = request_irq(ksproc->irq_ring, keystone_rproc_vring_interrupt, 0,
    177			  dev_name(ksproc->dev), ksproc);
    178	if (ret) {
    179		dev_err(ksproc->dev, "failed to enable vring interrupt, ret = %d\n",
    180			ret);
    181		goto out;
    182	}
    183
    184	ret = request_irq(ksproc->irq_fault, keystone_rproc_exception_interrupt,
    185			  0, dev_name(ksproc->dev), ksproc);
    186	if (ret) {
    187		dev_err(ksproc->dev, "failed to enable exception interrupt, ret = %d\n",
    188			ret);
    189		goto free_vring_irq;
    190	}
    191
    192	ret = keystone_rproc_dsp_boot(ksproc, rproc->bootaddr);
    193	if (ret)
    194		goto free_exc_irq;
    195
    196	return 0;
    197
    198free_exc_irq:
    199	free_irq(ksproc->irq_fault, ksproc);
    200free_vring_irq:
    201	free_irq(ksproc->irq_ring, ksproc);
    202	flush_work(&ksproc->workqueue);
    203out:
    204	return ret;
    205}
    206
    207/*
    208 * Stop the DSP remote processor.
    209 *
    210 * This function puts the DSP processor into reset, and finishes processing
    211 * of any pending messages.
    212 */
    213static int keystone_rproc_stop(struct rproc *rproc)
    214{
    215	struct keystone_rproc *ksproc = rproc->priv;
    216
    217	keystone_rproc_dsp_reset(ksproc);
    218	free_irq(ksproc->irq_fault, ksproc);
    219	free_irq(ksproc->irq_ring, ksproc);
    220	flush_work(&ksproc->workqueue);
    221
    222	return 0;
    223}
    224
    225/*
    226 * Kick the remote processor to notify about pending unprocessed messages.
    227 * The vqid usage is not used and is inconsequential, as the kick is performed
    228 * through a simulated GPIO (a bit in an IPC interrupt-triggering register),
    229 * the remote processor is expected to process both its Tx and Rx virtqueues.
    230 */
    231static void keystone_rproc_kick(struct rproc *rproc, int vqid)
    232{
    233	struct keystone_rproc *ksproc = rproc->priv;
    234
    235	if (WARN_ON(ksproc->kick_gpio < 0))
    236		return;
    237
    238	gpio_set_value(ksproc->kick_gpio, 1);
    239}
    240
    241/*
    242 * Custom function to translate a DSP device address (internal RAMs only) to a
    243 * kernel virtual address.  The DSPs can access their RAMs at either an internal
    244 * address visible only from a DSP, or at the SoC-level bus address. Both these
    245 * addresses need to be looked through for translation. The translated addresses
    246 * can be used either by the remoteproc core for loading (when using kernel
    247 * remoteproc loader), or by any rpmsg bus drivers.
    248 */
    249static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
    250{
    251	struct keystone_rproc *ksproc = rproc->priv;
    252	void __iomem *va = NULL;
    253	phys_addr_t bus_addr;
    254	u32 dev_addr, offset;
    255	size_t size;
    256	int i;
    257
    258	if (len == 0)
    259		return NULL;
    260
    261	for (i = 0; i < ksproc->num_mems; i++) {
    262		bus_addr = ksproc->mem[i].bus_addr;
    263		dev_addr = ksproc->mem[i].dev_addr;
    264		size = ksproc->mem[i].size;
    265
    266		if (da < KEYSTONE_RPROC_LOCAL_ADDRESS_MASK) {
    267			/* handle DSP-view addresses */
    268			if ((da >= dev_addr) &&
    269			    ((da + len) <= (dev_addr + size))) {
    270				offset = da - dev_addr;
    271				va = ksproc->mem[i].cpu_addr + offset;
    272				break;
    273			}
    274		} else {
    275			/* handle SoC-view addresses */
    276			if ((da >= bus_addr) &&
    277			    (da + len) <= (bus_addr + size)) {
    278				offset = da - bus_addr;
    279				va = ksproc->mem[i].cpu_addr + offset;
    280				break;
    281			}
    282		}
    283	}
    284
    285	return (__force void *)va;
    286}
    287
    288static const struct rproc_ops keystone_rproc_ops = {
    289	.start		= keystone_rproc_start,
    290	.stop		= keystone_rproc_stop,
    291	.kick		= keystone_rproc_kick,
    292	.da_to_va	= keystone_rproc_da_to_va,
    293};
    294
    295static int keystone_rproc_of_get_memories(struct platform_device *pdev,
    296					  struct keystone_rproc *ksproc)
    297{
    298	static const char * const mem_names[] = {"l2sram", "l1pram", "l1dram"};
    299	struct device *dev = &pdev->dev;
    300	struct resource *res;
    301	int num_mems = 0;
    302	int i;
    303
    304	num_mems = ARRAY_SIZE(mem_names);
    305	ksproc->mem = devm_kcalloc(ksproc->dev, num_mems,
    306				   sizeof(*ksproc->mem), GFP_KERNEL);
    307	if (!ksproc->mem)
    308		return -ENOMEM;
    309
    310	for (i = 0; i < num_mems; i++) {
    311		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
    312						   mem_names[i]);
    313		ksproc->mem[i].cpu_addr = devm_ioremap_resource(dev, res);
    314		if (IS_ERR(ksproc->mem[i].cpu_addr)) {
    315			dev_err(dev, "failed to parse and map %s memory\n",
    316				mem_names[i]);
    317			return PTR_ERR(ksproc->mem[i].cpu_addr);
    318		}
    319		ksproc->mem[i].bus_addr = res->start;
    320		ksproc->mem[i].dev_addr =
    321				res->start & KEYSTONE_RPROC_LOCAL_ADDRESS_MASK;
    322		ksproc->mem[i].size = resource_size(res);
    323
    324		/* zero out memories to start in a pristine state */
    325		memset((__force void *)ksproc->mem[i].cpu_addr, 0,
    326		       ksproc->mem[i].size);
    327	}
    328	ksproc->num_mems = num_mems;
    329
    330	return 0;
    331}
    332
    333static int keystone_rproc_of_get_dev_syscon(struct platform_device *pdev,
    334					    struct keystone_rproc *ksproc)
    335{
    336	struct device_node *np = pdev->dev.of_node;
    337	struct device *dev = &pdev->dev;
    338	int ret;
    339
    340	if (!of_property_read_bool(np, "ti,syscon-dev")) {
    341		dev_err(dev, "ti,syscon-dev property is absent\n");
    342		return -EINVAL;
    343	}
    344
    345	ksproc->dev_ctrl =
    346		syscon_regmap_lookup_by_phandle(np, "ti,syscon-dev");
    347	if (IS_ERR(ksproc->dev_ctrl)) {
    348		ret = PTR_ERR(ksproc->dev_ctrl);
    349		return ret;
    350	}
    351
    352	if (of_property_read_u32_index(np, "ti,syscon-dev", 1,
    353				       &ksproc->boot_offset)) {
    354		dev_err(dev, "couldn't read the boot register offset\n");
    355		return -EINVAL;
    356	}
    357
    358	return 0;
    359}
    360
    361static int keystone_rproc_probe(struct platform_device *pdev)
    362{
    363	struct device *dev = &pdev->dev;
    364	struct device_node *np = dev->of_node;
    365	struct keystone_rproc *ksproc;
    366	struct rproc *rproc;
    367	int dsp_id;
    368	char *fw_name = NULL;
    369	char *template = "keystone-dsp%d-fw";
    370	int name_len = 0;
    371	int ret = 0;
    372
    373	if (!np) {
    374		dev_err(dev, "only DT-based devices are supported\n");
    375		return -ENODEV;
    376	}
    377
    378	dsp_id = of_alias_get_id(np, "rproc");
    379	if (dsp_id < 0) {
    380		dev_warn(dev, "device does not have an alias id\n");
    381		return dsp_id;
    382	}
    383
    384	/* construct a custom default fw name - subject to change in future */
    385	name_len = strlen(template); /* assuming a single digit alias */
    386	fw_name = devm_kzalloc(dev, name_len, GFP_KERNEL);
    387	if (!fw_name)
    388		return -ENOMEM;
    389	snprintf(fw_name, name_len, template, dsp_id);
    390
    391	rproc = rproc_alloc(dev, dev_name(dev), &keystone_rproc_ops, fw_name,
    392			    sizeof(*ksproc));
    393	if (!rproc)
    394		return -ENOMEM;
    395
    396	rproc->has_iommu = false;
    397	ksproc = rproc->priv;
    398	ksproc->rproc = rproc;
    399	ksproc->dev = dev;
    400
    401	ret = keystone_rproc_of_get_dev_syscon(pdev, ksproc);
    402	if (ret)
    403		goto free_rproc;
    404
    405	ksproc->reset = devm_reset_control_get_exclusive(dev, NULL);
    406	if (IS_ERR(ksproc->reset)) {
    407		ret = PTR_ERR(ksproc->reset);
    408		goto free_rproc;
    409	}
    410
    411	/* enable clock for accessing DSP internal memories */
    412	pm_runtime_enable(dev);
    413	ret = pm_runtime_get_sync(dev);
    414	if (ret < 0) {
    415		dev_err(dev, "failed to enable clock, status = %d\n", ret);
    416		pm_runtime_put_noidle(dev);
    417		goto disable_rpm;
    418	}
    419
    420	ret = keystone_rproc_of_get_memories(pdev, ksproc);
    421	if (ret)
    422		goto disable_clk;
    423
    424	ksproc->irq_ring = platform_get_irq_byname(pdev, "vring");
    425	if (ksproc->irq_ring < 0) {
    426		ret = ksproc->irq_ring;
    427		goto disable_clk;
    428	}
    429
    430	ksproc->irq_fault = platform_get_irq_byname(pdev, "exception");
    431	if (ksproc->irq_fault < 0) {
    432		ret = ksproc->irq_fault;
    433		goto disable_clk;
    434	}
    435
    436	ksproc->kick_gpio = of_get_named_gpio_flags(np, "kick-gpios", 0, NULL);
    437	if (ksproc->kick_gpio < 0) {
    438		ret = ksproc->kick_gpio;
    439		dev_err(dev, "failed to get gpio for virtio kicks, status = %d\n",
    440			ret);
    441		goto disable_clk;
    442	}
    443
    444	if (of_reserved_mem_device_init(dev))
    445		dev_warn(dev, "device does not have specific CMA pool\n");
    446
    447	/* ensure the DSP is in reset before loading firmware */
    448	ret = reset_control_status(ksproc->reset);
    449	if (ret < 0) {
    450		dev_err(dev, "failed to get reset status, status = %d\n", ret);
    451		goto release_mem;
    452	} else if (ret == 0) {
    453		WARN(1, "device is not in reset\n");
    454		keystone_rproc_dsp_reset(ksproc);
    455	}
    456
    457	ret = rproc_add(rproc);
    458	if (ret) {
    459		dev_err(dev, "failed to add register device with remoteproc core, status = %d\n",
    460			ret);
    461		goto release_mem;
    462	}
    463
    464	platform_set_drvdata(pdev, ksproc);
    465
    466	return 0;
    467
    468release_mem:
    469	of_reserved_mem_device_release(dev);
    470disable_clk:
    471	pm_runtime_put_sync(dev);
    472disable_rpm:
    473	pm_runtime_disable(dev);
    474free_rproc:
    475	rproc_free(rproc);
    476	return ret;
    477}
    478
    479static int keystone_rproc_remove(struct platform_device *pdev)
    480{
    481	struct keystone_rproc *ksproc = platform_get_drvdata(pdev);
    482
    483	rproc_del(ksproc->rproc);
    484	pm_runtime_put_sync(&pdev->dev);
    485	pm_runtime_disable(&pdev->dev);
    486	rproc_free(ksproc->rproc);
    487	of_reserved_mem_device_release(&pdev->dev);
    488
    489	return 0;
    490}
    491
    492static const struct of_device_id keystone_rproc_of_match[] = {
    493	{ .compatible = "ti,k2hk-dsp", },
    494	{ .compatible = "ti,k2l-dsp", },
    495	{ .compatible = "ti,k2e-dsp", },
    496	{ .compatible = "ti,k2g-dsp", },
    497	{ /* sentinel */ },
    498};
    499MODULE_DEVICE_TABLE(of, keystone_rproc_of_match);
    500
    501static struct platform_driver keystone_rproc_driver = {
    502	.probe	= keystone_rproc_probe,
    503	.remove	= keystone_rproc_remove,
    504	.driver	= {
    505		.name = "keystone-rproc",
    506		.of_match_table = keystone_rproc_of_match,
    507	},
    508};
    509
    510module_platform_driver(keystone_rproc_driver);
    511
    512MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
    513MODULE_LICENSE("GPL v2");
    514MODULE_DESCRIPTION("TI Keystone DSP Remoteproc driver");