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

sprd-iommu.c (14509B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Unisoc IOMMU driver
      4 *
      5 * Copyright (C) 2020 Unisoc, Inc.
      6 * Author: Chunyan Zhang <chunyan.zhang@unisoc.com>
      7 */
      8
      9#include <linux/clk.h>
     10#include <linux/device.h>
     11#include <linux/dma-mapping.h>
     12#include <linux/errno.h>
     13#include <linux/iommu.h>
     14#include <linux/mfd/syscon.h>
     15#include <linux/module.h>
     16#include <linux/of_platform.h>
     17#include <linux/regmap.h>
     18#include <linux/slab.h>
     19
     20#define SPRD_IOMMU_PAGE_SHIFT	12
     21#define SPRD_IOMMU_PAGE_SIZE	SZ_4K
     22
     23#define SPRD_EX_CFG		0x0
     24#define SPRD_IOMMU_VAOR_BYPASS	BIT(4)
     25#define SPRD_IOMMU_GATE_EN	BIT(1)
     26#define SPRD_IOMMU_EN		BIT(0)
     27#define SPRD_EX_UPDATE		0x4
     28#define SPRD_EX_FIRST_VPN	0x8
     29#define SPRD_EX_VPN_RANGE	0xc
     30#define SPRD_EX_FIRST_PPN	0x10
     31#define SPRD_EX_DEFAULT_PPN	0x14
     32
     33#define SPRD_IOMMU_VERSION	0x0
     34#define SPRD_VERSION_MASK	GENMASK(15, 8)
     35#define SPRD_VERSION_SHIFT	0x8
     36#define SPRD_VAU_CFG		0x4
     37#define SPRD_VAU_UPDATE		0x8
     38#define SPRD_VAU_AUTH_CFG	0xc
     39#define SPRD_VAU_FIRST_PPN	0x10
     40#define SPRD_VAU_DEFAULT_PPN_RD	0x14
     41#define SPRD_VAU_DEFAULT_PPN_WR	0x18
     42#define SPRD_VAU_FIRST_VPN	0x1c
     43#define SPRD_VAU_VPN_RANGE	0x20
     44
     45enum sprd_iommu_version {
     46	SPRD_IOMMU_EX,
     47	SPRD_IOMMU_VAU,
     48};
     49
     50/*
     51 * struct sprd_iommu_device - high-level sprd IOMMU device representation,
     52 * including hardware information and configuration, also driver data, etc
     53 *
     54 * @ver: sprd IOMMU IP version
     55 * @prot_page_va: protect page base virtual address
     56 * @prot_page_pa: protect page base physical address, data would be
     57 *		  written to here while translation fault
     58 * @base: mapped base address for accessing registers
     59 * @dev: pointer to basic device structure
     60 * @iommu: IOMMU core representation
     61 * @group: IOMMU group
     62 * @eb: gate clock which controls IOMMU access
     63 */
     64struct sprd_iommu_device {
     65	enum sprd_iommu_version	ver;
     66	u32			*prot_page_va;
     67	dma_addr_t		prot_page_pa;
     68	void __iomem		*base;
     69	struct device		*dev;
     70	struct iommu_device	iommu;
     71	struct iommu_group	*group;
     72	struct clk		*eb;
     73};
     74
     75struct sprd_iommu_domain {
     76	spinlock_t		pgtlock; /* lock for page table */
     77	struct iommu_domain	domain;
     78	u32			*pgt_va; /* page table virtual address base */
     79	dma_addr_t		pgt_pa; /* page table physical address base */
     80	struct sprd_iommu_device	*sdev;
     81};
     82
     83static const struct iommu_ops sprd_iommu_ops;
     84
     85static struct sprd_iommu_domain *to_sprd_domain(struct iommu_domain *dom)
     86{
     87	return container_of(dom, struct sprd_iommu_domain, domain);
     88}
     89
     90static inline void
     91sprd_iommu_write(struct sprd_iommu_device *sdev, unsigned int reg, u32 val)
     92{
     93	writel_relaxed(val, sdev->base + reg);
     94}
     95
     96static inline u32
     97sprd_iommu_read(struct sprd_iommu_device *sdev, unsigned int reg)
     98{
     99	return readl_relaxed(sdev->base + reg);
    100}
    101
    102static inline void
    103sprd_iommu_update_bits(struct sprd_iommu_device *sdev, unsigned int reg,
    104		  u32 mask, u32 shift, u32 val)
    105{
    106	u32 t = sprd_iommu_read(sdev, reg);
    107
    108	t = (t & (~(mask << shift))) | ((val & mask) << shift);
    109	sprd_iommu_write(sdev, reg, t);
    110}
    111
    112static inline int
    113sprd_iommu_get_version(struct sprd_iommu_device *sdev)
    114{
    115	int ver = (sprd_iommu_read(sdev, SPRD_IOMMU_VERSION) &
    116		   SPRD_VERSION_MASK) >> SPRD_VERSION_SHIFT;
    117
    118	switch (ver) {
    119	case SPRD_IOMMU_EX:
    120	case SPRD_IOMMU_VAU:
    121		return ver;
    122	default:
    123		return -EINVAL;
    124	}
    125}
    126
    127static size_t
    128sprd_iommu_pgt_size(struct iommu_domain *domain)
    129{
    130	return ((domain->geometry.aperture_end -
    131		 domain->geometry.aperture_start + 1) >>
    132		SPRD_IOMMU_PAGE_SHIFT) * sizeof(u32);
    133}
    134
    135static struct iommu_domain *sprd_iommu_domain_alloc(unsigned int domain_type)
    136{
    137	struct sprd_iommu_domain *dom;
    138
    139	if (domain_type != IOMMU_DOMAIN_DMA && domain_type != IOMMU_DOMAIN_UNMANAGED)
    140		return NULL;
    141
    142	dom = kzalloc(sizeof(*dom), GFP_KERNEL);
    143	if (!dom)
    144		return NULL;
    145
    146	spin_lock_init(&dom->pgtlock);
    147
    148	dom->domain.geometry.aperture_start = 0;
    149	dom->domain.geometry.aperture_end = SZ_256M - 1;
    150
    151	return &dom->domain;
    152}
    153
    154static void sprd_iommu_domain_free(struct iommu_domain *domain)
    155{
    156	struct sprd_iommu_domain *dom = to_sprd_domain(domain);
    157
    158	kfree(dom);
    159}
    160
    161static void sprd_iommu_first_vpn(struct sprd_iommu_domain *dom)
    162{
    163	struct sprd_iommu_device *sdev = dom->sdev;
    164	u32 val;
    165	unsigned int reg;
    166
    167	if (sdev->ver == SPRD_IOMMU_EX)
    168		reg = SPRD_EX_FIRST_VPN;
    169	else
    170		reg = SPRD_VAU_FIRST_VPN;
    171
    172	val = dom->domain.geometry.aperture_start >> SPRD_IOMMU_PAGE_SHIFT;
    173	sprd_iommu_write(sdev, reg, val);
    174}
    175
    176static void sprd_iommu_vpn_range(struct sprd_iommu_domain *dom)
    177{
    178	struct sprd_iommu_device *sdev = dom->sdev;
    179	u32 val;
    180	unsigned int reg;
    181
    182	if (sdev->ver == SPRD_IOMMU_EX)
    183		reg = SPRD_EX_VPN_RANGE;
    184	else
    185		reg = SPRD_VAU_VPN_RANGE;
    186
    187	val = (dom->domain.geometry.aperture_end -
    188	       dom->domain.geometry.aperture_start) >> SPRD_IOMMU_PAGE_SHIFT;
    189	sprd_iommu_write(sdev, reg, val);
    190}
    191
    192static void sprd_iommu_first_ppn(struct sprd_iommu_domain *dom)
    193{
    194	u32 val = dom->pgt_pa >> SPRD_IOMMU_PAGE_SHIFT;
    195	struct sprd_iommu_device *sdev = dom->sdev;
    196	unsigned int reg;
    197
    198	if (sdev->ver == SPRD_IOMMU_EX)
    199		reg = SPRD_EX_FIRST_PPN;
    200	else
    201		reg = SPRD_VAU_FIRST_PPN;
    202
    203	sprd_iommu_write(sdev, reg, val);
    204}
    205
    206static void sprd_iommu_default_ppn(struct sprd_iommu_device *sdev)
    207{
    208	u32 val = sdev->prot_page_pa >> SPRD_IOMMU_PAGE_SHIFT;
    209
    210	if (sdev->ver == SPRD_IOMMU_EX) {
    211		sprd_iommu_write(sdev, SPRD_EX_DEFAULT_PPN, val);
    212	} else if (sdev->ver == SPRD_IOMMU_VAU) {
    213		sprd_iommu_write(sdev, SPRD_VAU_DEFAULT_PPN_RD, val);
    214		sprd_iommu_write(sdev, SPRD_VAU_DEFAULT_PPN_WR, val);
    215	}
    216}
    217
    218static void sprd_iommu_hw_en(struct sprd_iommu_device *sdev, bool en)
    219{
    220	unsigned int reg_cfg;
    221	u32 mask, val;
    222
    223	if (sdev->ver == SPRD_IOMMU_EX)
    224		reg_cfg = SPRD_EX_CFG;
    225	else
    226		reg_cfg = SPRD_VAU_CFG;
    227
    228	mask = SPRD_IOMMU_EN | SPRD_IOMMU_GATE_EN;
    229	val = en ? mask : 0;
    230	sprd_iommu_update_bits(sdev, reg_cfg, mask, 0, val);
    231}
    232
    233static int sprd_iommu_attach_device(struct iommu_domain *domain,
    234				    struct device *dev)
    235{
    236	struct sprd_iommu_device *sdev = dev_iommu_priv_get(dev);
    237	struct sprd_iommu_domain *dom = to_sprd_domain(domain);
    238	size_t pgt_size = sprd_iommu_pgt_size(domain);
    239
    240	if (dom->sdev) {
    241		pr_err("There's already a device attached to this domain.\n");
    242		return -EINVAL;
    243	}
    244
    245	dom->pgt_va = dma_alloc_coherent(sdev->dev, pgt_size, &dom->pgt_pa, GFP_KERNEL);
    246	if (!dom->pgt_va)
    247		return -ENOMEM;
    248
    249	dom->sdev = sdev;
    250
    251	sprd_iommu_first_ppn(dom);
    252	sprd_iommu_first_vpn(dom);
    253	sprd_iommu_vpn_range(dom);
    254	sprd_iommu_default_ppn(sdev);
    255	sprd_iommu_hw_en(sdev, true);
    256
    257	return 0;
    258}
    259
    260static void sprd_iommu_detach_device(struct iommu_domain *domain,
    261					     struct device *dev)
    262{
    263	struct sprd_iommu_domain *dom = to_sprd_domain(domain);
    264	struct sprd_iommu_device *sdev = dom->sdev;
    265	size_t pgt_size = sprd_iommu_pgt_size(domain);
    266
    267	if (!sdev)
    268		return;
    269
    270	dma_free_coherent(sdev->dev, pgt_size, dom->pgt_va, dom->pgt_pa);
    271	sprd_iommu_hw_en(sdev, false);
    272	dom->sdev = NULL;
    273}
    274
    275static int sprd_iommu_map(struct iommu_domain *domain, unsigned long iova,
    276			  phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
    277{
    278	struct sprd_iommu_domain *dom = to_sprd_domain(domain);
    279	unsigned int page_num = size >> SPRD_IOMMU_PAGE_SHIFT;
    280	unsigned long flags;
    281	unsigned int i;
    282	u32 *pgt_base_iova;
    283	u32 pabase = (u32)paddr;
    284	unsigned long start = domain->geometry.aperture_start;
    285	unsigned long end = domain->geometry.aperture_end;
    286
    287	if (!dom->sdev) {
    288		pr_err("No sprd_iommu_device attached to the domain\n");
    289		return -EINVAL;
    290	}
    291
    292	if (iova < start || (iova + size) > (end + 1)) {
    293		dev_err(dom->sdev->dev, "(iova(0x%lx) + size(%zx)) are not in the range!\n",
    294			iova, size);
    295		return -EINVAL;
    296	}
    297
    298	pgt_base_iova = dom->pgt_va + ((iova - start) >> SPRD_IOMMU_PAGE_SHIFT);
    299
    300	spin_lock_irqsave(&dom->pgtlock, flags);
    301	for (i = 0; i < page_num; i++) {
    302		pgt_base_iova[i] = pabase >> SPRD_IOMMU_PAGE_SHIFT;
    303		pabase += SPRD_IOMMU_PAGE_SIZE;
    304	}
    305	spin_unlock_irqrestore(&dom->pgtlock, flags);
    306
    307	return 0;
    308}
    309
    310static size_t sprd_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
    311			size_t size, struct iommu_iotlb_gather *iotlb_gather)
    312{
    313	struct sprd_iommu_domain *dom = to_sprd_domain(domain);
    314	unsigned long flags;
    315	u32 *pgt_base_iova;
    316	unsigned int page_num = size >> SPRD_IOMMU_PAGE_SHIFT;
    317	unsigned long start = domain->geometry.aperture_start;
    318	unsigned long end = domain->geometry.aperture_end;
    319
    320	if (iova < start || (iova + size) > (end + 1))
    321		return -EINVAL;
    322
    323	pgt_base_iova = dom->pgt_va + ((iova - start) >> SPRD_IOMMU_PAGE_SHIFT);
    324
    325	spin_lock_irqsave(&dom->pgtlock, flags);
    326	memset(pgt_base_iova, 0, page_num * sizeof(u32));
    327	spin_unlock_irqrestore(&dom->pgtlock, flags);
    328
    329	return 0;
    330}
    331
    332static void sprd_iommu_sync_map(struct iommu_domain *domain,
    333				unsigned long iova, size_t size)
    334{
    335	struct sprd_iommu_domain *dom = to_sprd_domain(domain);
    336	unsigned int reg;
    337
    338	if (dom->sdev->ver == SPRD_IOMMU_EX)
    339		reg = SPRD_EX_UPDATE;
    340	else
    341		reg = SPRD_VAU_UPDATE;
    342
    343	/* clear IOMMU TLB buffer after page table updated */
    344	sprd_iommu_write(dom->sdev, reg, 0xffffffff);
    345}
    346
    347static void sprd_iommu_sync(struct iommu_domain *domain,
    348			    struct iommu_iotlb_gather *iotlb_gather)
    349{
    350	sprd_iommu_sync_map(domain, 0, 0);
    351}
    352
    353static phys_addr_t sprd_iommu_iova_to_phys(struct iommu_domain *domain,
    354					   dma_addr_t iova)
    355{
    356	struct sprd_iommu_domain *dom = to_sprd_domain(domain);
    357	unsigned long flags;
    358	phys_addr_t pa;
    359	unsigned long start = domain->geometry.aperture_start;
    360	unsigned long end = domain->geometry.aperture_end;
    361
    362	if (WARN_ON(iova < start || iova > end))
    363		return 0;
    364
    365	spin_lock_irqsave(&dom->pgtlock, flags);
    366	pa = *(dom->pgt_va + ((iova - start) >> SPRD_IOMMU_PAGE_SHIFT));
    367	pa = (pa << SPRD_IOMMU_PAGE_SHIFT) + ((iova - start) & (SPRD_IOMMU_PAGE_SIZE - 1));
    368	spin_unlock_irqrestore(&dom->pgtlock, flags);
    369
    370	return pa;
    371}
    372
    373static struct iommu_device *sprd_iommu_probe_device(struct device *dev)
    374{
    375	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
    376	struct sprd_iommu_device *sdev;
    377
    378	if (!fwspec || fwspec->ops != &sprd_iommu_ops)
    379		return ERR_PTR(-ENODEV);
    380
    381	sdev = dev_iommu_priv_get(dev);
    382
    383	return &sdev->iommu;
    384}
    385
    386static void sprd_iommu_release_device(struct device *dev)
    387{
    388	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
    389
    390	if (!fwspec || fwspec->ops != &sprd_iommu_ops)
    391		return;
    392
    393	iommu_fwspec_free(dev);
    394}
    395
    396static struct iommu_group *sprd_iommu_device_group(struct device *dev)
    397{
    398	struct sprd_iommu_device *sdev = dev_iommu_priv_get(dev);
    399
    400	return iommu_group_ref_get(sdev->group);
    401}
    402
    403static int sprd_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)
    404{
    405	struct platform_device *pdev;
    406
    407	if (!dev_iommu_priv_get(dev)) {
    408		pdev = of_find_device_by_node(args->np);
    409		dev_iommu_priv_set(dev, platform_get_drvdata(pdev));
    410		platform_device_put(pdev);
    411	}
    412
    413	return 0;
    414}
    415
    416
    417static const struct iommu_ops sprd_iommu_ops = {
    418	.domain_alloc	= sprd_iommu_domain_alloc,
    419	.probe_device	= sprd_iommu_probe_device,
    420	.release_device	= sprd_iommu_release_device,
    421	.device_group	= sprd_iommu_device_group,
    422	.of_xlate	= sprd_iommu_of_xlate,
    423	.pgsize_bitmap	= ~0UL << SPRD_IOMMU_PAGE_SHIFT,
    424	.owner		= THIS_MODULE,
    425	.default_domain_ops = &(const struct iommu_domain_ops) {
    426		.attach_dev	= sprd_iommu_attach_device,
    427		.detach_dev	= sprd_iommu_detach_device,
    428		.map		= sprd_iommu_map,
    429		.unmap		= sprd_iommu_unmap,
    430		.iotlb_sync_map	= sprd_iommu_sync_map,
    431		.iotlb_sync	= sprd_iommu_sync,
    432		.iova_to_phys	= sprd_iommu_iova_to_phys,
    433		.free		= sprd_iommu_domain_free,
    434	}
    435};
    436
    437static const struct of_device_id sprd_iommu_of_match[] = {
    438	{ .compatible = "sprd,iommu-v1" },
    439	{ },
    440};
    441MODULE_DEVICE_TABLE(of, sprd_iommu_of_match);
    442
    443/*
    444 * Clock is not required, access to some of IOMMUs is controlled by gate
    445 * clk, enabled clocks for that kind of IOMMUs before accessing.
    446 * Return 0 for success or no clocks found.
    447 */
    448static int sprd_iommu_clk_enable(struct sprd_iommu_device *sdev)
    449{
    450	struct clk *eb;
    451
    452	eb = devm_clk_get_optional(sdev->dev, NULL);
    453	if (!eb)
    454		return 0;
    455
    456	if (IS_ERR(eb))
    457		return PTR_ERR(eb);
    458
    459	sdev->eb = eb;
    460	return clk_prepare_enable(eb);
    461}
    462
    463static void sprd_iommu_clk_disable(struct sprd_iommu_device *sdev)
    464{
    465	if (sdev->eb)
    466		clk_disable_unprepare(sdev->eb);
    467}
    468
    469static int sprd_iommu_probe(struct platform_device *pdev)
    470{
    471	struct sprd_iommu_device *sdev;
    472	struct device *dev = &pdev->dev;
    473	void __iomem *base;
    474	int ret;
    475
    476	sdev = devm_kzalloc(dev, sizeof(*sdev), GFP_KERNEL);
    477	if (!sdev)
    478		return -ENOMEM;
    479
    480	base = devm_platform_ioremap_resource(pdev, 0);
    481	if (IS_ERR(base)) {
    482		dev_err(dev, "Failed to get ioremap resource.\n");
    483		return PTR_ERR(base);
    484	}
    485	sdev->base = base;
    486
    487	sdev->prot_page_va = dma_alloc_coherent(dev, SPRD_IOMMU_PAGE_SIZE,
    488						&sdev->prot_page_pa, GFP_KERNEL);
    489	if (!sdev->prot_page_va)
    490		return -ENOMEM;
    491
    492	platform_set_drvdata(pdev, sdev);
    493	sdev->dev = dev;
    494
    495	/* All the client devices are in the same iommu-group */
    496	sdev->group = iommu_group_alloc();
    497	if (IS_ERR(sdev->group)) {
    498		ret = PTR_ERR(sdev->group);
    499		goto free_page;
    500	}
    501
    502	ret = iommu_device_sysfs_add(&sdev->iommu, dev, NULL, dev_name(dev));
    503	if (ret)
    504		goto put_group;
    505
    506	ret = iommu_device_register(&sdev->iommu, &sprd_iommu_ops, dev);
    507	if (ret)
    508		goto remove_sysfs;
    509
    510	if (!iommu_present(&platform_bus_type))
    511		bus_set_iommu(&platform_bus_type, &sprd_iommu_ops);
    512
    513	ret = sprd_iommu_clk_enable(sdev);
    514	if (ret)
    515		goto unregister_iommu;
    516
    517	ret = sprd_iommu_get_version(sdev);
    518	if (ret < 0) {
    519		dev_err(dev, "IOMMU version(%d) is invalid.\n", ret);
    520		goto disable_clk;
    521	}
    522	sdev->ver = ret;
    523
    524	return 0;
    525
    526disable_clk:
    527	sprd_iommu_clk_disable(sdev);
    528unregister_iommu:
    529	iommu_device_unregister(&sdev->iommu);
    530remove_sysfs:
    531	iommu_device_sysfs_remove(&sdev->iommu);
    532put_group:
    533	iommu_group_put(sdev->group);
    534free_page:
    535	dma_free_coherent(sdev->dev, SPRD_IOMMU_PAGE_SIZE, sdev->prot_page_va, sdev->prot_page_pa);
    536	return ret;
    537}
    538
    539static int sprd_iommu_remove(struct platform_device *pdev)
    540{
    541	struct sprd_iommu_device *sdev = platform_get_drvdata(pdev);
    542
    543	dma_free_coherent(sdev->dev, SPRD_IOMMU_PAGE_SIZE, sdev->prot_page_va, sdev->prot_page_pa);
    544
    545	iommu_group_put(sdev->group);
    546	sdev->group = NULL;
    547
    548	bus_set_iommu(&platform_bus_type, NULL);
    549
    550	platform_set_drvdata(pdev, NULL);
    551	iommu_device_sysfs_remove(&sdev->iommu);
    552	iommu_device_unregister(&sdev->iommu);
    553
    554	return 0;
    555}
    556
    557static struct platform_driver sprd_iommu_driver = {
    558	.driver	= {
    559		.name		= "sprd-iommu",
    560		.of_match_table	= sprd_iommu_of_match,
    561		.suppress_bind_attrs = true,
    562	},
    563	.probe	= sprd_iommu_probe,
    564	.remove	= sprd_iommu_remove,
    565};
    566module_platform_driver(sprd_iommu_driver);
    567
    568MODULE_DESCRIPTION("IOMMU driver for Unisoc SoCs");
    569MODULE_ALIAS("platform:sprd-iommu");
    570MODULE_LICENSE("GPL");