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

sp-platform.c (4933B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * AMD Secure Processor device driver
      4 *
      5 * Copyright (C) 2014,2018 Advanced Micro Devices, Inc.
      6 *
      7 * Author: Tom Lendacky <thomas.lendacky@amd.com>
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/kernel.h>
     12#include <linux/device.h>
     13#include <linux/platform_device.h>
     14#include <linux/ioport.h>
     15#include <linux/dma-mapping.h>
     16#include <linux/kthread.h>
     17#include <linux/sched.h>
     18#include <linux/interrupt.h>
     19#include <linux/spinlock.h>
     20#include <linux/delay.h>
     21#include <linux/ccp.h>
     22#include <linux/of.h>
     23#include <linux/of_address.h>
     24#include <linux/acpi.h>
     25
     26#include "ccp-dev.h"
     27
     28struct sp_platform {
     29	int coherent;
     30	unsigned int irq_count;
     31};
     32
     33static const struct sp_dev_vdata dev_vdata[] = {
     34	{
     35		.bar = 0,
     36#ifdef CONFIG_CRYPTO_DEV_SP_CCP
     37		.ccp_vdata = &ccpv3_platform,
     38#endif
     39	},
     40};
     41
     42#ifdef CONFIG_ACPI
     43static const struct acpi_device_id sp_acpi_match[] = {
     44	{ "AMDI0C00", (kernel_ulong_t)&dev_vdata[0] },
     45	{ },
     46};
     47MODULE_DEVICE_TABLE(acpi, sp_acpi_match);
     48#endif
     49
     50#ifdef CONFIG_OF
     51static const struct of_device_id sp_of_match[] = {
     52	{ .compatible = "amd,ccp-seattle-v1a",
     53	  .data = (const void *)&dev_vdata[0] },
     54	{ },
     55};
     56MODULE_DEVICE_TABLE(of, sp_of_match);
     57#endif
     58
     59static struct sp_dev_vdata *sp_get_of_version(struct platform_device *pdev)
     60{
     61#ifdef CONFIG_OF
     62	const struct of_device_id *match;
     63
     64	match = of_match_node(sp_of_match, pdev->dev.of_node);
     65	if (match && match->data)
     66		return (struct sp_dev_vdata *)match->data;
     67#endif
     68	return NULL;
     69}
     70
     71static struct sp_dev_vdata *sp_get_acpi_version(struct platform_device *pdev)
     72{
     73#ifdef CONFIG_ACPI
     74	const struct acpi_device_id *match;
     75
     76	match = acpi_match_device(sp_acpi_match, &pdev->dev);
     77	if (match && match->driver_data)
     78		return (struct sp_dev_vdata *)match->driver_data;
     79#endif
     80	return NULL;
     81}
     82
     83static int sp_get_irqs(struct sp_device *sp)
     84{
     85	struct sp_platform *sp_platform = sp->dev_specific;
     86	struct device *dev = sp->dev;
     87	struct platform_device *pdev = to_platform_device(dev);
     88	int ret;
     89
     90	sp_platform->irq_count = platform_irq_count(pdev);
     91
     92	ret = platform_get_irq(pdev, 0);
     93	if (ret < 0) {
     94		dev_notice(dev, "unable to get IRQ (%d)\n", ret);
     95		return ret;
     96	}
     97
     98	sp->psp_irq = ret;
     99	if (sp_platform->irq_count == 1) {
    100		sp->ccp_irq = ret;
    101	} else {
    102		ret = platform_get_irq(pdev, 1);
    103		if (ret < 0) {
    104			dev_notice(dev, "unable to get IRQ (%d)\n", ret);
    105			return ret;
    106		}
    107
    108		sp->ccp_irq = ret;
    109	}
    110
    111	return 0;
    112}
    113
    114static int sp_platform_probe(struct platform_device *pdev)
    115{
    116	struct sp_device *sp;
    117	struct sp_platform *sp_platform;
    118	struct device *dev = &pdev->dev;
    119	enum dev_dma_attr attr;
    120	int ret;
    121
    122	ret = -ENOMEM;
    123	sp = sp_alloc_struct(dev);
    124	if (!sp)
    125		goto e_err;
    126
    127	sp_platform = devm_kzalloc(dev, sizeof(*sp_platform), GFP_KERNEL);
    128	if (!sp_platform)
    129		goto e_err;
    130
    131	sp->dev_specific = sp_platform;
    132	sp->dev_vdata = pdev->dev.of_node ? sp_get_of_version(pdev)
    133					 : sp_get_acpi_version(pdev);
    134	if (!sp->dev_vdata) {
    135		ret = -ENODEV;
    136		dev_err(dev, "missing driver data\n");
    137		goto e_err;
    138	}
    139
    140	sp->io_map = devm_platform_ioremap_resource(pdev, 0);
    141	if (IS_ERR(sp->io_map)) {
    142		ret = PTR_ERR(sp->io_map);
    143		goto e_err;
    144	}
    145
    146	attr = device_get_dma_attr(dev);
    147	if (attr == DEV_DMA_NOT_SUPPORTED) {
    148		dev_err(dev, "DMA is not supported");
    149		goto e_err;
    150	}
    151
    152	sp_platform->coherent = (attr == DEV_DMA_COHERENT);
    153	if (sp_platform->coherent)
    154		sp->axcache = CACHE_WB_NO_ALLOC;
    155	else
    156		sp->axcache = CACHE_NONE;
    157
    158	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
    159	if (ret) {
    160		dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret);
    161		goto e_err;
    162	}
    163
    164	ret = sp_get_irqs(sp);
    165	if (ret)
    166		goto e_err;
    167
    168	dev_set_drvdata(dev, sp);
    169
    170	ret = sp_init(sp);
    171	if (ret)
    172		goto e_err;
    173
    174	dev_notice(dev, "enabled\n");
    175
    176	return 0;
    177
    178e_err:
    179	dev_notice(dev, "initialization failed\n");
    180	return ret;
    181}
    182
    183static int sp_platform_remove(struct platform_device *pdev)
    184{
    185	struct device *dev = &pdev->dev;
    186	struct sp_device *sp = dev_get_drvdata(dev);
    187
    188	sp_destroy(sp);
    189
    190	dev_notice(dev, "disabled\n");
    191
    192	return 0;
    193}
    194
    195#ifdef CONFIG_PM
    196static int sp_platform_suspend(struct platform_device *pdev,
    197				pm_message_t state)
    198{
    199	struct device *dev = &pdev->dev;
    200	struct sp_device *sp = dev_get_drvdata(dev);
    201
    202	return sp_suspend(sp);
    203}
    204
    205static int sp_platform_resume(struct platform_device *pdev)
    206{
    207	struct device *dev = &pdev->dev;
    208	struct sp_device *sp = dev_get_drvdata(dev);
    209
    210	return sp_resume(sp);
    211}
    212#endif
    213
    214static struct platform_driver sp_platform_driver = {
    215	.driver = {
    216		.name = "ccp",
    217#ifdef CONFIG_ACPI
    218		.acpi_match_table = sp_acpi_match,
    219#endif
    220#ifdef CONFIG_OF
    221		.of_match_table = sp_of_match,
    222#endif
    223	},
    224	.probe = sp_platform_probe,
    225	.remove = sp_platform_remove,
    226#ifdef CONFIG_PM
    227	.suspend = sp_platform_suspend,
    228	.resume = sp_platform_resume,
    229#endif
    230};
    231
    232int sp_platform_init(void)
    233{
    234	return platform_driver_register(&sp_platform_driver);
    235}
    236
    237void sp_platform_exit(void)
    238{
    239	platform_driver_unregister(&sp_platform_driver);
    240}