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

vic.c (12461B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2015, NVIDIA Corporation.
      4 */
      5
      6#include <linux/clk.h>
      7#include <linux/delay.h>
      8#include <linux/dma-mapping.h>
      9#include <linux/host1x.h>
     10#include <linux/iommu.h>
     11#include <linux/module.h>
     12#include <linux/of.h>
     13#include <linux/of_device.h>
     14#include <linux/of_platform.h>
     15#include <linux/platform_device.h>
     16#include <linux/pm_runtime.h>
     17#include <linux/reset.h>
     18
     19#include <soc/tegra/pmc.h>
     20
     21#include "drm.h"
     22#include "falcon.h"
     23#include "vic.h"
     24
     25struct vic_config {
     26	const char *firmware;
     27	unsigned int version;
     28	bool supports_sid;
     29};
     30
     31struct vic {
     32	struct falcon falcon;
     33
     34	void __iomem *regs;
     35	struct tegra_drm_client client;
     36	struct host1x_channel *channel;
     37	struct device *dev;
     38	struct clk *clk;
     39	struct reset_control *rst;
     40
     41	/* Platform configuration */
     42	const struct vic_config *config;
     43};
     44
     45static inline struct vic *to_vic(struct tegra_drm_client *client)
     46{
     47	return container_of(client, struct vic, client);
     48}
     49
     50static void vic_writel(struct vic *vic, u32 value, unsigned int offset)
     51{
     52	writel(value, vic->regs + offset);
     53}
     54
     55static int vic_boot(struct vic *vic)
     56{
     57#ifdef CONFIG_IOMMU_API
     58	struct iommu_fwspec *spec = dev_iommu_fwspec_get(vic->dev);
     59#endif
     60	u32 fce_ucode_size, fce_bin_data_offset;
     61	void *hdr;
     62	int err = 0;
     63
     64#ifdef CONFIG_IOMMU_API
     65	if (vic->config->supports_sid && spec) {
     66		u32 value;
     67
     68		value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) |
     69			TRANSCFG_ATT(0, TRANSCFG_SID_HW);
     70		vic_writel(vic, value, VIC_TFBIF_TRANSCFG);
     71
     72		if (spec->num_ids > 0) {
     73			value = spec->ids[0] & 0xffff;
     74
     75			/*
     76			 * STREAMID0 is used for input/output buffers.
     77			 * Initialize it to SID_VIC in case context isolation
     78			 * is not enabled, and SID_VIC is used for both firmware
     79			 * and data buffers.
     80			 *
     81			 * If context isolation is enabled, it will be
     82			 * overridden by the SETSTREAMID opcode as part of
     83			 * each job.
     84			 */
     85			vic_writel(vic, value, VIC_THI_STREAMID0);
     86
     87			/* STREAMID1 is used for firmware loading. */
     88			vic_writel(vic, value, VIC_THI_STREAMID1);
     89		}
     90	}
     91#endif
     92
     93	/* setup clockgating registers */
     94	vic_writel(vic, CG_IDLE_CG_DLY_CNT(4) |
     95			CG_IDLE_CG_EN |
     96			CG_WAKEUP_DLY_CNT(4),
     97		   NV_PVIC_MISC_PRI_VIC_CG);
     98
     99	err = falcon_boot(&vic->falcon);
    100	if (err < 0)
    101		return err;
    102
    103	hdr = vic->falcon.firmware.virt;
    104	fce_bin_data_offset = *(u32 *)(hdr + VIC_UCODE_FCE_DATA_OFFSET);
    105
    106	/* Old VIC firmware needs kernel help with setting up FCE microcode. */
    107	if (fce_bin_data_offset != 0x0 && fce_bin_data_offset != 0xa5a5a5a5) {
    108		hdr = vic->falcon.firmware.virt +
    109			*(u32 *)(hdr + VIC_UCODE_FCE_HEADER_OFFSET);
    110		fce_ucode_size = *(u32 *)(hdr + FCE_UCODE_SIZE_OFFSET);
    111
    112		falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_SIZE,
    113				      fce_ucode_size);
    114		falcon_execute_method(
    115			&vic->falcon, VIC_SET_FCE_UCODE_OFFSET,
    116			(vic->falcon.firmware.iova + fce_bin_data_offset) >> 8);
    117	}
    118
    119	err = falcon_wait_idle(&vic->falcon);
    120	if (err < 0) {
    121		dev_err(vic->dev,
    122			"failed to set application ID and FCE base\n");
    123		return err;
    124	}
    125
    126	return 0;
    127}
    128
    129static int vic_init(struct host1x_client *client)
    130{
    131	struct tegra_drm_client *drm = host1x_to_drm_client(client);
    132	struct drm_device *dev = dev_get_drvdata(client->host);
    133	struct tegra_drm *tegra = dev->dev_private;
    134	struct vic *vic = to_vic(drm);
    135	int err;
    136
    137	err = host1x_client_iommu_attach(client);
    138	if (err < 0 && err != -ENODEV) {
    139		dev_err(vic->dev, "failed to attach to domain: %d\n", err);
    140		return err;
    141	}
    142
    143	vic->channel = host1x_channel_request(client);
    144	if (!vic->channel) {
    145		err = -ENOMEM;
    146		goto detach;
    147	}
    148
    149	client->syncpts[0] = host1x_syncpt_request(client, 0);
    150	if (!client->syncpts[0]) {
    151		err = -ENOMEM;
    152		goto free_channel;
    153	}
    154
    155	pm_runtime_enable(client->dev);
    156	pm_runtime_use_autosuspend(client->dev);
    157	pm_runtime_set_autosuspend_delay(client->dev, 500);
    158
    159	err = tegra_drm_register_client(tegra, drm);
    160	if (err < 0)
    161		goto disable_rpm;
    162
    163	/*
    164	 * Inherit the DMA parameters (such as maximum segment size) from the
    165	 * parent host1x device.
    166	 */
    167	client->dev->dma_parms = client->host->dma_parms;
    168
    169	return 0;
    170
    171disable_rpm:
    172	pm_runtime_dont_use_autosuspend(client->dev);
    173	pm_runtime_force_suspend(client->dev);
    174
    175	host1x_syncpt_put(client->syncpts[0]);
    176free_channel:
    177	host1x_channel_put(vic->channel);
    178detach:
    179	host1x_client_iommu_detach(client);
    180
    181	return err;
    182}
    183
    184static int vic_exit(struct host1x_client *client)
    185{
    186	struct tegra_drm_client *drm = host1x_to_drm_client(client);
    187	struct drm_device *dev = dev_get_drvdata(client->host);
    188	struct tegra_drm *tegra = dev->dev_private;
    189	struct vic *vic = to_vic(drm);
    190	int err;
    191
    192	/* avoid a dangling pointer just in case this disappears */
    193	client->dev->dma_parms = NULL;
    194
    195	err = tegra_drm_unregister_client(tegra, drm);
    196	if (err < 0)
    197		return err;
    198
    199	pm_runtime_dont_use_autosuspend(client->dev);
    200	pm_runtime_force_suspend(client->dev);
    201
    202	host1x_syncpt_put(client->syncpts[0]);
    203	host1x_channel_put(vic->channel);
    204	host1x_client_iommu_detach(client);
    205
    206	vic->channel = NULL;
    207
    208	if (client->group) {
    209		dma_unmap_single(vic->dev, vic->falcon.firmware.phys,
    210				 vic->falcon.firmware.size, DMA_TO_DEVICE);
    211		tegra_drm_free(tegra, vic->falcon.firmware.size,
    212			       vic->falcon.firmware.virt,
    213			       vic->falcon.firmware.iova);
    214	} else {
    215		dma_free_coherent(vic->dev, vic->falcon.firmware.size,
    216				  vic->falcon.firmware.virt,
    217				  vic->falcon.firmware.iova);
    218	}
    219
    220	return 0;
    221}
    222
    223static const struct host1x_client_ops vic_client_ops = {
    224	.init = vic_init,
    225	.exit = vic_exit,
    226};
    227
    228static int vic_load_firmware(struct vic *vic)
    229{
    230	struct host1x_client *client = &vic->client.base;
    231	struct tegra_drm *tegra = vic->client.drm;
    232	dma_addr_t iova;
    233	size_t size;
    234	void *virt;
    235	int err;
    236
    237	if (vic->falcon.firmware.virt)
    238		return 0;
    239
    240	err = falcon_read_firmware(&vic->falcon, vic->config->firmware);
    241	if (err < 0)
    242		return err;
    243
    244	size = vic->falcon.firmware.size;
    245
    246	if (!client->group) {
    247		virt = dma_alloc_coherent(vic->dev, size, &iova, GFP_KERNEL);
    248		if (!virt)
    249			return -ENOMEM;
    250	} else {
    251		virt = tegra_drm_alloc(tegra, size, &iova);
    252		if (IS_ERR(virt))
    253			return PTR_ERR(virt);
    254	}
    255
    256	vic->falcon.firmware.virt = virt;
    257	vic->falcon.firmware.iova = iova;
    258
    259	err = falcon_load_firmware(&vic->falcon);
    260	if (err < 0)
    261		goto cleanup;
    262
    263	/*
    264	 * In this case we have received an IOVA from the shared domain, so we
    265	 * need to make sure to get the physical address so that the DMA API
    266	 * knows what memory pages to flush the cache for.
    267	 */
    268	if (client->group) {
    269		dma_addr_t phys;
    270
    271		phys = dma_map_single(vic->dev, virt, size, DMA_TO_DEVICE);
    272
    273		err = dma_mapping_error(vic->dev, phys);
    274		if (err < 0)
    275			goto cleanup;
    276
    277		vic->falcon.firmware.phys = phys;
    278	}
    279
    280	return 0;
    281
    282cleanup:
    283	if (!client->group)
    284		dma_free_coherent(vic->dev, size, virt, iova);
    285	else
    286		tegra_drm_free(tegra, size, virt, iova);
    287
    288	return err;
    289}
    290
    291
    292static int vic_runtime_resume(struct device *dev)
    293{
    294	struct vic *vic = dev_get_drvdata(dev);
    295	int err;
    296
    297	err = clk_prepare_enable(vic->clk);
    298	if (err < 0)
    299		return err;
    300
    301	usleep_range(10, 20);
    302
    303	err = reset_control_deassert(vic->rst);
    304	if (err < 0)
    305		goto disable;
    306
    307	usleep_range(10, 20);
    308
    309	err = vic_load_firmware(vic);
    310	if (err < 0)
    311		goto assert;
    312
    313	err = vic_boot(vic);
    314	if (err < 0)
    315		goto assert;
    316
    317	return 0;
    318
    319assert:
    320	reset_control_assert(vic->rst);
    321disable:
    322	clk_disable_unprepare(vic->clk);
    323	return err;
    324}
    325
    326static int vic_runtime_suspend(struct device *dev)
    327{
    328	struct vic *vic = dev_get_drvdata(dev);
    329	int err;
    330
    331	host1x_channel_stop(vic->channel);
    332
    333	err = reset_control_assert(vic->rst);
    334	if (err < 0)
    335		return err;
    336
    337	usleep_range(2000, 4000);
    338
    339	clk_disable_unprepare(vic->clk);
    340
    341	return 0;
    342}
    343
    344static int vic_open_channel(struct tegra_drm_client *client,
    345			    struct tegra_drm_context *context)
    346{
    347	struct vic *vic = to_vic(client);
    348
    349	context->channel = host1x_channel_get(vic->channel);
    350	if (!context->channel)
    351		return -ENOMEM;
    352
    353	return 0;
    354}
    355
    356static void vic_close_channel(struct tegra_drm_context *context)
    357{
    358	host1x_channel_put(context->channel);
    359}
    360
    361static const struct tegra_drm_client_ops vic_ops = {
    362	.open_channel = vic_open_channel,
    363	.close_channel = vic_close_channel,
    364	.submit = tegra_drm_submit,
    365};
    366
    367#define NVIDIA_TEGRA_124_VIC_FIRMWARE "nvidia/tegra124/vic03_ucode.bin"
    368
    369static const struct vic_config vic_t124_config = {
    370	.firmware = NVIDIA_TEGRA_124_VIC_FIRMWARE,
    371	.version = 0x40,
    372	.supports_sid = false,
    373};
    374
    375#define NVIDIA_TEGRA_210_VIC_FIRMWARE "nvidia/tegra210/vic04_ucode.bin"
    376
    377static const struct vic_config vic_t210_config = {
    378	.firmware = NVIDIA_TEGRA_210_VIC_FIRMWARE,
    379	.version = 0x21,
    380	.supports_sid = false,
    381};
    382
    383#define NVIDIA_TEGRA_186_VIC_FIRMWARE "nvidia/tegra186/vic04_ucode.bin"
    384
    385static const struct vic_config vic_t186_config = {
    386	.firmware = NVIDIA_TEGRA_186_VIC_FIRMWARE,
    387	.version = 0x18,
    388	.supports_sid = true,
    389};
    390
    391#define NVIDIA_TEGRA_194_VIC_FIRMWARE "nvidia/tegra194/vic.bin"
    392
    393static const struct vic_config vic_t194_config = {
    394	.firmware = NVIDIA_TEGRA_194_VIC_FIRMWARE,
    395	.version = 0x19,
    396	.supports_sid = true,
    397};
    398
    399static const struct of_device_id tegra_vic_of_match[] = {
    400	{ .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config },
    401	{ .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config },
    402	{ .compatible = "nvidia,tegra186-vic", .data = &vic_t186_config },
    403	{ .compatible = "nvidia,tegra194-vic", .data = &vic_t194_config },
    404	{ },
    405};
    406MODULE_DEVICE_TABLE(of, tegra_vic_of_match);
    407
    408static int vic_probe(struct platform_device *pdev)
    409{
    410	struct device *dev = &pdev->dev;
    411	struct host1x_syncpt **syncpts;
    412	struct resource *regs;
    413	struct vic *vic;
    414	int err;
    415
    416	/* inherit DMA mask from host1x parent */
    417	err = dma_coerce_mask_and_coherent(dev, *dev->parent->dma_mask);
    418	if (err < 0) {
    419		dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err);
    420		return err;
    421	}
    422
    423	vic = devm_kzalloc(dev, sizeof(*vic), GFP_KERNEL);
    424	if (!vic)
    425		return -ENOMEM;
    426
    427	vic->config = of_device_get_match_data(dev);
    428
    429	syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL);
    430	if (!syncpts)
    431		return -ENOMEM;
    432
    433	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    434	if (!regs) {
    435		dev_err(&pdev->dev, "failed to get registers\n");
    436		return -ENXIO;
    437	}
    438
    439	vic->regs = devm_ioremap_resource(dev, regs);
    440	if (IS_ERR(vic->regs))
    441		return PTR_ERR(vic->regs);
    442
    443	vic->clk = devm_clk_get(dev, NULL);
    444	if (IS_ERR(vic->clk)) {
    445		dev_err(&pdev->dev, "failed to get clock\n");
    446		return PTR_ERR(vic->clk);
    447	}
    448
    449	err = clk_set_rate(vic->clk, ULONG_MAX);
    450	if (err < 0) {
    451		dev_err(&pdev->dev, "failed to set clock rate\n");
    452		return err;
    453	}
    454
    455	if (!dev->pm_domain) {
    456		vic->rst = devm_reset_control_get(dev, "vic");
    457		if (IS_ERR(vic->rst)) {
    458			dev_err(&pdev->dev, "failed to get reset\n");
    459			return PTR_ERR(vic->rst);
    460		}
    461	}
    462
    463	vic->falcon.dev = dev;
    464	vic->falcon.regs = vic->regs;
    465
    466	err = falcon_init(&vic->falcon);
    467	if (err < 0)
    468		return err;
    469
    470	platform_set_drvdata(pdev, vic);
    471
    472	INIT_LIST_HEAD(&vic->client.base.list);
    473	vic->client.base.ops = &vic_client_ops;
    474	vic->client.base.dev = dev;
    475	vic->client.base.class = HOST1X_CLASS_VIC;
    476	vic->client.base.syncpts = syncpts;
    477	vic->client.base.num_syncpts = 1;
    478	vic->dev = dev;
    479
    480	INIT_LIST_HEAD(&vic->client.list);
    481	vic->client.version = vic->config->version;
    482	vic->client.ops = &vic_ops;
    483
    484	err = host1x_client_register(&vic->client.base);
    485	if (err < 0) {
    486		dev_err(dev, "failed to register host1x client: %d\n", err);
    487		goto exit_falcon;
    488	}
    489
    490	return 0;
    491
    492exit_falcon:
    493	falcon_exit(&vic->falcon);
    494
    495	return err;
    496}
    497
    498static int vic_remove(struct platform_device *pdev)
    499{
    500	struct vic *vic = platform_get_drvdata(pdev);
    501	int err;
    502
    503	err = host1x_client_unregister(&vic->client.base);
    504	if (err < 0) {
    505		dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
    506			err);
    507		return err;
    508	}
    509
    510	falcon_exit(&vic->falcon);
    511
    512	return 0;
    513}
    514
    515static const struct dev_pm_ops vic_pm_ops = {
    516	RUNTIME_PM_OPS(vic_runtime_suspend, vic_runtime_resume, NULL)
    517	SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
    518};
    519
    520struct platform_driver tegra_vic_driver = {
    521	.driver = {
    522		.name = "tegra-vic",
    523		.of_match_table = tegra_vic_of_match,
    524		.pm = &vic_pm_ops
    525	},
    526	.probe = vic_probe,
    527	.remove = vic_remove,
    528};
    529
    530#if IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC)
    531MODULE_FIRMWARE(NVIDIA_TEGRA_124_VIC_FIRMWARE);
    532#endif
    533#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
    534MODULE_FIRMWARE(NVIDIA_TEGRA_210_VIC_FIRMWARE);
    535#endif
    536#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
    537MODULE_FIRMWARE(NVIDIA_TEGRA_186_VIC_FIRMWARE);
    538#endif
    539#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
    540MODULE_FIRMWARE(NVIDIA_TEGRA_194_VIC_FIRMWARE);
    541#endif