162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright © 2006-2014 Intel Corporation.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Authors: David Woodhouse <dwmw2@infradead.org>,
662306a36Sopenharmony_ci *          Ashok Raj <ashok.raj@intel.com>,
762306a36Sopenharmony_ci *          Shaohua Li <shaohua.li@intel.com>,
862306a36Sopenharmony_ci *          Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>,
962306a36Sopenharmony_ci *          Fenghua Yu <fenghua.yu@intel.com>
1062306a36Sopenharmony_ci *          Joerg Roedel <jroedel@suse.de>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define pr_fmt(fmt)     "DMAR: " fmt
1462306a36Sopenharmony_ci#define dev_fmt(fmt)    pr_fmt(fmt)
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/crash_dump.h>
1762306a36Sopenharmony_ci#include <linux/dma-direct.h>
1862306a36Sopenharmony_ci#include <linux/dmi.h>
1962306a36Sopenharmony_ci#include <linux/memory.h>
2062306a36Sopenharmony_ci#include <linux/pci.h>
2162306a36Sopenharmony_ci#include <linux/pci-ats.h>
2262306a36Sopenharmony_ci#include <linux/spinlock.h>
2362306a36Sopenharmony_ci#include <linux/syscore_ops.h>
2462306a36Sopenharmony_ci#include <linux/tboot.h>
2562306a36Sopenharmony_ci#include <uapi/linux/iommufd.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "iommu.h"
2862306a36Sopenharmony_ci#include "../dma-iommu.h"
2962306a36Sopenharmony_ci#include "../irq_remapping.h"
3062306a36Sopenharmony_ci#include "../iommu-sva.h"
3162306a36Sopenharmony_ci#include "pasid.h"
3262306a36Sopenharmony_ci#include "cap_audit.h"
3362306a36Sopenharmony_ci#include "perfmon.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define ROOT_SIZE		VTD_PAGE_SIZE
3662306a36Sopenharmony_ci#define CONTEXT_SIZE		VTD_PAGE_SIZE
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
3962306a36Sopenharmony_ci#define IS_USB_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_SERIAL_USB)
4062306a36Sopenharmony_ci#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
4162306a36Sopenharmony_ci#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define IOAPIC_RANGE_START	(0xfee00000)
4462306a36Sopenharmony_ci#define IOAPIC_RANGE_END	(0xfeefffff)
4562306a36Sopenharmony_ci#define IOVA_START_ADDR		(0x1000)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define DEFAULT_DOMAIN_ADDRESS_WIDTH 57
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define MAX_AGAW_WIDTH 64
5062306a36Sopenharmony_ci#define MAX_AGAW_PFN_WIDTH	(MAX_AGAW_WIDTH - VTD_PAGE_SHIFT)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define __DOMAIN_MAX_PFN(gaw)  ((((uint64_t)1) << ((gaw) - VTD_PAGE_SHIFT)) - 1)
5362306a36Sopenharmony_ci#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << (gaw)) - 1)
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
5662306a36Sopenharmony_ci   to match. That way, we can use 'unsigned long' for PFNs with impunity. */
5762306a36Sopenharmony_ci#define DOMAIN_MAX_PFN(gaw)	((unsigned long) min_t(uint64_t, \
5862306a36Sopenharmony_ci				__DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
5962306a36Sopenharmony_ci#define DOMAIN_MAX_ADDR(gaw)	(((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* IO virtual address start page frame number */
6262306a36Sopenharmony_ci#define IOVA_START_PFN		(1)
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define IOVA_PFN(addr)		((addr) >> PAGE_SHIFT)
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* page table handling */
6762306a36Sopenharmony_ci#define LEVEL_STRIDE		(9)
6862306a36Sopenharmony_ci#define LEVEL_MASK		(((u64)1 << LEVEL_STRIDE) - 1)
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic inline int agaw_to_level(int agaw)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	return agaw + 2;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic inline int agaw_to_width(int agaw)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	return min_t(int, 30 + agaw * LEVEL_STRIDE, MAX_AGAW_WIDTH);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic inline int width_to_agaw(int width)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	return DIV_ROUND_UP(width - 30, LEVEL_STRIDE);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic inline unsigned int level_to_offset_bits(int level)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	return (level - 1) * LEVEL_STRIDE;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic inline int pfn_level_offset(u64 pfn, int level)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic inline u64 level_mask(int level)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	return -1ULL << level_to_offset_bits(level);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic inline u64 level_size(int level)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	return 1ULL << level_to_offset_bits(level);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic inline u64 align_to_level(u64 pfn, int level)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	return (pfn + level_size(level) - 1) & level_mask(level);
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic inline unsigned long lvl_to_nr_pages(unsigned int lvl)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	return 1UL << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
11662306a36Sopenharmony_ci   are never going to work. */
11762306a36Sopenharmony_cistatic inline unsigned long mm_to_dma_pfn_start(unsigned long mm_pfn)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_cistatic inline unsigned long mm_to_dma_pfn_end(unsigned long mm_pfn)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	return ((mm_pfn + 1) << (PAGE_SHIFT - VTD_PAGE_SHIFT)) - 1;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_cistatic inline unsigned long page_to_dma_pfn(struct page *pg)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	return mm_to_dma_pfn_start(page_to_pfn(pg));
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_cistatic inline unsigned long virt_to_dma_pfn(void *p)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	return page_to_dma_pfn(virt_to_page(p));
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic void __init check_tylersburg_isoch(void);
13562306a36Sopenharmony_cistatic int rwbf_quirk;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/*
13862306a36Sopenharmony_ci * set to 1 to panic kernel if can't successfully enable VT-d
13962306a36Sopenharmony_ci * (used when kernel is launched w/ TXT)
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_cistatic int force_on = 0;
14262306a36Sopenharmony_cistatic int intel_iommu_tboot_noforce;
14362306a36Sopenharmony_cistatic int no_platform_optin;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci/*
14862306a36Sopenharmony_ci * Take a root_entry and return the Lower Context Table Pointer (LCTP)
14962306a36Sopenharmony_ci * if marked present.
15062306a36Sopenharmony_ci */
15162306a36Sopenharmony_cistatic phys_addr_t root_entry_lctp(struct root_entry *re)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	if (!(re->lo & 1))
15462306a36Sopenharmony_ci		return 0;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	return re->lo & VTD_PAGE_MASK;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/*
16062306a36Sopenharmony_ci * Take a root_entry and return the Upper Context Table Pointer (UCTP)
16162306a36Sopenharmony_ci * if marked present.
16262306a36Sopenharmony_ci */
16362306a36Sopenharmony_cistatic phys_addr_t root_entry_uctp(struct root_entry *re)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	if (!(re->hi & 1))
16662306a36Sopenharmony_ci		return 0;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	return re->hi & VTD_PAGE_MASK;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic inline void context_set_present(struct context_entry *context)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	context->lo |= 1;
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic inline void context_set_fault_enable(struct context_entry *context)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	context->lo &= (((u64)-1) << 2) | 1;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic inline void context_set_translation_type(struct context_entry *context,
18262306a36Sopenharmony_ci						unsigned long value)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	context->lo &= (((u64)-1) << 4) | 3;
18562306a36Sopenharmony_ci	context->lo |= (value & 3) << 2;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic inline void context_set_address_root(struct context_entry *context,
18962306a36Sopenharmony_ci					    unsigned long value)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	context->lo &= ~VTD_PAGE_MASK;
19262306a36Sopenharmony_ci	context->lo |= value & VTD_PAGE_MASK;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic inline void context_set_address_width(struct context_entry *context,
19662306a36Sopenharmony_ci					     unsigned long value)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	context->hi |= value & 7;
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic inline void context_set_domain_id(struct context_entry *context,
20262306a36Sopenharmony_ci					 unsigned long value)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	context->hi |= (value & ((1 << 16) - 1)) << 8;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic inline void context_set_pasid(struct context_entry *context)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	context->lo |= CONTEXT_PASIDE;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic inline int context_domain_id(struct context_entry *c)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	return((c->hi >> 8) & 0xffff);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic inline void context_clear_entry(struct context_entry *context)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	context->lo = 0;
22062306a36Sopenharmony_ci	context->hi = 0;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic inline bool context_copied(struct intel_iommu *iommu, u8 bus, u8 devfn)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	if (!iommu->copied_tables)
22662306a36Sopenharmony_ci		return false;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	return test_bit(((long)bus << 8) | devfn, iommu->copied_tables);
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic inline void
23262306a36Sopenharmony_ciset_context_copied(struct intel_iommu *iommu, u8 bus, u8 devfn)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	set_bit(((long)bus << 8) | devfn, iommu->copied_tables);
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic inline void
23862306a36Sopenharmony_ciclear_context_copied(struct intel_iommu *iommu, u8 bus, u8 devfn)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	clear_bit(((long)bus << 8) | devfn, iommu->copied_tables);
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci/*
24462306a36Sopenharmony_ci * This domain is a statically identity mapping domain.
24562306a36Sopenharmony_ci *	1. This domain creats a static 1:1 mapping to all usable memory.
24662306a36Sopenharmony_ci * 	2. It maps to each iommu if successful.
24762306a36Sopenharmony_ci *	3. Each iommu mapps to this domain if successful.
24862306a36Sopenharmony_ci */
24962306a36Sopenharmony_cistatic struct dmar_domain *si_domain;
25062306a36Sopenharmony_cistatic int hw_pass_through = 1;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistruct dmar_rmrr_unit {
25362306a36Sopenharmony_ci	struct list_head list;		/* list of rmrr units	*/
25462306a36Sopenharmony_ci	struct acpi_dmar_header *hdr;	/* ACPI header		*/
25562306a36Sopenharmony_ci	u64	base_address;		/* reserved base address*/
25662306a36Sopenharmony_ci	u64	end_address;		/* reserved end address */
25762306a36Sopenharmony_ci	struct dmar_dev_scope *devices;	/* target devices */
25862306a36Sopenharmony_ci	int	devices_cnt;		/* target device count */
25962306a36Sopenharmony_ci};
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistruct dmar_atsr_unit {
26262306a36Sopenharmony_ci	struct list_head list;		/* list of ATSR units */
26362306a36Sopenharmony_ci	struct acpi_dmar_header *hdr;	/* ACPI header */
26462306a36Sopenharmony_ci	struct dmar_dev_scope *devices;	/* target devices */
26562306a36Sopenharmony_ci	int devices_cnt;		/* target device count */
26662306a36Sopenharmony_ci	u8 include_all:1;		/* include all ports */
26762306a36Sopenharmony_ci};
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistruct dmar_satc_unit {
27062306a36Sopenharmony_ci	struct list_head list;		/* list of SATC units */
27162306a36Sopenharmony_ci	struct acpi_dmar_header *hdr;	/* ACPI header */
27262306a36Sopenharmony_ci	struct dmar_dev_scope *devices;	/* target devices */
27362306a36Sopenharmony_ci	struct intel_iommu *iommu;	/* the corresponding iommu */
27462306a36Sopenharmony_ci	int devices_cnt;		/* target device count */
27562306a36Sopenharmony_ci	u8 atc_required:1;		/* ATS is required */
27662306a36Sopenharmony_ci};
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic LIST_HEAD(dmar_atsr_units);
27962306a36Sopenharmony_cistatic LIST_HEAD(dmar_rmrr_units);
28062306a36Sopenharmony_cistatic LIST_HEAD(dmar_satc_units);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci#define for_each_rmrr_units(rmrr) \
28362306a36Sopenharmony_ci	list_for_each_entry(rmrr, &dmar_rmrr_units, list)
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic void device_block_translation(struct device *dev);
28662306a36Sopenharmony_cistatic void intel_iommu_domain_free(struct iommu_domain *domain);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ciint dmar_disabled = !IS_ENABLED(CONFIG_INTEL_IOMMU_DEFAULT_ON);
28962306a36Sopenharmony_ciint intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ciint intel_iommu_enabled = 0;
29262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_iommu_enabled);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic int dmar_map_gfx = 1;
29562306a36Sopenharmony_cistatic int intel_iommu_superpage = 1;
29662306a36Sopenharmony_cistatic int iommu_identity_mapping;
29762306a36Sopenharmony_cistatic int iommu_skip_te_disable;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci#define IDENTMAP_GFX		2
30062306a36Sopenharmony_ci#define IDENTMAP_AZALIA		4
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ciconst struct iommu_ops intel_iommu_ops;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic bool translation_pre_enabled(struct intel_iommu *iommu)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	return (iommu->flags & VTD_FLAG_TRANS_PRE_ENABLED);
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic void clear_translation_pre_enabled(struct intel_iommu *iommu)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	iommu->flags &= ~VTD_FLAG_TRANS_PRE_ENABLED;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic void init_translation_status(struct intel_iommu *iommu)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	u32 gsts;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	gsts = readl(iommu->reg + DMAR_GSTS_REG);
31962306a36Sopenharmony_ci	if (gsts & DMA_GSTS_TES)
32062306a36Sopenharmony_ci		iommu->flags |= VTD_FLAG_TRANS_PRE_ENABLED;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic int __init intel_iommu_setup(char *str)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	if (!str)
32662306a36Sopenharmony_ci		return -EINVAL;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	while (*str) {
32962306a36Sopenharmony_ci		if (!strncmp(str, "on", 2)) {
33062306a36Sopenharmony_ci			dmar_disabled = 0;
33162306a36Sopenharmony_ci			pr_info("IOMMU enabled\n");
33262306a36Sopenharmony_ci		} else if (!strncmp(str, "off", 3)) {
33362306a36Sopenharmony_ci			dmar_disabled = 1;
33462306a36Sopenharmony_ci			no_platform_optin = 1;
33562306a36Sopenharmony_ci			pr_info("IOMMU disabled\n");
33662306a36Sopenharmony_ci		} else if (!strncmp(str, "igfx_off", 8)) {
33762306a36Sopenharmony_ci			dmar_map_gfx = 0;
33862306a36Sopenharmony_ci			pr_info("Disable GFX device mapping\n");
33962306a36Sopenharmony_ci		} else if (!strncmp(str, "forcedac", 8)) {
34062306a36Sopenharmony_ci			pr_warn("intel_iommu=forcedac deprecated; use iommu.forcedac instead\n");
34162306a36Sopenharmony_ci			iommu_dma_forcedac = true;
34262306a36Sopenharmony_ci		} else if (!strncmp(str, "strict", 6)) {
34362306a36Sopenharmony_ci			pr_warn("intel_iommu=strict deprecated; use iommu.strict=1 instead\n");
34462306a36Sopenharmony_ci			iommu_set_dma_strict();
34562306a36Sopenharmony_ci		} else if (!strncmp(str, "sp_off", 6)) {
34662306a36Sopenharmony_ci			pr_info("Disable supported super page\n");
34762306a36Sopenharmony_ci			intel_iommu_superpage = 0;
34862306a36Sopenharmony_ci		} else if (!strncmp(str, "sm_on", 5)) {
34962306a36Sopenharmony_ci			pr_info("Enable scalable mode if hardware supports\n");
35062306a36Sopenharmony_ci			intel_iommu_sm = 1;
35162306a36Sopenharmony_ci		} else if (!strncmp(str, "sm_off", 6)) {
35262306a36Sopenharmony_ci			pr_info("Scalable mode is disallowed\n");
35362306a36Sopenharmony_ci			intel_iommu_sm = 0;
35462306a36Sopenharmony_ci		} else if (!strncmp(str, "tboot_noforce", 13)) {
35562306a36Sopenharmony_ci			pr_info("Intel-IOMMU: not forcing on after tboot. This could expose security risk for tboot\n");
35662306a36Sopenharmony_ci			intel_iommu_tboot_noforce = 1;
35762306a36Sopenharmony_ci		} else {
35862306a36Sopenharmony_ci			pr_notice("Unknown option - '%s'\n", str);
35962306a36Sopenharmony_ci		}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		str += strcspn(str, ",");
36262306a36Sopenharmony_ci		while (*str == ',')
36362306a36Sopenharmony_ci			str++;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	return 1;
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci__setup("intel_iommu=", intel_iommu_setup);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_civoid *alloc_pgtable_page(int node, gfp_t gfp)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	struct page *page;
37362306a36Sopenharmony_ci	void *vaddr = NULL;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	page = alloc_pages_node(node, gfp | __GFP_ZERO, 0);
37662306a36Sopenharmony_ci	if (page)
37762306a36Sopenharmony_ci		vaddr = page_address(page);
37862306a36Sopenharmony_ci	return vaddr;
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_civoid free_pgtable_page(void *vaddr)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	free_page((unsigned long)vaddr);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic inline int domain_type_is_si(struct dmar_domain *domain)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	return domain->domain.type == IOMMU_DOMAIN_IDENTITY;
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic inline int domain_pfn_supported(struct dmar_domain *domain,
39262306a36Sopenharmony_ci				       unsigned long pfn)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	return !(addr_width < BITS_PER_LONG && pfn >> addr_width);
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci/*
40062306a36Sopenharmony_ci * Calculate the Supported Adjusted Guest Address Widths of an IOMMU.
40162306a36Sopenharmony_ci * Refer to 11.4.2 of the VT-d spec for the encoding of each bit of
40262306a36Sopenharmony_ci * the returned SAGAW.
40362306a36Sopenharmony_ci */
40462306a36Sopenharmony_cistatic unsigned long __iommu_calculate_sagaw(struct intel_iommu *iommu)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	unsigned long fl_sagaw, sl_sagaw;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	fl_sagaw = BIT(2) | (cap_fl5lp_support(iommu->cap) ? BIT(3) : 0);
40962306a36Sopenharmony_ci	sl_sagaw = cap_sagaw(iommu->cap);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/* Second level only. */
41262306a36Sopenharmony_ci	if (!sm_supported(iommu) || !ecap_flts(iommu->ecap))
41362306a36Sopenharmony_ci		return sl_sagaw;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* First level only. */
41662306a36Sopenharmony_ci	if (!ecap_slts(iommu->ecap))
41762306a36Sopenharmony_ci		return fl_sagaw;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return fl_sagaw & sl_sagaw;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	unsigned long sagaw;
42562306a36Sopenharmony_ci	int agaw;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	sagaw = __iommu_calculate_sagaw(iommu);
42862306a36Sopenharmony_ci	for (agaw = width_to_agaw(max_gaw); agaw >= 0; agaw--) {
42962306a36Sopenharmony_ci		if (test_bit(agaw, &sagaw))
43062306a36Sopenharmony_ci			break;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return agaw;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci/*
43762306a36Sopenharmony_ci * Calculate max SAGAW for each iommu.
43862306a36Sopenharmony_ci */
43962306a36Sopenharmony_ciint iommu_calculate_max_sagaw(struct intel_iommu *iommu)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci/*
44562306a36Sopenharmony_ci * calculate agaw for each iommu.
44662306a36Sopenharmony_ci * "SAGAW" may be different across iommus, use a default agaw, and
44762306a36Sopenharmony_ci * get a supported less agaw for iommus that don't support the default agaw.
44862306a36Sopenharmony_ci */
44962306a36Sopenharmony_ciint iommu_calculate_agaw(struct intel_iommu *iommu)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic inline bool iommu_paging_structure_coherency(struct intel_iommu *iommu)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	return sm_supported(iommu) ?
45762306a36Sopenharmony_ci			ecap_smpwc(iommu->ecap) : ecap_coherent(iommu->ecap);
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic void domain_update_iommu_coherency(struct dmar_domain *domain)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	struct iommu_domain_info *info;
46362306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd;
46462306a36Sopenharmony_ci	struct intel_iommu *iommu;
46562306a36Sopenharmony_ci	bool found = false;
46662306a36Sopenharmony_ci	unsigned long i;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	domain->iommu_coherency = true;
46962306a36Sopenharmony_ci	xa_for_each(&domain->iommu_array, i, info) {
47062306a36Sopenharmony_ci		found = true;
47162306a36Sopenharmony_ci		if (!iommu_paging_structure_coherency(info->iommu)) {
47262306a36Sopenharmony_ci			domain->iommu_coherency = false;
47362306a36Sopenharmony_ci			break;
47462306a36Sopenharmony_ci		}
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci	if (found)
47762306a36Sopenharmony_ci		return;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/* No hardware attached; use lowest common denominator */
48062306a36Sopenharmony_ci	rcu_read_lock();
48162306a36Sopenharmony_ci	for_each_active_iommu(iommu, drhd) {
48262306a36Sopenharmony_ci		if (!iommu_paging_structure_coherency(iommu)) {
48362306a36Sopenharmony_ci			domain->iommu_coherency = false;
48462306a36Sopenharmony_ci			break;
48562306a36Sopenharmony_ci		}
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci	rcu_read_unlock();
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic int domain_update_iommu_superpage(struct dmar_domain *domain,
49162306a36Sopenharmony_ci					 struct intel_iommu *skip)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd;
49462306a36Sopenharmony_ci	struct intel_iommu *iommu;
49562306a36Sopenharmony_ci	int mask = 0x3;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	if (!intel_iommu_superpage)
49862306a36Sopenharmony_ci		return 0;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	/* set iommu_superpage to the smallest common denominator */
50162306a36Sopenharmony_ci	rcu_read_lock();
50262306a36Sopenharmony_ci	for_each_active_iommu(iommu, drhd) {
50362306a36Sopenharmony_ci		if (iommu != skip) {
50462306a36Sopenharmony_ci			if (domain && domain->use_first_level) {
50562306a36Sopenharmony_ci				if (!cap_fl1gp_support(iommu->cap))
50662306a36Sopenharmony_ci					mask = 0x1;
50762306a36Sopenharmony_ci			} else {
50862306a36Sopenharmony_ci				mask &= cap_super_page_val(iommu->cap);
50962306a36Sopenharmony_ci			}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci			if (!mask)
51262306a36Sopenharmony_ci				break;
51362306a36Sopenharmony_ci		}
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci	rcu_read_unlock();
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	return fls(mask);
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic int domain_update_device_node(struct dmar_domain *domain)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	struct device_domain_info *info;
52362306a36Sopenharmony_ci	int nid = NUMA_NO_NODE;
52462306a36Sopenharmony_ci	unsigned long flags;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	spin_lock_irqsave(&domain->lock, flags);
52762306a36Sopenharmony_ci	list_for_each_entry(info, &domain->devices, link) {
52862306a36Sopenharmony_ci		/*
52962306a36Sopenharmony_ci		 * There could possibly be multiple device numa nodes as devices
53062306a36Sopenharmony_ci		 * within the same domain may sit behind different IOMMUs. There
53162306a36Sopenharmony_ci		 * isn't perfect answer in such situation, so we select first
53262306a36Sopenharmony_ci		 * come first served policy.
53362306a36Sopenharmony_ci		 */
53462306a36Sopenharmony_ci		nid = dev_to_node(info->dev);
53562306a36Sopenharmony_ci		if (nid != NUMA_NO_NODE)
53662306a36Sopenharmony_ci			break;
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci	spin_unlock_irqrestore(&domain->lock, flags);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	return nid;
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic void domain_update_iotlb(struct dmar_domain *domain);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci/* Return the super pagesize bitmap if supported. */
54662306a36Sopenharmony_cistatic unsigned long domain_super_pgsize_bitmap(struct dmar_domain *domain)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	unsigned long bitmap = 0;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	/*
55162306a36Sopenharmony_ci	 * 1-level super page supports page size of 2MiB, 2-level super page
55262306a36Sopenharmony_ci	 * supports page size of both 2MiB and 1GiB.
55362306a36Sopenharmony_ci	 */
55462306a36Sopenharmony_ci	if (domain->iommu_superpage == 1)
55562306a36Sopenharmony_ci		bitmap |= SZ_2M;
55662306a36Sopenharmony_ci	else if (domain->iommu_superpage == 2)
55762306a36Sopenharmony_ci		bitmap |= SZ_2M | SZ_1G;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	return bitmap;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci/* Some capabilities may be different across iommus */
56362306a36Sopenharmony_cistatic void domain_update_iommu_cap(struct dmar_domain *domain)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	domain_update_iommu_coherency(domain);
56662306a36Sopenharmony_ci	domain->iommu_superpage = domain_update_iommu_superpage(domain, NULL);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	/*
56962306a36Sopenharmony_ci	 * If RHSA is missing, we should default to the device numa domain
57062306a36Sopenharmony_ci	 * as fall back.
57162306a36Sopenharmony_ci	 */
57262306a36Sopenharmony_ci	if (domain->nid == NUMA_NO_NODE)
57362306a36Sopenharmony_ci		domain->nid = domain_update_device_node(domain);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	/*
57662306a36Sopenharmony_ci	 * First-level translation restricts the input-address to a
57762306a36Sopenharmony_ci	 * canonical address (i.e., address bits 63:N have the same
57862306a36Sopenharmony_ci	 * value as address bit [N-1], where N is 48-bits with 4-level
57962306a36Sopenharmony_ci	 * paging and 57-bits with 5-level paging). Hence, skip bit
58062306a36Sopenharmony_ci	 * [N-1].
58162306a36Sopenharmony_ci	 */
58262306a36Sopenharmony_ci	if (domain->use_first_level)
58362306a36Sopenharmony_ci		domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw - 1);
58462306a36Sopenharmony_ci	else
58562306a36Sopenharmony_ci		domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	domain->domain.pgsize_bitmap |= domain_super_pgsize_bitmap(domain);
58862306a36Sopenharmony_ci	domain_update_iotlb(domain);
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistruct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
59262306a36Sopenharmony_ci					 u8 devfn, int alloc)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	struct root_entry *root = &iommu->root_entry[bus];
59562306a36Sopenharmony_ci	struct context_entry *context;
59662306a36Sopenharmony_ci	u64 *entry;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	/*
59962306a36Sopenharmony_ci	 * Except that the caller requested to allocate a new entry,
60062306a36Sopenharmony_ci	 * returning a copied context entry makes no sense.
60162306a36Sopenharmony_ci	 */
60262306a36Sopenharmony_ci	if (!alloc && context_copied(iommu, bus, devfn))
60362306a36Sopenharmony_ci		return NULL;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	entry = &root->lo;
60662306a36Sopenharmony_ci	if (sm_supported(iommu)) {
60762306a36Sopenharmony_ci		if (devfn >= 0x80) {
60862306a36Sopenharmony_ci			devfn -= 0x80;
60962306a36Sopenharmony_ci			entry = &root->hi;
61062306a36Sopenharmony_ci		}
61162306a36Sopenharmony_ci		devfn *= 2;
61262306a36Sopenharmony_ci	}
61362306a36Sopenharmony_ci	if (*entry & 1)
61462306a36Sopenharmony_ci		context = phys_to_virt(*entry & VTD_PAGE_MASK);
61562306a36Sopenharmony_ci	else {
61662306a36Sopenharmony_ci		unsigned long phy_addr;
61762306a36Sopenharmony_ci		if (!alloc)
61862306a36Sopenharmony_ci			return NULL;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		context = alloc_pgtable_page(iommu->node, GFP_ATOMIC);
62162306a36Sopenharmony_ci		if (!context)
62262306a36Sopenharmony_ci			return NULL;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		__iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
62562306a36Sopenharmony_ci		phy_addr = virt_to_phys((void *)context);
62662306a36Sopenharmony_ci		*entry = phy_addr | 1;
62762306a36Sopenharmony_ci		__iommu_flush_cache(iommu, entry, sizeof(*entry));
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci	return &context[devfn];
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci/**
63362306a36Sopenharmony_ci * is_downstream_to_pci_bridge - test if a device belongs to the PCI
63462306a36Sopenharmony_ci *				 sub-hierarchy of a candidate PCI-PCI bridge
63562306a36Sopenharmony_ci * @dev: candidate PCI device belonging to @bridge PCI sub-hierarchy
63662306a36Sopenharmony_ci * @bridge: the candidate PCI-PCI bridge
63762306a36Sopenharmony_ci *
63862306a36Sopenharmony_ci * Return: true if @dev belongs to @bridge PCI sub-hierarchy, else false.
63962306a36Sopenharmony_ci */
64062306a36Sopenharmony_cistatic bool
64162306a36Sopenharmony_ciis_downstream_to_pci_bridge(struct device *dev, struct device *bridge)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	struct pci_dev *pdev, *pbridge;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if (!dev_is_pci(dev) || !dev_is_pci(bridge))
64662306a36Sopenharmony_ci		return false;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	pdev = to_pci_dev(dev);
64962306a36Sopenharmony_ci	pbridge = to_pci_dev(bridge);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	if (pbridge->subordinate &&
65262306a36Sopenharmony_ci	    pbridge->subordinate->number <= pdev->bus->number &&
65362306a36Sopenharmony_ci	    pbridge->subordinate->busn_res.end >= pdev->bus->number)
65462306a36Sopenharmony_ci		return true;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	return false;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic bool quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
66062306a36Sopenharmony_ci{
66162306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd;
66262306a36Sopenharmony_ci	u32 vtbar;
66362306a36Sopenharmony_ci	int rc;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/* We know that this device on this chipset has its own IOMMU.
66662306a36Sopenharmony_ci	 * If we find it under a different IOMMU, then the BIOS is lying
66762306a36Sopenharmony_ci	 * to us. Hope that the IOMMU for this device is actually
66862306a36Sopenharmony_ci	 * disabled, and it needs no translation...
66962306a36Sopenharmony_ci	 */
67062306a36Sopenharmony_ci	rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
67162306a36Sopenharmony_ci	if (rc) {
67262306a36Sopenharmony_ci		/* "can't" happen */
67362306a36Sopenharmony_ci		dev_info(&pdev->dev, "failed to run vt-d quirk\n");
67462306a36Sopenharmony_ci		return false;
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci	vtbar &= 0xffff0000;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	/* we know that the this iommu should be at offset 0xa000 from vtbar */
67962306a36Sopenharmony_ci	drhd = dmar_find_matched_drhd_unit(pdev);
68062306a36Sopenharmony_ci	if (!drhd || drhd->reg_base_addr - vtbar != 0xa000) {
68162306a36Sopenharmony_ci		pr_warn_once(FW_BUG "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n");
68262306a36Sopenharmony_ci		add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
68362306a36Sopenharmony_ci		return true;
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	return false;
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_cistatic bool iommu_is_dummy(struct intel_iommu *iommu, struct device *dev)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci	if (!iommu || iommu->drhd->ignored)
69262306a36Sopenharmony_ci		return true;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	if (dev_is_pci(dev)) {
69562306a36Sopenharmony_ci		struct pci_dev *pdev = to_pci_dev(dev);
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci		if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
69862306a36Sopenharmony_ci		    pdev->device == PCI_DEVICE_ID_INTEL_IOAT_SNB &&
69962306a36Sopenharmony_ci		    quirk_ioat_snb_local_iommu(pdev))
70062306a36Sopenharmony_ci			return true;
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	return false;
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistruct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd = NULL;
70962306a36Sopenharmony_ci	struct pci_dev *pdev = NULL;
71062306a36Sopenharmony_ci	struct intel_iommu *iommu;
71162306a36Sopenharmony_ci	struct device *tmp;
71262306a36Sopenharmony_ci	u16 segment = 0;
71362306a36Sopenharmony_ci	int i;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if (!dev)
71662306a36Sopenharmony_ci		return NULL;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	if (dev_is_pci(dev)) {
71962306a36Sopenharmony_ci		struct pci_dev *pf_pdev;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci		pdev = pci_real_dma_dev(to_pci_dev(dev));
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci		/* VFs aren't listed in scope tables; we need to look up
72462306a36Sopenharmony_ci		 * the PF instead to find the IOMMU. */
72562306a36Sopenharmony_ci		pf_pdev = pci_physfn(pdev);
72662306a36Sopenharmony_ci		dev = &pf_pdev->dev;
72762306a36Sopenharmony_ci		segment = pci_domain_nr(pdev->bus);
72862306a36Sopenharmony_ci	} else if (has_acpi_companion(dev))
72962306a36Sopenharmony_ci		dev = &ACPI_COMPANION(dev)->dev;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	rcu_read_lock();
73262306a36Sopenharmony_ci	for_each_iommu(iommu, drhd) {
73362306a36Sopenharmony_ci		if (pdev && segment != drhd->segment)
73462306a36Sopenharmony_ci			continue;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		for_each_active_dev_scope(drhd->devices,
73762306a36Sopenharmony_ci					  drhd->devices_cnt, i, tmp) {
73862306a36Sopenharmony_ci			if (tmp == dev) {
73962306a36Sopenharmony_ci				/* For a VF use its original BDF# not that of the PF
74062306a36Sopenharmony_ci				 * which we used for the IOMMU lookup. Strictly speaking
74162306a36Sopenharmony_ci				 * we could do this for all PCI devices; we only need to
74262306a36Sopenharmony_ci				 * get the BDF# from the scope table for ACPI matches. */
74362306a36Sopenharmony_ci				if (pdev && pdev->is_virtfn)
74462306a36Sopenharmony_ci					goto got_pdev;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci				if (bus && devfn) {
74762306a36Sopenharmony_ci					*bus = drhd->devices[i].bus;
74862306a36Sopenharmony_ci					*devfn = drhd->devices[i].devfn;
74962306a36Sopenharmony_ci				}
75062306a36Sopenharmony_ci				goto out;
75162306a36Sopenharmony_ci			}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci			if (is_downstream_to_pci_bridge(dev, tmp))
75462306a36Sopenharmony_ci				goto got_pdev;
75562306a36Sopenharmony_ci		}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci		if (pdev && drhd->include_all) {
75862306a36Sopenharmony_cigot_pdev:
75962306a36Sopenharmony_ci			if (bus && devfn) {
76062306a36Sopenharmony_ci				*bus = pdev->bus->number;
76162306a36Sopenharmony_ci				*devfn = pdev->devfn;
76262306a36Sopenharmony_ci			}
76362306a36Sopenharmony_ci			goto out;
76462306a36Sopenharmony_ci		}
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci	iommu = NULL;
76762306a36Sopenharmony_ciout:
76862306a36Sopenharmony_ci	if (iommu_is_dummy(iommu, dev))
76962306a36Sopenharmony_ci		iommu = NULL;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	rcu_read_unlock();
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	return iommu;
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_cistatic void domain_flush_cache(struct dmar_domain *domain,
77762306a36Sopenharmony_ci			       void *addr, int size)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	if (!domain->iommu_coherency)
78062306a36Sopenharmony_ci		clflush_cache_range(addr, size);
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic void free_context_table(struct intel_iommu *iommu)
78462306a36Sopenharmony_ci{
78562306a36Sopenharmony_ci	struct context_entry *context;
78662306a36Sopenharmony_ci	int i;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (!iommu->root_entry)
78962306a36Sopenharmony_ci		return;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	for (i = 0; i < ROOT_ENTRY_NR; i++) {
79262306a36Sopenharmony_ci		context = iommu_context_addr(iommu, i, 0, 0);
79362306a36Sopenharmony_ci		if (context)
79462306a36Sopenharmony_ci			free_pgtable_page(context);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci		if (!sm_supported(iommu))
79762306a36Sopenharmony_ci			continue;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci		context = iommu_context_addr(iommu, i, 0x80, 0);
80062306a36Sopenharmony_ci		if (context)
80162306a36Sopenharmony_ci			free_pgtable_page(context);
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	free_pgtable_page(iommu->root_entry);
80562306a36Sopenharmony_ci	iommu->root_entry = NULL;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci#ifdef CONFIG_DMAR_DEBUG
80962306a36Sopenharmony_cistatic void pgtable_walk(struct intel_iommu *iommu, unsigned long pfn,
81062306a36Sopenharmony_ci			 u8 bus, u8 devfn, struct dma_pte *parent, int level)
81162306a36Sopenharmony_ci{
81262306a36Sopenharmony_ci	struct dma_pte *pte;
81362306a36Sopenharmony_ci	int offset;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	while (1) {
81662306a36Sopenharmony_ci		offset = pfn_level_offset(pfn, level);
81762306a36Sopenharmony_ci		pte = &parent[offset];
81862306a36Sopenharmony_ci		if (!pte || (dma_pte_superpage(pte) || !dma_pte_present(pte))) {
81962306a36Sopenharmony_ci			pr_info("PTE not present at level %d\n", level);
82062306a36Sopenharmony_ci			break;
82162306a36Sopenharmony_ci		}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci		pr_info("pte level: %d, pte value: 0x%016llx\n", level, pte->val);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci		if (level == 1)
82662306a36Sopenharmony_ci			break;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci		parent = phys_to_virt(dma_pte_addr(pte));
82962306a36Sopenharmony_ci		level--;
83062306a36Sopenharmony_ci	}
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_civoid dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id,
83462306a36Sopenharmony_ci			  unsigned long long addr, u32 pasid)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	struct pasid_dir_entry *dir, *pde;
83762306a36Sopenharmony_ci	struct pasid_entry *entries, *pte;
83862306a36Sopenharmony_ci	struct context_entry *ctx_entry;
83962306a36Sopenharmony_ci	struct root_entry *rt_entry;
84062306a36Sopenharmony_ci	int i, dir_index, index, level;
84162306a36Sopenharmony_ci	u8 devfn = source_id & 0xff;
84262306a36Sopenharmony_ci	u8 bus = source_id >> 8;
84362306a36Sopenharmony_ci	struct dma_pte *pgtable;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	pr_info("Dump %s table entries for IOVA 0x%llx\n", iommu->name, addr);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	/* root entry dump */
84862306a36Sopenharmony_ci	rt_entry = &iommu->root_entry[bus];
84962306a36Sopenharmony_ci	if (!rt_entry) {
85062306a36Sopenharmony_ci		pr_info("root table entry is not present\n");
85162306a36Sopenharmony_ci		return;
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	if (sm_supported(iommu))
85562306a36Sopenharmony_ci		pr_info("scalable mode root entry: hi 0x%016llx, low 0x%016llx\n",
85662306a36Sopenharmony_ci			rt_entry->hi, rt_entry->lo);
85762306a36Sopenharmony_ci	else
85862306a36Sopenharmony_ci		pr_info("root entry: 0x%016llx", rt_entry->lo);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	/* context entry dump */
86162306a36Sopenharmony_ci	ctx_entry = iommu_context_addr(iommu, bus, devfn, 0);
86262306a36Sopenharmony_ci	if (!ctx_entry) {
86362306a36Sopenharmony_ci		pr_info("context table entry is not present\n");
86462306a36Sopenharmony_ci		return;
86562306a36Sopenharmony_ci	}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	pr_info("context entry: hi 0x%016llx, low 0x%016llx\n",
86862306a36Sopenharmony_ci		ctx_entry->hi, ctx_entry->lo);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	/* legacy mode does not require PASID entries */
87162306a36Sopenharmony_ci	if (!sm_supported(iommu)) {
87262306a36Sopenharmony_ci		level = agaw_to_level(ctx_entry->hi & 7);
87362306a36Sopenharmony_ci		pgtable = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK);
87462306a36Sopenharmony_ci		goto pgtable_walk;
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	/* get the pointer to pasid directory entry */
87862306a36Sopenharmony_ci	dir = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK);
87962306a36Sopenharmony_ci	if (!dir) {
88062306a36Sopenharmony_ci		pr_info("pasid directory entry is not present\n");
88162306a36Sopenharmony_ci		return;
88262306a36Sopenharmony_ci	}
88362306a36Sopenharmony_ci	/* For request-without-pasid, get the pasid from context entry */
88462306a36Sopenharmony_ci	if (intel_iommu_sm && pasid == IOMMU_PASID_INVALID)
88562306a36Sopenharmony_ci		pasid = IOMMU_NO_PASID;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	dir_index = pasid >> PASID_PDE_SHIFT;
88862306a36Sopenharmony_ci	pde = &dir[dir_index];
88962306a36Sopenharmony_ci	pr_info("pasid dir entry: 0x%016llx\n", pde->val);
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	/* get the pointer to the pasid table entry */
89262306a36Sopenharmony_ci	entries = get_pasid_table_from_pde(pde);
89362306a36Sopenharmony_ci	if (!entries) {
89462306a36Sopenharmony_ci		pr_info("pasid table entry is not present\n");
89562306a36Sopenharmony_ci		return;
89662306a36Sopenharmony_ci	}
89762306a36Sopenharmony_ci	index = pasid & PASID_PTE_MASK;
89862306a36Sopenharmony_ci	pte = &entries[index];
89962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pte->val); i++)
90062306a36Sopenharmony_ci		pr_info("pasid table entry[%d]: 0x%016llx\n", i, pte->val[i]);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	if (pasid_pte_get_pgtt(pte) == PASID_ENTRY_PGTT_FL_ONLY) {
90362306a36Sopenharmony_ci		level = pte->val[2] & BIT_ULL(2) ? 5 : 4;
90462306a36Sopenharmony_ci		pgtable = phys_to_virt(pte->val[2] & VTD_PAGE_MASK);
90562306a36Sopenharmony_ci	} else {
90662306a36Sopenharmony_ci		level = agaw_to_level((pte->val[0] >> 2) & 0x7);
90762306a36Sopenharmony_ci		pgtable = phys_to_virt(pte->val[0] & VTD_PAGE_MASK);
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_cipgtable_walk:
91162306a36Sopenharmony_ci	pgtable_walk(iommu, addr >> VTD_PAGE_SHIFT, bus, devfn, pgtable, level);
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci#endif
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_cistatic struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
91662306a36Sopenharmony_ci				      unsigned long pfn, int *target_level,
91762306a36Sopenharmony_ci				      gfp_t gfp)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	struct dma_pte *parent, *pte;
92062306a36Sopenharmony_ci	int level = agaw_to_level(domain->agaw);
92162306a36Sopenharmony_ci	int offset;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (!domain_pfn_supported(domain, pfn))
92462306a36Sopenharmony_ci		/* Address beyond IOMMU's addressing capabilities. */
92562306a36Sopenharmony_ci		return NULL;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	parent = domain->pgd;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	while (1) {
93062306a36Sopenharmony_ci		void *tmp_page;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci		offset = pfn_level_offset(pfn, level);
93362306a36Sopenharmony_ci		pte = &parent[offset];
93462306a36Sopenharmony_ci		if (!*target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
93562306a36Sopenharmony_ci			break;
93662306a36Sopenharmony_ci		if (level == *target_level)
93762306a36Sopenharmony_ci			break;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci		if (!dma_pte_present(pte)) {
94062306a36Sopenharmony_ci			uint64_t pteval;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci			tmp_page = alloc_pgtable_page(domain->nid, gfp);
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci			if (!tmp_page)
94562306a36Sopenharmony_ci				return NULL;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci			domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
94862306a36Sopenharmony_ci			pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
94962306a36Sopenharmony_ci			if (domain->use_first_level)
95062306a36Sopenharmony_ci				pteval |= DMA_FL_PTE_XD | DMA_FL_PTE_US | DMA_FL_PTE_ACCESS;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci			if (cmpxchg64(&pte->val, 0ULL, pteval))
95362306a36Sopenharmony_ci				/* Someone else set it while we were thinking; use theirs. */
95462306a36Sopenharmony_ci				free_pgtable_page(tmp_page);
95562306a36Sopenharmony_ci			else
95662306a36Sopenharmony_ci				domain_flush_cache(domain, pte, sizeof(*pte));
95762306a36Sopenharmony_ci		}
95862306a36Sopenharmony_ci		if (level == 1)
95962306a36Sopenharmony_ci			break;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci		parent = phys_to_virt(dma_pte_addr(pte));
96262306a36Sopenharmony_ci		level--;
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	if (!*target_level)
96662306a36Sopenharmony_ci		*target_level = level;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	return pte;
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci/* return address's pte at specific level */
97262306a36Sopenharmony_cistatic struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
97362306a36Sopenharmony_ci					 unsigned long pfn,
97462306a36Sopenharmony_ci					 int level, int *large_page)
97562306a36Sopenharmony_ci{
97662306a36Sopenharmony_ci	struct dma_pte *parent, *pte;
97762306a36Sopenharmony_ci	int total = agaw_to_level(domain->agaw);
97862306a36Sopenharmony_ci	int offset;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	parent = domain->pgd;
98162306a36Sopenharmony_ci	while (level <= total) {
98262306a36Sopenharmony_ci		offset = pfn_level_offset(pfn, total);
98362306a36Sopenharmony_ci		pte = &parent[offset];
98462306a36Sopenharmony_ci		if (level == total)
98562306a36Sopenharmony_ci			return pte;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci		if (!dma_pte_present(pte)) {
98862306a36Sopenharmony_ci			*large_page = total;
98962306a36Sopenharmony_ci			break;
99062306a36Sopenharmony_ci		}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		if (dma_pte_superpage(pte)) {
99362306a36Sopenharmony_ci			*large_page = total;
99462306a36Sopenharmony_ci			return pte;
99562306a36Sopenharmony_ci		}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci		parent = phys_to_virt(dma_pte_addr(pte));
99862306a36Sopenharmony_ci		total--;
99962306a36Sopenharmony_ci	}
100062306a36Sopenharmony_ci	return NULL;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci/* clear last level pte, a tlb flush should be followed */
100462306a36Sopenharmony_cistatic void dma_pte_clear_range(struct dmar_domain *domain,
100562306a36Sopenharmony_ci				unsigned long start_pfn,
100662306a36Sopenharmony_ci				unsigned long last_pfn)
100762306a36Sopenharmony_ci{
100862306a36Sopenharmony_ci	unsigned int large_page;
100962306a36Sopenharmony_ci	struct dma_pte *first_pte, *pte;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	if (WARN_ON(!domain_pfn_supported(domain, last_pfn)) ||
101262306a36Sopenharmony_ci	    WARN_ON(start_pfn > last_pfn))
101362306a36Sopenharmony_ci		return;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	/* we don't need lock here; nobody else touches the iova range */
101662306a36Sopenharmony_ci	do {
101762306a36Sopenharmony_ci		large_page = 1;
101862306a36Sopenharmony_ci		first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
101962306a36Sopenharmony_ci		if (!pte) {
102062306a36Sopenharmony_ci			start_pfn = align_to_level(start_pfn + 1, large_page + 1);
102162306a36Sopenharmony_ci			continue;
102262306a36Sopenharmony_ci		}
102362306a36Sopenharmony_ci		do {
102462306a36Sopenharmony_ci			dma_clear_pte(pte);
102562306a36Sopenharmony_ci			start_pfn += lvl_to_nr_pages(large_page);
102662306a36Sopenharmony_ci			pte++;
102762306a36Sopenharmony_ci		} while (start_pfn <= last_pfn && !first_pte_in_page(pte));
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci		domain_flush_cache(domain, first_pte,
103062306a36Sopenharmony_ci				   (void *)pte - (void *)first_pte);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	} while (start_pfn && start_pfn <= last_pfn);
103362306a36Sopenharmony_ci}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_cistatic void dma_pte_free_level(struct dmar_domain *domain, int level,
103662306a36Sopenharmony_ci			       int retain_level, struct dma_pte *pte,
103762306a36Sopenharmony_ci			       unsigned long pfn, unsigned long start_pfn,
103862306a36Sopenharmony_ci			       unsigned long last_pfn)
103962306a36Sopenharmony_ci{
104062306a36Sopenharmony_ci	pfn = max(start_pfn, pfn);
104162306a36Sopenharmony_ci	pte = &pte[pfn_level_offset(pfn, level)];
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	do {
104462306a36Sopenharmony_ci		unsigned long level_pfn;
104562306a36Sopenharmony_ci		struct dma_pte *level_pte;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci		if (!dma_pte_present(pte) || dma_pte_superpage(pte))
104862306a36Sopenharmony_ci			goto next;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci		level_pfn = pfn & level_mask(level);
105162306a36Sopenharmony_ci		level_pte = phys_to_virt(dma_pte_addr(pte));
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci		if (level > 2) {
105462306a36Sopenharmony_ci			dma_pte_free_level(domain, level - 1, retain_level,
105562306a36Sopenharmony_ci					   level_pte, level_pfn, start_pfn,
105662306a36Sopenharmony_ci					   last_pfn);
105762306a36Sopenharmony_ci		}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci		/*
106062306a36Sopenharmony_ci		 * Free the page table if we're below the level we want to
106162306a36Sopenharmony_ci		 * retain and the range covers the entire table.
106262306a36Sopenharmony_ci		 */
106362306a36Sopenharmony_ci		if (level < retain_level && !(start_pfn > level_pfn ||
106462306a36Sopenharmony_ci		      last_pfn < level_pfn + level_size(level) - 1)) {
106562306a36Sopenharmony_ci			dma_clear_pte(pte);
106662306a36Sopenharmony_ci			domain_flush_cache(domain, pte, sizeof(*pte));
106762306a36Sopenharmony_ci			free_pgtable_page(level_pte);
106862306a36Sopenharmony_ci		}
106962306a36Sopenharmony_cinext:
107062306a36Sopenharmony_ci		pfn += level_size(level);
107162306a36Sopenharmony_ci	} while (!first_pte_in_page(++pte) && pfn <= last_pfn);
107262306a36Sopenharmony_ci}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci/*
107562306a36Sopenharmony_ci * clear last level (leaf) ptes and free page table pages below the
107662306a36Sopenharmony_ci * level we wish to keep intact.
107762306a36Sopenharmony_ci */
107862306a36Sopenharmony_cistatic void dma_pte_free_pagetable(struct dmar_domain *domain,
107962306a36Sopenharmony_ci				   unsigned long start_pfn,
108062306a36Sopenharmony_ci				   unsigned long last_pfn,
108162306a36Sopenharmony_ci				   int retain_level)
108262306a36Sopenharmony_ci{
108362306a36Sopenharmony_ci	dma_pte_clear_range(domain, start_pfn, last_pfn);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	/* We don't need lock here; nobody else touches the iova range */
108662306a36Sopenharmony_ci	dma_pte_free_level(domain, agaw_to_level(domain->agaw), retain_level,
108762306a36Sopenharmony_ci			   domain->pgd, 0, start_pfn, last_pfn);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	/* free pgd */
109062306a36Sopenharmony_ci	if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
109162306a36Sopenharmony_ci		free_pgtable_page(domain->pgd);
109262306a36Sopenharmony_ci		domain->pgd = NULL;
109362306a36Sopenharmony_ci	}
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci/* When a page at a given level is being unlinked from its parent, we don't
109762306a36Sopenharmony_ci   need to *modify* it at all. All we need to do is make a list of all the
109862306a36Sopenharmony_ci   pages which can be freed just as soon as we've flushed the IOTLB and we
109962306a36Sopenharmony_ci   know the hardware page-walk will no longer touch them.
110062306a36Sopenharmony_ci   The 'pte' argument is the *parent* PTE, pointing to the page that is to
110162306a36Sopenharmony_ci   be freed. */
110262306a36Sopenharmony_cistatic void dma_pte_list_pagetables(struct dmar_domain *domain,
110362306a36Sopenharmony_ci				    int level, struct dma_pte *pte,
110462306a36Sopenharmony_ci				    struct list_head *freelist)
110562306a36Sopenharmony_ci{
110662306a36Sopenharmony_ci	struct page *pg;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	pg = pfn_to_page(dma_pte_addr(pte) >> PAGE_SHIFT);
110962306a36Sopenharmony_ci	list_add_tail(&pg->lru, freelist);
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	if (level == 1)
111262306a36Sopenharmony_ci		return;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	pte = page_address(pg);
111562306a36Sopenharmony_ci	do {
111662306a36Sopenharmony_ci		if (dma_pte_present(pte) && !dma_pte_superpage(pte))
111762306a36Sopenharmony_ci			dma_pte_list_pagetables(domain, level - 1, pte, freelist);
111862306a36Sopenharmony_ci		pte++;
111962306a36Sopenharmony_ci	} while (!first_pte_in_page(pte));
112062306a36Sopenharmony_ci}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_cistatic void dma_pte_clear_level(struct dmar_domain *domain, int level,
112362306a36Sopenharmony_ci				struct dma_pte *pte, unsigned long pfn,
112462306a36Sopenharmony_ci				unsigned long start_pfn, unsigned long last_pfn,
112562306a36Sopenharmony_ci				struct list_head *freelist)
112662306a36Sopenharmony_ci{
112762306a36Sopenharmony_ci	struct dma_pte *first_pte = NULL, *last_pte = NULL;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	pfn = max(start_pfn, pfn);
113062306a36Sopenharmony_ci	pte = &pte[pfn_level_offset(pfn, level)];
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	do {
113362306a36Sopenharmony_ci		unsigned long level_pfn = pfn & level_mask(level);
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci		if (!dma_pte_present(pte))
113662306a36Sopenharmony_ci			goto next;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci		/* If range covers entire pagetable, free it */
113962306a36Sopenharmony_ci		if (start_pfn <= level_pfn &&
114062306a36Sopenharmony_ci		    last_pfn >= level_pfn + level_size(level) - 1) {
114162306a36Sopenharmony_ci			/* These suborbinate page tables are going away entirely. Don't
114262306a36Sopenharmony_ci			   bother to clear them; we're just going to *free* them. */
114362306a36Sopenharmony_ci			if (level > 1 && !dma_pte_superpage(pte))
114462306a36Sopenharmony_ci				dma_pte_list_pagetables(domain, level - 1, pte, freelist);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci			dma_clear_pte(pte);
114762306a36Sopenharmony_ci			if (!first_pte)
114862306a36Sopenharmony_ci				first_pte = pte;
114962306a36Sopenharmony_ci			last_pte = pte;
115062306a36Sopenharmony_ci		} else if (level > 1) {
115162306a36Sopenharmony_ci			/* Recurse down into a level that isn't *entirely* obsolete */
115262306a36Sopenharmony_ci			dma_pte_clear_level(domain, level - 1,
115362306a36Sopenharmony_ci					    phys_to_virt(dma_pte_addr(pte)),
115462306a36Sopenharmony_ci					    level_pfn, start_pfn, last_pfn,
115562306a36Sopenharmony_ci					    freelist);
115662306a36Sopenharmony_ci		}
115762306a36Sopenharmony_cinext:
115862306a36Sopenharmony_ci		pfn = level_pfn + level_size(level);
115962306a36Sopenharmony_ci	} while (!first_pte_in_page(++pte) && pfn <= last_pfn);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	if (first_pte)
116262306a36Sopenharmony_ci		domain_flush_cache(domain, first_pte,
116362306a36Sopenharmony_ci				   (void *)++last_pte - (void *)first_pte);
116462306a36Sopenharmony_ci}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci/* We can't just free the pages because the IOMMU may still be walking
116762306a36Sopenharmony_ci   the page tables, and may have cached the intermediate levels. The
116862306a36Sopenharmony_ci   pages can only be freed after the IOTLB flush has been done. */
116962306a36Sopenharmony_cistatic void domain_unmap(struct dmar_domain *domain, unsigned long start_pfn,
117062306a36Sopenharmony_ci			 unsigned long last_pfn, struct list_head *freelist)
117162306a36Sopenharmony_ci{
117262306a36Sopenharmony_ci	if (WARN_ON(!domain_pfn_supported(domain, last_pfn)) ||
117362306a36Sopenharmony_ci	    WARN_ON(start_pfn > last_pfn))
117462306a36Sopenharmony_ci		return;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	/* we don't need lock here; nobody else touches the iova range */
117762306a36Sopenharmony_ci	dma_pte_clear_level(domain, agaw_to_level(domain->agaw),
117862306a36Sopenharmony_ci			    domain->pgd, 0, start_pfn, last_pfn, freelist);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	/* free pgd */
118162306a36Sopenharmony_ci	if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
118262306a36Sopenharmony_ci		struct page *pgd_page = virt_to_page(domain->pgd);
118362306a36Sopenharmony_ci		list_add_tail(&pgd_page->lru, freelist);
118462306a36Sopenharmony_ci		domain->pgd = NULL;
118562306a36Sopenharmony_ci	}
118662306a36Sopenharmony_ci}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci/* iommu handling */
118962306a36Sopenharmony_cistatic int iommu_alloc_root_entry(struct intel_iommu *iommu)
119062306a36Sopenharmony_ci{
119162306a36Sopenharmony_ci	struct root_entry *root;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	root = alloc_pgtable_page(iommu->node, GFP_ATOMIC);
119462306a36Sopenharmony_ci	if (!root) {
119562306a36Sopenharmony_ci		pr_err("Allocating root entry for %s failed\n",
119662306a36Sopenharmony_ci			iommu->name);
119762306a36Sopenharmony_ci		return -ENOMEM;
119862306a36Sopenharmony_ci	}
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	__iommu_flush_cache(iommu, root, ROOT_SIZE);
120162306a36Sopenharmony_ci	iommu->root_entry = root;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	return 0;
120462306a36Sopenharmony_ci}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_cistatic void iommu_set_root_entry(struct intel_iommu *iommu)
120762306a36Sopenharmony_ci{
120862306a36Sopenharmony_ci	u64 addr;
120962306a36Sopenharmony_ci	u32 sts;
121062306a36Sopenharmony_ci	unsigned long flag;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	addr = virt_to_phys(iommu->root_entry);
121362306a36Sopenharmony_ci	if (sm_supported(iommu))
121462306a36Sopenharmony_ci		addr |= DMA_RTADDR_SMT;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	raw_spin_lock_irqsave(&iommu->register_lock, flag);
121762306a36Sopenharmony_ci	dmar_writeq(iommu->reg + DMAR_RTADDR_REG, addr);
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	/* Make sure hardware complete it */
122262306a36Sopenharmony_ci	IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
122362306a36Sopenharmony_ci		      readl, (sts & DMA_GSTS_RTPS), sts);
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	/*
122862306a36Sopenharmony_ci	 * Hardware invalidates all DMA remapping hardware translation
122962306a36Sopenharmony_ci	 * caches as part of SRTP flow.
123062306a36Sopenharmony_ci	 */
123162306a36Sopenharmony_ci	if (cap_esrtps(iommu->cap))
123262306a36Sopenharmony_ci		return;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
123562306a36Sopenharmony_ci	if (sm_supported(iommu))
123662306a36Sopenharmony_ci		qi_flush_pasid_cache(iommu, 0, QI_PC_GLOBAL, 0);
123762306a36Sopenharmony_ci	iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
123862306a36Sopenharmony_ci}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_civoid iommu_flush_write_buffer(struct intel_iommu *iommu)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	u32 val;
124362306a36Sopenharmony_ci	unsigned long flag;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (!rwbf_quirk && !cap_rwbf(iommu->cap))
124662306a36Sopenharmony_ci		return;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	raw_spin_lock_irqsave(&iommu->register_lock, flag);
124962306a36Sopenharmony_ci	writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	/* Make sure hardware complete it */
125262306a36Sopenharmony_ci	IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
125362306a36Sopenharmony_ci		      readl, (!(val & DMA_GSTS_WBFS)), val);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
125662306a36Sopenharmony_ci}
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci/* return value determine if we need a write buffer flush */
125962306a36Sopenharmony_cistatic void __iommu_flush_context(struct intel_iommu *iommu,
126062306a36Sopenharmony_ci				  u16 did, u16 source_id, u8 function_mask,
126162306a36Sopenharmony_ci				  u64 type)
126262306a36Sopenharmony_ci{
126362306a36Sopenharmony_ci	u64 val = 0;
126462306a36Sopenharmony_ci	unsigned long flag;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	switch (type) {
126762306a36Sopenharmony_ci	case DMA_CCMD_GLOBAL_INVL:
126862306a36Sopenharmony_ci		val = DMA_CCMD_GLOBAL_INVL;
126962306a36Sopenharmony_ci		break;
127062306a36Sopenharmony_ci	case DMA_CCMD_DOMAIN_INVL:
127162306a36Sopenharmony_ci		val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
127262306a36Sopenharmony_ci		break;
127362306a36Sopenharmony_ci	case DMA_CCMD_DEVICE_INVL:
127462306a36Sopenharmony_ci		val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
127562306a36Sopenharmony_ci			| DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
127662306a36Sopenharmony_ci		break;
127762306a36Sopenharmony_ci	default:
127862306a36Sopenharmony_ci		pr_warn("%s: Unexpected context-cache invalidation type 0x%llx\n",
127962306a36Sopenharmony_ci			iommu->name, type);
128062306a36Sopenharmony_ci		return;
128162306a36Sopenharmony_ci	}
128262306a36Sopenharmony_ci	val |= DMA_CCMD_ICC;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	raw_spin_lock_irqsave(&iommu->register_lock, flag);
128562306a36Sopenharmony_ci	dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	/* Make sure hardware complete it */
128862306a36Sopenharmony_ci	IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
128962306a36Sopenharmony_ci		dmar_readq, (!(val & DMA_CCMD_ICC)), val);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
129262306a36Sopenharmony_ci}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci/* return value determine if we need a write buffer flush */
129562306a36Sopenharmony_cistatic void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
129662306a36Sopenharmony_ci				u64 addr, unsigned int size_order, u64 type)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	int tlb_offset = ecap_iotlb_offset(iommu->ecap);
129962306a36Sopenharmony_ci	u64 val = 0, val_iva = 0;
130062306a36Sopenharmony_ci	unsigned long flag;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	switch (type) {
130362306a36Sopenharmony_ci	case DMA_TLB_GLOBAL_FLUSH:
130462306a36Sopenharmony_ci		/* global flush doesn't need set IVA_REG */
130562306a36Sopenharmony_ci		val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
130662306a36Sopenharmony_ci		break;
130762306a36Sopenharmony_ci	case DMA_TLB_DSI_FLUSH:
130862306a36Sopenharmony_ci		val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
130962306a36Sopenharmony_ci		break;
131062306a36Sopenharmony_ci	case DMA_TLB_PSI_FLUSH:
131162306a36Sopenharmony_ci		val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
131262306a36Sopenharmony_ci		/* IH bit is passed in as part of address */
131362306a36Sopenharmony_ci		val_iva = size_order | addr;
131462306a36Sopenharmony_ci		break;
131562306a36Sopenharmony_ci	default:
131662306a36Sopenharmony_ci		pr_warn("%s: Unexpected iotlb invalidation type 0x%llx\n",
131762306a36Sopenharmony_ci			iommu->name, type);
131862306a36Sopenharmony_ci		return;
131962306a36Sopenharmony_ci	}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	if (cap_write_drain(iommu->cap))
132262306a36Sopenharmony_ci		val |= DMA_TLB_WRITE_DRAIN;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	raw_spin_lock_irqsave(&iommu->register_lock, flag);
132562306a36Sopenharmony_ci	/* Note: Only uses first TLB reg currently */
132662306a36Sopenharmony_ci	if (val_iva)
132762306a36Sopenharmony_ci		dmar_writeq(iommu->reg + tlb_offset, val_iva);
132862306a36Sopenharmony_ci	dmar_writeq(iommu->reg + tlb_offset + 8, val);
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	/* Make sure hardware complete it */
133162306a36Sopenharmony_ci	IOMMU_WAIT_OP(iommu, tlb_offset + 8,
133262306a36Sopenharmony_ci		dmar_readq, (!(val & DMA_TLB_IVT)), val);
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	/* check IOTLB invalidation granularity */
133762306a36Sopenharmony_ci	if (DMA_TLB_IAIG(val) == 0)
133862306a36Sopenharmony_ci		pr_err("Flush IOTLB failed\n");
133962306a36Sopenharmony_ci	if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
134062306a36Sopenharmony_ci		pr_debug("TLB flush request %Lx, actual %Lx\n",
134162306a36Sopenharmony_ci			(unsigned long long)DMA_TLB_IIRG(type),
134262306a36Sopenharmony_ci			(unsigned long long)DMA_TLB_IAIG(val));
134362306a36Sopenharmony_ci}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_cistatic struct device_domain_info *
134662306a36Sopenharmony_cidomain_lookup_dev_info(struct dmar_domain *domain,
134762306a36Sopenharmony_ci		       struct intel_iommu *iommu, u8 bus, u8 devfn)
134862306a36Sopenharmony_ci{
134962306a36Sopenharmony_ci	struct device_domain_info *info;
135062306a36Sopenharmony_ci	unsigned long flags;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	spin_lock_irqsave(&domain->lock, flags);
135362306a36Sopenharmony_ci	list_for_each_entry(info, &domain->devices, link) {
135462306a36Sopenharmony_ci		if (info->iommu == iommu && info->bus == bus &&
135562306a36Sopenharmony_ci		    info->devfn == devfn) {
135662306a36Sopenharmony_ci			spin_unlock_irqrestore(&domain->lock, flags);
135762306a36Sopenharmony_ci			return info;
135862306a36Sopenharmony_ci		}
135962306a36Sopenharmony_ci	}
136062306a36Sopenharmony_ci	spin_unlock_irqrestore(&domain->lock, flags);
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	return NULL;
136362306a36Sopenharmony_ci}
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_cistatic void domain_update_iotlb(struct dmar_domain *domain)
136662306a36Sopenharmony_ci{
136762306a36Sopenharmony_ci	struct dev_pasid_info *dev_pasid;
136862306a36Sopenharmony_ci	struct device_domain_info *info;
136962306a36Sopenharmony_ci	bool has_iotlb_device = false;
137062306a36Sopenharmony_ci	unsigned long flags;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	spin_lock_irqsave(&domain->lock, flags);
137362306a36Sopenharmony_ci	list_for_each_entry(info, &domain->devices, link) {
137462306a36Sopenharmony_ci		if (info->ats_enabled) {
137562306a36Sopenharmony_ci			has_iotlb_device = true;
137662306a36Sopenharmony_ci			break;
137762306a36Sopenharmony_ci		}
137862306a36Sopenharmony_ci	}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) {
138162306a36Sopenharmony_ci		info = dev_iommu_priv_get(dev_pasid->dev);
138262306a36Sopenharmony_ci		if (info->ats_enabled) {
138362306a36Sopenharmony_ci			has_iotlb_device = true;
138462306a36Sopenharmony_ci			break;
138562306a36Sopenharmony_ci		}
138662306a36Sopenharmony_ci	}
138762306a36Sopenharmony_ci	domain->has_iotlb_device = has_iotlb_device;
138862306a36Sopenharmony_ci	spin_unlock_irqrestore(&domain->lock, flags);
138962306a36Sopenharmony_ci}
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci/*
139262306a36Sopenharmony_ci * The extra devTLB flush quirk impacts those QAT devices with PCI device
139362306a36Sopenharmony_ci * IDs ranging from 0x4940 to 0x4943. It is exempted from risky_device()
139462306a36Sopenharmony_ci * check because it applies only to the built-in QAT devices and it doesn't
139562306a36Sopenharmony_ci * grant additional privileges.
139662306a36Sopenharmony_ci */
139762306a36Sopenharmony_ci#define BUGGY_QAT_DEVID_MASK 0x4940
139862306a36Sopenharmony_cistatic bool dev_needs_extra_dtlb_flush(struct pci_dev *pdev)
139962306a36Sopenharmony_ci{
140062306a36Sopenharmony_ci	if (pdev->vendor != PCI_VENDOR_ID_INTEL)
140162306a36Sopenharmony_ci		return false;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	if ((pdev->device & 0xfffc) != BUGGY_QAT_DEVID_MASK)
140462306a36Sopenharmony_ci		return false;
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	return true;
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_cistatic void iommu_enable_pci_caps(struct device_domain_info *info)
141062306a36Sopenharmony_ci{
141162306a36Sopenharmony_ci	struct pci_dev *pdev;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	if (!dev_is_pci(info->dev))
141462306a36Sopenharmony_ci		return;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	pdev = to_pci_dev(info->dev);
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	/* The PCIe spec, in its wisdom, declares that the behaviour of
141962306a36Sopenharmony_ci	   the device if you enable PASID support after ATS support is
142062306a36Sopenharmony_ci	   undefined. So always enable PASID support on devices which
142162306a36Sopenharmony_ci	   have it, even if we can't yet know if we're ever going to
142262306a36Sopenharmony_ci	   use it. */
142362306a36Sopenharmony_ci	if (info->pasid_supported && !pci_enable_pasid(pdev, info->pasid_supported & ~1))
142462306a36Sopenharmony_ci		info->pasid_enabled = 1;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	if (info->ats_supported && pci_ats_page_aligned(pdev) &&
142762306a36Sopenharmony_ci	    !pci_enable_ats(pdev, VTD_PAGE_SHIFT)) {
142862306a36Sopenharmony_ci		info->ats_enabled = 1;
142962306a36Sopenharmony_ci		domain_update_iotlb(info->domain);
143062306a36Sopenharmony_ci	}
143162306a36Sopenharmony_ci}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_cistatic void iommu_disable_pci_caps(struct device_domain_info *info)
143462306a36Sopenharmony_ci{
143562306a36Sopenharmony_ci	struct pci_dev *pdev;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	if (!dev_is_pci(info->dev))
143862306a36Sopenharmony_ci		return;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	pdev = to_pci_dev(info->dev);
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	if (info->ats_enabled) {
144362306a36Sopenharmony_ci		pci_disable_ats(pdev);
144462306a36Sopenharmony_ci		info->ats_enabled = 0;
144562306a36Sopenharmony_ci		domain_update_iotlb(info->domain);
144662306a36Sopenharmony_ci	}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	if (info->pasid_enabled) {
144962306a36Sopenharmony_ci		pci_disable_pasid(pdev);
145062306a36Sopenharmony_ci		info->pasid_enabled = 0;
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_cistatic void __iommu_flush_dev_iotlb(struct device_domain_info *info,
145562306a36Sopenharmony_ci				    u64 addr, unsigned int mask)
145662306a36Sopenharmony_ci{
145762306a36Sopenharmony_ci	u16 sid, qdep;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	if (!info || !info->ats_enabled)
146062306a36Sopenharmony_ci		return;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	sid = info->bus << 8 | info->devfn;
146362306a36Sopenharmony_ci	qdep = info->ats_qdep;
146462306a36Sopenharmony_ci	qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
146562306a36Sopenharmony_ci			   qdep, addr, mask);
146662306a36Sopenharmony_ci	quirk_extra_dev_tlb_flush(info, addr, mask, IOMMU_NO_PASID, qdep);
146762306a36Sopenharmony_ci}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_cistatic void iommu_flush_dev_iotlb(struct dmar_domain *domain,
147062306a36Sopenharmony_ci				  u64 addr, unsigned mask)
147162306a36Sopenharmony_ci{
147262306a36Sopenharmony_ci	struct dev_pasid_info *dev_pasid;
147362306a36Sopenharmony_ci	struct device_domain_info *info;
147462306a36Sopenharmony_ci	unsigned long flags;
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	if (!domain->has_iotlb_device)
147762306a36Sopenharmony_ci		return;
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	spin_lock_irqsave(&domain->lock, flags);
148062306a36Sopenharmony_ci	list_for_each_entry(info, &domain->devices, link)
148162306a36Sopenharmony_ci		__iommu_flush_dev_iotlb(info, addr, mask);
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain) {
148462306a36Sopenharmony_ci		info = dev_iommu_priv_get(dev_pasid->dev);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci		if (!info->ats_enabled)
148762306a36Sopenharmony_ci			continue;
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci		qi_flush_dev_iotlb_pasid(info->iommu,
149062306a36Sopenharmony_ci					 PCI_DEVID(info->bus, info->devfn),
149162306a36Sopenharmony_ci					 info->pfsid, dev_pasid->pasid,
149262306a36Sopenharmony_ci					 info->ats_qdep, addr,
149362306a36Sopenharmony_ci					 mask);
149462306a36Sopenharmony_ci	}
149562306a36Sopenharmony_ci	spin_unlock_irqrestore(&domain->lock, flags);
149662306a36Sopenharmony_ci}
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_cistatic void domain_flush_pasid_iotlb(struct intel_iommu *iommu,
149962306a36Sopenharmony_ci				     struct dmar_domain *domain, u64 addr,
150062306a36Sopenharmony_ci				     unsigned long npages, bool ih)
150162306a36Sopenharmony_ci{
150262306a36Sopenharmony_ci	u16 did = domain_id_iommu(domain, iommu);
150362306a36Sopenharmony_ci	struct dev_pasid_info *dev_pasid;
150462306a36Sopenharmony_ci	unsigned long flags;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	spin_lock_irqsave(&domain->lock, flags);
150762306a36Sopenharmony_ci	list_for_each_entry(dev_pasid, &domain->dev_pasids, link_domain)
150862306a36Sopenharmony_ci		qi_flush_piotlb(iommu, did, dev_pasid->pasid, addr, npages, ih);
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	if (!list_empty(&domain->devices))
151162306a36Sopenharmony_ci		qi_flush_piotlb(iommu, did, IOMMU_NO_PASID, addr, npages, ih);
151262306a36Sopenharmony_ci	spin_unlock_irqrestore(&domain->lock, flags);
151362306a36Sopenharmony_ci}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_cistatic void iommu_flush_iotlb_psi(struct intel_iommu *iommu,
151662306a36Sopenharmony_ci				  struct dmar_domain *domain,
151762306a36Sopenharmony_ci				  unsigned long pfn, unsigned int pages,
151862306a36Sopenharmony_ci				  int ih, int map)
151962306a36Sopenharmony_ci{
152062306a36Sopenharmony_ci	unsigned int aligned_pages = __roundup_pow_of_two(pages);
152162306a36Sopenharmony_ci	unsigned int mask = ilog2(aligned_pages);
152262306a36Sopenharmony_ci	uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
152362306a36Sopenharmony_ci	u16 did = domain_id_iommu(domain, iommu);
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	if (WARN_ON(!pages))
152662306a36Sopenharmony_ci		return;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	if (ih)
152962306a36Sopenharmony_ci		ih = 1 << 6;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	if (domain->use_first_level) {
153262306a36Sopenharmony_ci		domain_flush_pasid_iotlb(iommu, domain, addr, pages, ih);
153362306a36Sopenharmony_ci	} else {
153462306a36Sopenharmony_ci		unsigned long bitmask = aligned_pages - 1;
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci		/*
153762306a36Sopenharmony_ci		 * PSI masks the low order bits of the base address. If the
153862306a36Sopenharmony_ci		 * address isn't aligned to the mask, then compute a mask value
153962306a36Sopenharmony_ci		 * needed to ensure the target range is flushed.
154062306a36Sopenharmony_ci		 */
154162306a36Sopenharmony_ci		if (unlikely(bitmask & pfn)) {
154262306a36Sopenharmony_ci			unsigned long end_pfn = pfn + pages - 1, shared_bits;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci			/*
154562306a36Sopenharmony_ci			 * Since end_pfn <= pfn + bitmask, the only way bits
154662306a36Sopenharmony_ci			 * higher than bitmask can differ in pfn and end_pfn is
154762306a36Sopenharmony_ci			 * by carrying. This means after masking out bitmask,
154862306a36Sopenharmony_ci			 * high bits starting with the first set bit in
154962306a36Sopenharmony_ci			 * shared_bits are all equal in both pfn and end_pfn.
155062306a36Sopenharmony_ci			 */
155162306a36Sopenharmony_ci			shared_bits = ~(pfn ^ end_pfn) & ~bitmask;
155262306a36Sopenharmony_ci			mask = shared_bits ? __ffs(shared_bits) : BITS_PER_LONG;
155362306a36Sopenharmony_ci		}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci		/*
155662306a36Sopenharmony_ci		 * Fallback to domain selective flush if no PSI support or
155762306a36Sopenharmony_ci		 * the size is too big.
155862306a36Sopenharmony_ci		 */
155962306a36Sopenharmony_ci		if (!cap_pgsel_inv(iommu->cap) ||
156062306a36Sopenharmony_ci		    mask > cap_max_amask_val(iommu->cap))
156162306a36Sopenharmony_ci			iommu->flush.flush_iotlb(iommu, did, 0, 0,
156262306a36Sopenharmony_ci							DMA_TLB_DSI_FLUSH);
156362306a36Sopenharmony_ci		else
156462306a36Sopenharmony_ci			iommu->flush.flush_iotlb(iommu, did, addr | ih, mask,
156562306a36Sopenharmony_ci							DMA_TLB_PSI_FLUSH);
156662306a36Sopenharmony_ci	}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	/*
156962306a36Sopenharmony_ci	 * In caching mode, changes of pages from non-present to present require
157062306a36Sopenharmony_ci	 * flush. However, device IOTLB doesn't need to be flushed in this case.
157162306a36Sopenharmony_ci	 */
157262306a36Sopenharmony_ci	if (!cap_caching_mode(iommu->cap) || !map)
157362306a36Sopenharmony_ci		iommu_flush_dev_iotlb(domain, addr, mask);
157462306a36Sopenharmony_ci}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci/* Notification for newly created mappings */
157762306a36Sopenharmony_cistatic inline void __mapping_notify_one(struct intel_iommu *iommu,
157862306a36Sopenharmony_ci					struct dmar_domain *domain,
157962306a36Sopenharmony_ci					unsigned long pfn, unsigned int pages)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci	/*
158262306a36Sopenharmony_ci	 * It's a non-present to present mapping. Only flush if caching mode
158362306a36Sopenharmony_ci	 * and second level.
158462306a36Sopenharmony_ci	 */
158562306a36Sopenharmony_ci	if (cap_caching_mode(iommu->cap) && !domain->use_first_level)
158662306a36Sopenharmony_ci		iommu_flush_iotlb_psi(iommu, domain, pfn, pages, 0, 1);
158762306a36Sopenharmony_ci	else
158862306a36Sopenharmony_ci		iommu_flush_write_buffer(iommu);
158962306a36Sopenharmony_ci}
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_cistatic void intel_flush_iotlb_all(struct iommu_domain *domain)
159262306a36Sopenharmony_ci{
159362306a36Sopenharmony_ci	struct dmar_domain *dmar_domain = to_dmar_domain(domain);
159462306a36Sopenharmony_ci	struct iommu_domain_info *info;
159562306a36Sopenharmony_ci	unsigned long idx;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	xa_for_each(&dmar_domain->iommu_array, idx, info) {
159862306a36Sopenharmony_ci		struct intel_iommu *iommu = info->iommu;
159962306a36Sopenharmony_ci		u16 did = domain_id_iommu(dmar_domain, iommu);
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci		if (dmar_domain->use_first_level)
160262306a36Sopenharmony_ci			domain_flush_pasid_iotlb(iommu, dmar_domain, 0, -1, 0);
160362306a36Sopenharmony_ci		else
160462306a36Sopenharmony_ci			iommu->flush.flush_iotlb(iommu, did, 0, 0,
160562306a36Sopenharmony_ci						 DMA_TLB_DSI_FLUSH);
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci		if (!cap_caching_mode(iommu->cap))
160862306a36Sopenharmony_ci			iommu_flush_dev_iotlb(dmar_domain, 0, MAX_AGAW_PFN_WIDTH);
160962306a36Sopenharmony_ci	}
161062306a36Sopenharmony_ci}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_cistatic void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
161362306a36Sopenharmony_ci{
161462306a36Sopenharmony_ci	u32 pmen;
161562306a36Sopenharmony_ci	unsigned long flags;
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	if (!cap_plmr(iommu->cap) && !cap_phmr(iommu->cap))
161862306a36Sopenharmony_ci		return;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	raw_spin_lock_irqsave(&iommu->register_lock, flags);
162162306a36Sopenharmony_ci	pmen = readl(iommu->reg + DMAR_PMEN_REG);
162262306a36Sopenharmony_ci	pmen &= ~DMA_PMEN_EPM;
162362306a36Sopenharmony_ci	writel(pmen, iommu->reg + DMAR_PMEN_REG);
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	/* wait for the protected region status bit to clear */
162662306a36Sopenharmony_ci	IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
162762306a36Sopenharmony_ci		readl, !(pmen & DMA_PMEN_PRS), pmen);
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
163062306a36Sopenharmony_ci}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_cistatic void iommu_enable_translation(struct intel_iommu *iommu)
163362306a36Sopenharmony_ci{
163462306a36Sopenharmony_ci	u32 sts;
163562306a36Sopenharmony_ci	unsigned long flags;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	raw_spin_lock_irqsave(&iommu->register_lock, flags);
163862306a36Sopenharmony_ci	iommu->gcmd |= DMA_GCMD_TE;
163962306a36Sopenharmony_ci	writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci	/* Make sure hardware complete it */
164262306a36Sopenharmony_ci	IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
164362306a36Sopenharmony_ci		      readl, (sts & DMA_GSTS_TES), sts);
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
164662306a36Sopenharmony_ci}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_cistatic void iommu_disable_translation(struct intel_iommu *iommu)
164962306a36Sopenharmony_ci{
165062306a36Sopenharmony_ci	u32 sts;
165162306a36Sopenharmony_ci	unsigned long flag;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	if (iommu_skip_te_disable && iommu->drhd->gfx_dedicated &&
165462306a36Sopenharmony_ci	    (cap_read_drain(iommu->cap) || cap_write_drain(iommu->cap)))
165562306a36Sopenharmony_ci		return;
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	raw_spin_lock_irqsave(&iommu->register_lock, flag);
165862306a36Sopenharmony_ci	iommu->gcmd &= ~DMA_GCMD_TE;
165962306a36Sopenharmony_ci	writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	/* Make sure hardware complete it */
166262306a36Sopenharmony_ci	IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
166362306a36Sopenharmony_ci		      readl, (!(sts & DMA_GSTS_TES)), sts);
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
166662306a36Sopenharmony_ci}
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_cistatic int iommu_init_domains(struct intel_iommu *iommu)
166962306a36Sopenharmony_ci{
167062306a36Sopenharmony_ci	u32 ndomains;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	ndomains = cap_ndoms(iommu->cap);
167362306a36Sopenharmony_ci	pr_debug("%s: Number of Domains supported <%d>\n",
167462306a36Sopenharmony_ci		 iommu->name, ndomains);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	spin_lock_init(&iommu->lock);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	iommu->domain_ids = bitmap_zalloc(ndomains, GFP_KERNEL);
167962306a36Sopenharmony_ci	if (!iommu->domain_ids)
168062306a36Sopenharmony_ci		return -ENOMEM;
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	/*
168362306a36Sopenharmony_ci	 * If Caching mode is set, then invalid translations are tagged
168462306a36Sopenharmony_ci	 * with domain-id 0, hence we need to pre-allocate it. We also
168562306a36Sopenharmony_ci	 * use domain-id 0 as a marker for non-allocated domain-id, so
168662306a36Sopenharmony_ci	 * make sure it is not used for a real domain.
168762306a36Sopenharmony_ci	 */
168862306a36Sopenharmony_ci	set_bit(0, iommu->domain_ids);
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	/*
169162306a36Sopenharmony_ci	 * Vt-d spec rev3.0 (section 6.2.3.1) requires that each pasid
169262306a36Sopenharmony_ci	 * entry for first-level or pass-through translation modes should
169362306a36Sopenharmony_ci	 * be programmed with a domain id different from those used for
169462306a36Sopenharmony_ci	 * second-level or nested translation. We reserve a domain id for
169562306a36Sopenharmony_ci	 * this purpose.
169662306a36Sopenharmony_ci	 */
169762306a36Sopenharmony_ci	if (sm_supported(iommu))
169862306a36Sopenharmony_ci		set_bit(FLPT_DEFAULT_DID, iommu->domain_ids);
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	return 0;
170162306a36Sopenharmony_ci}
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_cistatic void disable_dmar_iommu(struct intel_iommu *iommu)
170462306a36Sopenharmony_ci{
170562306a36Sopenharmony_ci	if (!iommu->domain_ids)
170662306a36Sopenharmony_ci		return;
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	/*
170962306a36Sopenharmony_ci	 * All iommu domains must have been detached from the devices,
171062306a36Sopenharmony_ci	 * hence there should be no domain IDs in use.
171162306a36Sopenharmony_ci	 */
171262306a36Sopenharmony_ci	if (WARN_ON(bitmap_weight(iommu->domain_ids, cap_ndoms(iommu->cap))
171362306a36Sopenharmony_ci		    > NUM_RESERVED_DID))
171462306a36Sopenharmony_ci		return;
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	if (iommu->gcmd & DMA_GCMD_TE)
171762306a36Sopenharmony_ci		iommu_disable_translation(iommu);
171862306a36Sopenharmony_ci}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_cistatic void free_dmar_iommu(struct intel_iommu *iommu)
172162306a36Sopenharmony_ci{
172262306a36Sopenharmony_ci	if (iommu->domain_ids) {
172362306a36Sopenharmony_ci		bitmap_free(iommu->domain_ids);
172462306a36Sopenharmony_ci		iommu->domain_ids = NULL;
172562306a36Sopenharmony_ci	}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	if (iommu->copied_tables) {
172862306a36Sopenharmony_ci		bitmap_free(iommu->copied_tables);
172962306a36Sopenharmony_ci		iommu->copied_tables = NULL;
173062306a36Sopenharmony_ci	}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	/* free context mapping */
173362306a36Sopenharmony_ci	free_context_table(iommu);
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci#ifdef CONFIG_INTEL_IOMMU_SVM
173662306a36Sopenharmony_ci	if (pasid_supported(iommu)) {
173762306a36Sopenharmony_ci		if (ecap_prs(iommu->ecap))
173862306a36Sopenharmony_ci			intel_svm_finish_prq(iommu);
173962306a36Sopenharmony_ci	}
174062306a36Sopenharmony_ci#endif
174162306a36Sopenharmony_ci}
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci/*
174462306a36Sopenharmony_ci * Check and return whether first level is used by default for
174562306a36Sopenharmony_ci * DMA translation.
174662306a36Sopenharmony_ci */
174762306a36Sopenharmony_cistatic bool first_level_by_default(unsigned int type)
174862306a36Sopenharmony_ci{
174962306a36Sopenharmony_ci	/* Only SL is available in legacy mode */
175062306a36Sopenharmony_ci	if (!scalable_mode_support())
175162306a36Sopenharmony_ci		return false;
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci	/* Only level (either FL or SL) is available, just use it */
175462306a36Sopenharmony_ci	if (intel_cap_flts_sanity() ^ intel_cap_slts_sanity())
175562306a36Sopenharmony_ci		return intel_cap_flts_sanity();
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	/* Both levels are available, decide it based on domain type */
175862306a36Sopenharmony_ci	return type != IOMMU_DOMAIN_UNMANAGED;
175962306a36Sopenharmony_ci}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_cistatic struct dmar_domain *alloc_domain(unsigned int type)
176262306a36Sopenharmony_ci{
176362306a36Sopenharmony_ci	struct dmar_domain *domain;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	domain = kzalloc(sizeof(*domain), GFP_KERNEL);
176662306a36Sopenharmony_ci	if (!domain)
176762306a36Sopenharmony_ci		return NULL;
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	domain->nid = NUMA_NO_NODE;
177062306a36Sopenharmony_ci	if (first_level_by_default(type))
177162306a36Sopenharmony_ci		domain->use_first_level = true;
177262306a36Sopenharmony_ci	domain->has_iotlb_device = false;
177362306a36Sopenharmony_ci	INIT_LIST_HEAD(&domain->devices);
177462306a36Sopenharmony_ci	INIT_LIST_HEAD(&domain->dev_pasids);
177562306a36Sopenharmony_ci	spin_lock_init(&domain->lock);
177662306a36Sopenharmony_ci	xa_init(&domain->iommu_array);
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	return domain;
177962306a36Sopenharmony_ci}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_cistatic int domain_attach_iommu(struct dmar_domain *domain,
178262306a36Sopenharmony_ci			       struct intel_iommu *iommu)
178362306a36Sopenharmony_ci{
178462306a36Sopenharmony_ci	struct iommu_domain_info *info, *curr;
178562306a36Sopenharmony_ci	unsigned long ndomains;
178662306a36Sopenharmony_ci	int num, ret = -ENOSPC;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	info = kzalloc(sizeof(*info), GFP_KERNEL);
178962306a36Sopenharmony_ci	if (!info)
179062306a36Sopenharmony_ci		return -ENOMEM;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	spin_lock(&iommu->lock);
179362306a36Sopenharmony_ci	curr = xa_load(&domain->iommu_array, iommu->seq_id);
179462306a36Sopenharmony_ci	if (curr) {
179562306a36Sopenharmony_ci		curr->refcnt++;
179662306a36Sopenharmony_ci		spin_unlock(&iommu->lock);
179762306a36Sopenharmony_ci		kfree(info);
179862306a36Sopenharmony_ci		return 0;
179962306a36Sopenharmony_ci	}
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	ndomains = cap_ndoms(iommu->cap);
180262306a36Sopenharmony_ci	num = find_first_zero_bit(iommu->domain_ids, ndomains);
180362306a36Sopenharmony_ci	if (num >= ndomains) {
180462306a36Sopenharmony_ci		pr_err("%s: No free domain ids\n", iommu->name);
180562306a36Sopenharmony_ci		goto err_unlock;
180662306a36Sopenharmony_ci	}
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	set_bit(num, iommu->domain_ids);
180962306a36Sopenharmony_ci	info->refcnt	= 1;
181062306a36Sopenharmony_ci	info->did	= num;
181162306a36Sopenharmony_ci	info->iommu	= iommu;
181262306a36Sopenharmony_ci	curr = xa_cmpxchg(&domain->iommu_array, iommu->seq_id,
181362306a36Sopenharmony_ci			  NULL, info, GFP_ATOMIC);
181462306a36Sopenharmony_ci	if (curr) {
181562306a36Sopenharmony_ci		ret = xa_err(curr) ? : -EBUSY;
181662306a36Sopenharmony_ci		goto err_clear;
181762306a36Sopenharmony_ci	}
181862306a36Sopenharmony_ci	domain_update_iommu_cap(domain);
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	spin_unlock(&iommu->lock);
182162306a36Sopenharmony_ci	return 0;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_cierr_clear:
182462306a36Sopenharmony_ci	clear_bit(info->did, iommu->domain_ids);
182562306a36Sopenharmony_cierr_unlock:
182662306a36Sopenharmony_ci	spin_unlock(&iommu->lock);
182762306a36Sopenharmony_ci	kfree(info);
182862306a36Sopenharmony_ci	return ret;
182962306a36Sopenharmony_ci}
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_cistatic void domain_detach_iommu(struct dmar_domain *domain,
183262306a36Sopenharmony_ci				struct intel_iommu *iommu)
183362306a36Sopenharmony_ci{
183462306a36Sopenharmony_ci	struct iommu_domain_info *info;
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	spin_lock(&iommu->lock);
183762306a36Sopenharmony_ci	info = xa_load(&domain->iommu_array, iommu->seq_id);
183862306a36Sopenharmony_ci	if (--info->refcnt == 0) {
183962306a36Sopenharmony_ci		clear_bit(info->did, iommu->domain_ids);
184062306a36Sopenharmony_ci		xa_erase(&domain->iommu_array, iommu->seq_id);
184162306a36Sopenharmony_ci		domain->nid = NUMA_NO_NODE;
184262306a36Sopenharmony_ci		domain_update_iommu_cap(domain);
184362306a36Sopenharmony_ci		kfree(info);
184462306a36Sopenharmony_ci	}
184562306a36Sopenharmony_ci	spin_unlock(&iommu->lock);
184662306a36Sopenharmony_ci}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_cistatic inline int guestwidth_to_adjustwidth(int gaw)
184962306a36Sopenharmony_ci{
185062306a36Sopenharmony_ci	int agaw;
185162306a36Sopenharmony_ci	int r = (gaw - 12) % 9;
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	if (r == 0)
185462306a36Sopenharmony_ci		agaw = gaw;
185562306a36Sopenharmony_ci	else
185662306a36Sopenharmony_ci		agaw = gaw + 9 - r;
185762306a36Sopenharmony_ci	if (agaw > 64)
185862306a36Sopenharmony_ci		agaw = 64;
185962306a36Sopenharmony_ci	return agaw;
186062306a36Sopenharmony_ci}
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_cistatic void domain_exit(struct dmar_domain *domain)
186362306a36Sopenharmony_ci{
186462306a36Sopenharmony_ci	if (domain->pgd) {
186562306a36Sopenharmony_ci		LIST_HEAD(freelist);
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci		domain_unmap(domain, 0, DOMAIN_MAX_PFN(domain->gaw), &freelist);
186862306a36Sopenharmony_ci		put_pages_list(&freelist);
186962306a36Sopenharmony_ci	}
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	if (WARN_ON(!list_empty(&domain->devices)))
187262306a36Sopenharmony_ci		return;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	kfree(domain);
187562306a36Sopenharmony_ci}
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci/*
187862306a36Sopenharmony_ci * Get the PASID directory size for scalable mode context entry.
187962306a36Sopenharmony_ci * Value of X in the PDTS field of a scalable mode context entry
188062306a36Sopenharmony_ci * indicates PASID directory with 2^(X + 7) entries.
188162306a36Sopenharmony_ci */
188262306a36Sopenharmony_cistatic inline unsigned long context_get_sm_pds(struct pasid_table *table)
188362306a36Sopenharmony_ci{
188462306a36Sopenharmony_ci	unsigned long pds, max_pde;
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	max_pde = table->max_pasid >> PASID_PDE_SHIFT;
188762306a36Sopenharmony_ci	pds = find_first_bit(&max_pde, MAX_NR_PASID_BITS);
188862306a36Sopenharmony_ci	if (pds < 7)
188962306a36Sopenharmony_ci		return 0;
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	return pds - 7;
189262306a36Sopenharmony_ci}
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci/*
189562306a36Sopenharmony_ci * Set the RID_PASID field of a scalable mode context entry. The
189662306a36Sopenharmony_ci * IOMMU hardware will use the PASID value set in this field for
189762306a36Sopenharmony_ci * DMA translations of DMA requests without PASID.
189862306a36Sopenharmony_ci */
189962306a36Sopenharmony_cistatic inline void
190062306a36Sopenharmony_cicontext_set_sm_rid2pasid(struct context_entry *context, unsigned long pasid)
190162306a36Sopenharmony_ci{
190262306a36Sopenharmony_ci	context->hi |= pasid & ((1 << 20) - 1);
190362306a36Sopenharmony_ci}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci/*
190662306a36Sopenharmony_ci * Set the DTE(Device-TLB Enable) field of a scalable mode context
190762306a36Sopenharmony_ci * entry.
190862306a36Sopenharmony_ci */
190962306a36Sopenharmony_cistatic inline void context_set_sm_dte(struct context_entry *context)
191062306a36Sopenharmony_ci{
191162306a36Sopenharmony_ci	context->lo |= BIT_ULL(2);
191262306a36Sopenharmony_ci}
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci/*
191562306a36Sopenharmony_ci * Set the PRE(Page Request Enable) field of a scalable mode context
191662306a36Sopenharmony_ci * entry.
191762306a36Sopenharmony_ci */
191862306a36Sopenharmony_cistatic inline void context_set_sm_pre(struct context_entry *context)
191962306a36Sopenharmony_ci{
192062306a36Sopenharmony_ci	context->lo |= BIT_ULL(4);
192162306a36Sopenharmony_ci}
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci/* Convert value to context PASID directory size field coding. */
192462306a36Sopenharmony_ci#define context_pdts(pds)	(((pds) & 0x7) << 9)
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_cistatic int domain_context_mapping_one(struct dmar_domain *domain,
192762306a36Sopenharmony_ci				      struct intel_iommu *iommu,
192862306a36Sopenharmony_ci				      struct pasid_table *table,
192962306a36Sopenharmony_ci				      u8 bus, u8 devfn)
193062306a36Sopenharmony_ci{
193162306a36Sopenharmony_ci	struct device_domain_info *info =
193262306a36Sopenharmony_ci			domain_lookup_dev_info(domain, iommu, bus, devfn);
193362306a36Sopenharmony_ci	u16 did = domain_id_iommu(domain, iommu);
193462306a36Sopenharmony_ci	int translation = CONTEXT_TT_MULTI_LEVEL;
193562306a36Sopenharmony_ci	struct context_entry *context;
193662306a36Sopenharmony_ci	int ret;
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	if (hw_pass_through && domain_type_is_si(domain))
193962306a36Sopenharmony_ci		translation = CONTEXT_TT_PASS_THROUGH;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	pr_debug("Set context mapping for %02x:%02x.%d\n",
194262306a36Sopenharmony_ci		bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	spin_lock(&iommu->lock);
194562306a36Sopenharmony_ci	ret = -ENOMEM;
194662306a36Sopenharmony_ci	context = iommu_context_addr(iommu, bus, devfn, 1);
194762306a36Sopenharmony_ci	if (!context)
194862306a36Sopenharmony_ci		goto out_unlock;
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	ret = 0;
195162306a36Sopenharmony_ci	if (context_present(context) && !context_copied(iommu, bus, devfn))
195262306a36Sopenharmony_ci		goto out_unlock;
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	/*
195562306a36Sopenharmony_ci	 * For kdump cases, old valid entries may be cached due to the
195662306a36Sopenharmony_ci	 * in-flight DMA and copied pgtable, but there is no unmapping
195762306a36Sopenharmony_ci	 * behaviour for them, thus we need an explicit cache flush for
195862306a36Sopenharmony_ci	 * the newly-mapped device. For kdump, at this point, the device
195962306a36Sopenharmony_ci	 * is supposed to finish reset at its driver probe stage, so no
196062306a36Sopenharmony_ci	 * in-flight DMA will exist, and we don't need to worry anymore
196162306a36Sopenharmony_ci	 * hereafter.
196262306a36Sopenharmony_ci	 */
196362306a36Sopenharmony_ci	if (context_copied(iommu, bus, devfn)) {
196462306a36Sopenharmony_ci		u16 did_old = context_domain_id(context);
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci		if (did_old < cap_ndoms(iommu->cap)) {
196762306a36Sopenharmony_ci			iommu->flush.flush_context(iommu, did_old,
196862306a36Sopenharmony_ci						   (((u16)bus) << 8) | devfn,
196962306a36Sopenharmony_ci						   DMA_CCMD_MASK_NOBIT,
197062306a36Sopenharmony_ci						   DMA_CCMD_DEVICE_INVL);
197162306a36Sopenharmony_ci			iommu->flush.flush_iotlb(iommu, did_old, 0, 0,
197262306a36Sopenharmony_ci						 DMA_TLB_DSI_FLUSH);
197362306a36Sopenharmony_ci		}
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci		clear_context_copied(iommu, bus, devfn);
197662306a36Sopenharmony_ci	}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci	context_clear_entry(context);
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	if (sm_supported(iommu)) {
198162306a36Sopenharmony_ci		unsigned long pds;
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci		/* Setup the PASID DIR pointer: */
198462306a36Sopenharmony_ci		pds = context_get_sm_pds(table);
198562306a36Sopenharmony_ci		context->lo = (u64)virt_to_phys(table->table) |
198662306a36Sopenharmony_ci				context_pdts(pds);
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci		/* Setup the RID_PASID field: */
198962306a36Sopenharmony_ci		context_set_sm_rid2pasid(context, IOMMU_NO_PASID);
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci		/*
199262306a36Sopenharmony_ci		 * Setup the Device-TLB enable bit and Page request
199362306a36Sopenharmony_ci		 * Enable bit:
199462306a36Sopenharmony_ci		 */
199562306a36Sopenharmony_ci		if (info && info->ats_supported)
199662306a36Sopenharmony_ci			context_set_sm_dte(context);
199762306a36Sopenharmony_ci		if (info && info->pri_supported)
199862306a36Sopenharmony_ci			context_set_sm_pre(context);
199962306a36Sopenharmony_ci		if (info && info->pasid_supported)
200062306a36Sopenharmony_ci			context_set_pasid(context);
200162306a36Sopenharmony_ci	} else {
200262306a36Sopenharmony_ci		struct dma_pte *pgd = domain->pgd;
200362306a36Sopenharmony_ci		int agaw;
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci		context_set_domain_id(context, did);
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci		if (translation != CONTEXT_TT_PASS_THROUGH) {
200862306a36Sopenharmony_ci			/*
200962306a36Sopenharmony_ci			 * Skip top levels of page tables for iommu which has
201062306a36Sopenharmony_ci			 * less agaw than default. Unnecessary for PT mode.
201162306a36Sopenharmony_ci			 */
201262306a36Sopenharmony_ci			for (agaw = domain->agaw; agaw > iommu->agaw; agaw--) {
201362306a36Sopenharmony_ci				ret = -ENOMEM;
201462306a36Sopenharmony_ci				pgd = phys_to_virt(dma_pte_addr(pgd));
201562306a36Sopenharmony_ci				if (!dma_pte_present(pgd))
201662306a36Sopenharmony_ci					goto out_unlock;
201762306a36Sopenharmony_ci			}
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci			if (info && info->ats_supported)
202062306a36Sopenharmony_ci				translation = CONTEXT_TT_DEV_IOTLB;
202162306a36Sopenharmony_ci			else
202262306a36Sopenharmony_ci				translation = CONTEXT_TT_MULTI_LEVEL;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci			context_set_address_root(context, virt_to_phys(pgd));
202562306a36Sopenharmony_ci			context_set_address_width(context, agaw);
202662306a36Sopenharmony_ci		} else {
202762306a36Sopenharmony_ci			/*
202862306a36Sopenharmony_ci			 * In pass through mode, AW must be programmed to
202962306a36Sopenharmony_ci			 * indicate the largest AGAW value supported by
203062306a36Sopenharmony_ci			 * hardware. And ASR is ignored by hardware.
203162306a36Sopenharmony_ci			 */
203262306a36Sopenharmony_ci			context_set_address_width(context, iommu->msagaw);
203362306a36Sopenharmony_ci		}
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_ci		context_set_translation_type(context, translation);
203662306a36Sopenharmony_ci	}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	context_set_fault_enable(context);
203962306a36Sopenharmony_ci	context_set_present(context);
204062306a36Sopenharmony_ci	if (!ecap_coherent(iommu->ecap))
204162306a36Sopenharmony_ci		clflush_cache_range(context, sizeof(*context));
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	/*
204462306a36Sopenharmony_ci	 * It's a non-present to present mapping. If hardware doesn't cache
204562306a36Sopenharmony_ci	 * non-present entry we only need to flush the write-buffer. If the
204662306a36Sopenharmony_ci	 * _does_ cache non-present entries, then it does so in the special
204762306a36Sopenharmony_ci	 * domain #0, which we have to flush:
204862306a36Sopenharmony_ci	 */
204962306a36Sopenharmony_ci	if (cap_caching_mode(iommu->cap)) {
205062306a36Sopenharmony_ci		iommu->flush.flush_context(iommu, 0,
205162306a36Sopenharmony_ci					   (((u16)bus) << 8) | devfn,
205262306a36Sopenharmony_ci					   DMA_CCMD_MASK_NOBIT,
205362306a36Sopenharmony_ci					   DMA_CCMD_DEVICE_INVL);
205462306a36Sopenharmony_ci		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
205562306a36Sopenharmony_ci	} else {
205662306a36Sopenharmony_ci		iommu_flush_write_buffer(iommu);
205762306a36Sopenharmony_ci	}
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	ret = 0;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ciout_unlock:
206262306a36Sopenharmony_ci	spin_unlock(&iommu->lock);
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	return ret;
206562306a36Sopenharmony_ci}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_cistruct domain_context_mapping_data {
206862306a36Sopenharmony_ci	struct dmar_domain *domain;
206962306a36Sopenharmony_ci	struct intel_iommu *iommu;
207062306a36Sopenharmony_ci	struct pasid_table *table;
207162306a36Sopenharmony_ci};
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_cistatic int domain_context_mapping_cb(struct pci_dev *pdev,
207462306a36Sopenharmony_ci				     u16 alias, void *opaque)
207562306a36Sopenharmony_ci{
207662306a36Sopenharmony_ci	struct domain_context_mapping_data *data = opaque;
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci	return domain_context_mapping_one(data->domain, data->iommu,
207962306a36Sopenharmony_ci					  data->table, PCI_BUS_NUM(alias),
208062306a36Sopenharmony_ci					  alias & 0xff);
208162306a36Sopenharmony_ci}
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_cistatic int
208462306a36Sopenharmony_cidomain_context_mapping(struct dmar_domain *domain, struct device *dev)
208562306a36Sopenharmony_ci{
208662306a36Sopenharmony_ci	struct domain_context_mapping_data data;
208762306a36Sopenharmony_ci	struct pasid_table *table;
208862306a36Sopenharmony_ci	struct intel_iommu *iommu;
208962306a36Sopenharmony_ci	u8 bus, devfn;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	iommu = device_to_iommu(dev, &bus, &devfn);
209262306a36Sopenharmony_ci	if (!iommu)
209362306a36Sopenharmony_ci		return -ENODEV;
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	table = intel_pasid_get_table(dev);
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	if (!dev_is_pci(dev))
209862306a36Sopenharmony_ci		return domain_context_mapping_one(domain, iommu, table,
209962306a36Sopenharmony_ci						  bus, devfn);
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	data.domain = domain;
210262306a36Sopenharmony_ci	data.iommu = iommu;
210362306a36Sopenharmony_ci	data.table = table;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci	return pci_for_each_dma_alias(to_pci_dev(dev),
210662306a36Sopenharmony_ci				      &domain_context_mapping_cb, &data);
210762306a36Sopenharmony_ci}
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci/* Returns a number of VTD pages, but aligned to MM page size */
211062306a36Sopenharmony_cistatic inline unsigned long aligned_nrpages(unsigned long host_addr,
211162306a36Sopenharmony_ci					    size_t size)
211262306a36Sopenharmony_ci{
211362306a36Sopenharmony_ci	host_addr &= ~PAGE_MASK;
211462306a36Sopenharmony_ci	return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
211562306a36Sopenharmony_ci}
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci/* Return largest possible superpage level for a given mapping */
211862306a36Sopenharmony_cistatic inline int hardware_largepage_caps(struct dmar_domain *domain,
211962306a36Sopenharmony_ci					  unsigned long iov_pfn,
212062306a36Sopenharmony_ci					  unsigned long phy_pfn,
212162306a36Sopenharmony_ci					  unsigned long pages)
212262306a36Sopenharmony_ci{
212362306a36Sopenharmony_ci	int support, level = 1;
212462306a36Sopenharmony_ci	unsigned long pfnmerge;
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	support = domain->iommu_superpage;
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	/* To use a large page, the virtual *and* physical addresses
212962306a36Sopenharmony_ci	   must be aligned to 2MiB/1GiB/etc. Lower bits set in either
213062306a36Sopenharmony_ci	   of them will mean we have to use smaller pages. So just
213162306a36Sopenharmony_ci	   merge them and check both at once. */
213262306a36Sopenharmony_ci	pfnmerge = iov_pfn | phy_pfn;
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci	while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
213562306a36Sopenharmony_ci		pages >>= VTD_STRIDE_SHIFT;
213662306a36Sopenharmony_ci		if (!pages)
213762306a36Sopenharmony_ci			break;
213862306a36Sopenharmony_ci		pfnmerge >>= VTD_STRIDE_SHIFT;
213962306a36Sopenharmony_ci		level++;
214062306a36Sopenharmony_ci		support--;
214162306a36Sopenharmony_ci	}
214262306a36Sopenharmony_ci	return level;
214362306a36Sopenharmony_ci}
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci/*
214662306a36Sopenharmony_ci * Ensure that old small page tables are removed to make room for superpage(s).
214762306a36Sopenharmony_ci * We're going to add new large pages, so make sure we don't remove their parent
214862306a36Sopenharmony_ci * tables. The IOTLB/devTLBs should be flushed if any PDE/PTEs are cleared.
214962306a36Sopenharmony_ci */
215062306a36Sopenharmony_cistatic void switch_to_super_page(struct dmar_domain *domain,
215162306a36Sopenharmony_ci				 unsigned long start_pfn,
215262306a36Sopenharmony_ci				 unsigned long end_pfn, int level)
215362306a36Sopenharmony_ci{
215462306a36Sopenharmony_ci	unsigned long lvl_pages = lvl_to_nr_pages(level);
215562306a36Sopenharmony_ci	struct iommu_domain_info *info;
215662306a36Sopenharmony_ci	struct dma_pte *pte = NULL;
215762306a36Sopenharmony_ci	unsigned long i;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	while (start_pfn <= end_pfn) {
216062306a36Sopenharmony_ci		if (!pte)
216162306a36Sopenharmony_ci			pte = pfn_to_dma_pte(domain, start_pfn, &level,
216262306a36Sopenharmony_ci					     GFP_ATOMIC);
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci		if (dma_pte_present(pte)) {
216562306a36Sopenharmony_ci			dma_pte_free_pagetable(domain, start_pfn,
216662306a36Sopenharmony_ci					       start_pfn + lvl_pages - 1,
216762306a36Sopenharmony_ci					       level + 1);
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci			xa_for_each(&domain->iommu_array, i, info)
217062306a36Sopenharmony_ci				iommu_flush_iotlb_psi(info->iommu, domain,
217162306a36Sopenharmony_ci						      start_pfn, lvl_pages,
217262306a36Sopenharmony_ci						      0, 0);
217362306a36Sopenharmony_ci		}
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci		pte++;
217662306a36Sopenharmony_ci		start_pfn += lvl_pages;
217762306a36Sopenharmony_ci		if (first_pte_in_page(pte))
217862306a36Sopenharmony_ci			pte = NULL;
217962306a36Sopenharmony_ci	}
218062306a36Sopenharmony_ci}
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_cistatic int
218362306a36Sopenharmony_ci__domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
218462306a36Sopenharmony_ci		 unsigned long phys_pfn, unsigned long nr_pages, int prot,
218562306a36Sopenharmony_ci		 gfp_t gfp)
218662306a36Sopenharmony_ci{
218762306a36Sopenharmony_ci	struct dma_pte *first_pte = NULL, *pte = NULL;
218862306a36Sopenharmony_ci	unsigned int largepage_lvl = 0;
218962306a36Sopenharmony_ci	unsigned long lvl_pages = 0;
219062306a36Sopenharmony_ci	phys_addr_t pteval;
219162306a36Sopenharmony_ci	u64 attr;
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	if (unlikely(!domain_pfn_supported(domain, iov_pfn + nr_pages - 1)))
219462306a36Sopenharmony_ci		return -EINVAL;
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
219762306a36Sopenharmony_ci		return -EINVAL;
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	attr = prot & (DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP);
220062306a36Sopenharmony_ci	attr |= DMA_FL_PTE_PRESENT;
220162306a36Sopenharmony_ci	if (domain->use_first_level) {
220262306a36Sopenharmony_ci		attr |= DMA_FL_PTE_XD | DMA_FL_PTE_US | DMA_FL_PTE_ACCESS;
220362306a36Sopenharmony_ci		if (prot & DMA_PTE_WRITE)
220462306a36Sopenharmony_ci			attr |= DMA_FL_PTE_DIRTY;
220562306a36Sopenharmony_ci	}
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	domain->has_mappings = true;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | attr;
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	while (nr_pages > 0) {
221262306a36Sopenharmony_ci		uint64_t tmp;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci		if (!pte) {
221562306a36Sopenharmony_ci			largepage_lvl = hardware_largepage_caps(domain, iov_pfn,
221662306a36Sopenharmony_ci					phys_pfn, nr_pages);
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci			pte = pfn_to_dma_pte(domain, iov_pfn, &largepage_lvl,
221962306a36Sopenharmony_ci					     gfp);
222062306a36Sopenharmony_ci			if (!pte)
222162306a36Sopenharmony_ci				return -ENOMEM;
222262306a36Sopenharmony_ci			first_pte = pte;
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_ci			lvl_pages = lvl_to_nr_pages(largepage_lvl);
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci			/* It is large page*/
222762306a36Sopenharmony_ci			if (largepage_lvl > 1) {
222862306a36Sopenharmony_ci				unsigned long end_pfn;
222962306a36Sopenharmony_ci				unsigned long pages_to_remove;
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci				pteval |= DMA_PTE_LARGE_PAGE;
223262306a36Sopenharmony_ci				pages_to_remove = min_t(unsigned long, nr_pages,
223362306a36Sopenharmony_ci							nr_pte_to_next_page(pte) * lvl_pages);
223462306a36Sopenharmony_ci				end_pfn = iov_pfn + pages_to_remove - 1;
223562306a36Sopenharmony_ci				switch_to_super_page(domain, iov_pfn, end_pfn, largepage_lvl);
223662306a36Sopenharmony_ci			} else {
223762306a36Sopenharmony_ci				pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
223862306a36Sopenharmony_ci			}
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci		}
224162306a36Sopenharmony_ci		/* We don't need lock here, nobody else
224262306a36Sopenharmony_ci		 * touches the iova range
224362306a36Sopenharmony_ci		 */
224462306a36Sopenharmony_ci		tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
224562306a36Sopenharmony_ci		if (tmp) {
224662306a36Sopenharmony_ci			static int dumps = 5;
224762306a36Sopenharmony_ci			pr_crit("ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
224862306a36Sopenharmony_ci				iov_pfn, tmp, (unsigned long long)pteval);
224962306a36Sopenharmony_ci			if (dumps) {
225062306a36Sopenharmony_ci				dumps--;
225162306a36Sopenharmony_ci				debug_dma_dump_mappings(NULL);
225262306a36Sopenharmony_ci			}
225362306a36Sopenharmony_ci			WARN_ON(1);
225462306a36Sopenharmony_ci		}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci		nr_pages -= lvl_pages;
225762306a36Sopenharmony_ci		iov_pfn += lvl_pages;
225862306a36Sopenharmony_ci		phys_pfn += lvl_pages;
225962306a36Sopenharmony_ci		pteval += lvl_pages * VTD_PAGE_SIZE;
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci		/* If the next PTE would be the first in a new page, then we
226262306a36Sopenharmony_ci		 * need to flush the cache on the entries we've just written.
226362306a36Sopenharmony_ci		 * And then we'll need to recalculate 'pte', so clear it and
226462306a36Sopenharmony_ci		 * let it get set again in the if (!pte) block above.
226562306a36Sopenharmony_ci		 *
226662306a36Sopenharmony_ci		 * If we're done (!nr_pages) we need to flush the cache too.
226762306a36Sopenharmony_ci		 *
226862306a36Sopenharmony_ci		 * Also if we've been setting superpages, we may need to
226962306a36Sopenharmony_ci		 * recalculate 'pte' and switch back to smaller pages for the
227062306a36Sopenharmony_ci		 * end of the mapping, if the trailing size is not enough to
227162306a36Sopenharmony_ci		 * use another superpage (i.e. nr_pages < lvl_pages).
227262306a36Sopenharmony_ci		 */
227362306a36Sopenharmony_ci		pte++;
227462306a36Sopenharmony_ci		if (!nr_pages || first_pte_in_page(pte) ||
227562306a36Sopenharmony_ci		    (largepage_lvl > 1 && nr_pages < lvl_pages)) {
227662306a36Sopenharmony_ci			domain_flush_cache(domain, first_pte,
227762306a36Sopenharmony_ci					   (void *)pte - (void *)first_pte);
227862306a36Sopenharmony_ci			pte = NULL;
227962306a36Sopenharmony_ci		}
228062306a36Sopenharmony_ci	}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	return 0;
228362306a36Sopenharmony_ci}
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_cistatic void domain_context_clear_one(struct device_domain_info *info, u8 bus, u8 devfn)
228662306a36Sopenharmony_ci{
228762306a36Sopenharmony_ci	struct intel_iommu *iommu = info->iommu;
228862306a36Sopenharmony_ci	struct context_entry *context;
228962306a36Sopenharmony_ci	u16 did_old;
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	if (!iommu)
229262306a36Sopenharmony_ci		return;
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci	spin_lock(&iommu->lock);
229562306a36Sopenharmony_ci	context = iommu_context_addr(iommu, bus, devfn, 0);
229662306a36Sopenharmony_ci	if (!context) {
229762306a36Sopenharmony_ci		spin_unlock(&iommu->lock);
229862306a36Sopenharmony_ci		return;
229962306a36Sopenharmony_ci	}
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	if (sm_supported(iommu)) {
230262306a36Sopenharmony_ci		if (hw_pass_through && domain_type_is_si(info->domain))
230362306a36Sopenharmony_ci			did_old = FLPT_DEFAULT_DID;
230462306a36Sopenharmony_ci		else
230562306a36Sopenharmony_ci			did_old = domain_id_iommu(info->domain, iommu);
230662306a36Sopenharmony_ci	} else {
230762306a36Sopenharmony_ci		did_old = context_domain_id(context);
230862306a36Sopenharmony_ci	}
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	context_clear_entry(context);
231162306a36Sopenharmony_ci	__iommu_flush_cache(iommu, context, sizeof(*context));
231262306a36Sopenharmony_ci	spin_unlock(&iommu->lock);
231362306a36Sopenharmony_ci	iommu->flush.flush_context(iommu,
231462306a36Sopenharmony_ci				   did_old,
231562306a36Sopenharmony_ci				   (((u16)bus) << 8) | devfn,
231662306a36Sopenharmony_ci				   DMA_CCMD_MASK_NOBIT,
231762306a36Sopenharmony_ci				   DMA_CCMD_DEVICE_INVL);
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	if (sm_supported(iommu))
232062306a36Sopenharmony_ci		qi_flush_pasid_cache(iommu, did_old, QI_PC_ALL_PASIDS, 0);
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	iommu->flush.flush_iotlb(iommu,
232362306a36Sopenharmony_ci				 did_old,
232462306a36Sopenharmony_ci				 0,
232562306a36Sopenharmony_ci				 0,
232662306a36Sopenharmony_ci				 DMA_TLB_DSI_FLUSH);
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci	__iommu_flush_dev_iotlb(info, 0, MAX_AGAW_PFN_WIDTH);
232962306a36Sopenharmony_ci}
233062306a36Sopenharmony_ci
233162306a36Sopenharmony_cistatic int domain_setup_first_level(struct intel_iommu *iommu,
233262306a36Sopenharmony_ci				    struct dmar_domain *domain,
233362306a36Sopenharmony_ci				    struct device *dev,
233462306a36Sopenharmony_ci				    u32 pasid)
233562306a36Sopenharmony_ci{
233662306a36Sopenharmony_ci	struct dma_pte *pgd = domain->pgd;
233762306a36Sopenharmony_ci	int agaw, level;
233862306a36Sopenharmony_ci	int flags = 0;
233962306a36Sopenharmony_ci
234062306a36Sopenharmony_ci	/*
234162306a36Sopenharmony_ci	 * Skip top levels of page tables for iommu which has
234262306a36Sopenharmony_ci	 * less agaw than default. Unnecessary for PT mode.
234362306a36Sopenharmony_ci	 */
234462306a36Sopenharmony_ci	for (agaw = domain->agaw; agaw > iommu->agaw; agaw--) {
234562306a36Sopenharmony_ci		pgd = phys_to_virt(dma_pte_addr(pgd));
234662306a36Sopenharmony_ci		if (!dma_pte_present(pgd))
234762306a36Sopenharmony_ci			return -ENOMEM;
234862306a36Sopenharmony_ci	}
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	level = agaw_to_level(agaw);
235162306a36Sopenharmony_ci	if (level != 4 && level != 5)
235262306a36Sopenharmony_ci		return -EINVAL;
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci	if (level == 5)
235562306a36Sopenharmony_ci		flags |= PASID_FLAG_FL5LP;
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci	if (domain->force_snooping)
235862306a36Sopenharmony_ci		flags |= PASID_FLAG_PAGE_SNOOP;
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	return intel_pasid_setup_first_level(iommu, dev, (pgd_t *)pgd, pasid,
236162306a36Sopenharmony_ci					     domain_id_iommu(domain, iommu),
236262306a36Sopenharmony_ci					     flags);
236362306a36Sopenharmony_ci}
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_cistatic bool dev_is_real_dma_subdevice(struct device *dev)
236662306a36Sopenharmony_ci{
236762306a36Sopenharmony_ci	return dev && dev_is_pci(dev) &&
236862306a36Sopenharmony_ci	       pci_real_dma_dev(to_pci_dev(dev)) != to_pci_dev(dev);
236962306a36Sopenharmony_ci}
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_cistatic int iommu_domain_identity_map(struct dmar_domain *domain,
237262306a36Sopenharmony_ci				     unsigned long first_vpfn,
237362306a36Sopenharmony_ci				     unsigned long last_vpfn)
237462306a36Sopenharmony_ci{
237562306a36Sopenharmony_ci	/*
237662306a36Sopenharmony_ci	 * RMRR range might have overlap with physical memory range,
237762306a36Sopenharmony_ci	 * clear it first
237862306a36Sopenharmony_ci	 */
237962306a36Sopenharmony_ci	dma_pte_clear_range(domain, first_vpfn, last_vpfn);
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	return __domain_mapping(domain, first_vpfn,
238262306a36Sopenharmony_ci				first_vpfn, last_vpfn - first_vpfn + 1,
238362306a36Sopenharmony_ci				DMA_PTE_READ|DMA_PTE_WRITE, GFP_KERNEL);
238462306a36Sopenharmony_ci}
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_cistatic int md_domain_init(struct dmar_domain *domain, int guest_width);
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_cistatic int __init si_domain_init(int hw)
238962306a36Sopenharmony_ci{
239062306a36Sopenharmony_ci	struct dmar_rmrr_unit *rmrr;
239162306a36Sopenharmony_ci	struct device *dev;
239262306a36Sopenharmony_ci	int i, nid, ret;
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci	si_domain = alloc_domain(IOMMU_DOMAIN_IDENTITY);
239562306a36Sopenharmony_ci	if (!si_domain)
239662306a36Sopenharmony_ci		return -EFAULT;
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	if (md_domain_init(si_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
239962306a36Sopenharmony_ci		domain_exit(si_domain);
240062306a36Sopenharmony_ci		si_domain = NULL;
240162306a36Sopenharmony_ci		return -EFAULT;
240262306a36Sopenharmony_ci	}
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	if (hw)
240562306a36Sopenharmony_ci		return 0;
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci	for_each_online_node(nid) {
240862306a36Sopenharmony_ci		unsigned long start_pfn, end_pfn;
240962306a36Sopenharmony_ci		int i;
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_ci		for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) {
241262306a36Sopenharmony_ci			ret = iommu_domain_identity_map(si_domain,
241362306a36Sopenharmony_ci					mm_to_dma_pfn_start(start_pfn),
241462306a36Sopenharmony_ci					mm_to_dma_pfn_end(end_pfn));
241562306a36Sopenharmony_ci			if (ret)
241662306a36Sopenharmony_ci				return ret;
241762306a36Sopenharmony_ci		}
241862306a36Sopenharmony_ci	}
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ci	/*
242162306a36Sopenharmony_ci	 * Identity map the RMRRs so that devices with RMRRs could also use
242262306a36Sopenharmony_ci	 * the si_domain.
242362306a36Sopenharmony_ci	 */
242462306a36Sopenharmony_ci	for_each_rmrr_units(rmrr) {
242562306a36Sopenharmony_ci		for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt,
242662306a36Sopenharmony_ci					  i, dev) {
242762306a36Sopenharmony_ci			unsigned long long start = rmrr->base_address;
242862306a36Sopenharmony_ci			unsigned long long end = rmrr->end_address;
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci			if (WARN_ON(end < start ||
243162306a36Sopenharmony_ci				    end >> agaw_to_width(si_domain->agaw)))
243262306a36Sopenharmony_ci				continue;
243362306a36Sopenharmony_ci
243462306a36Sopenharmony_ci			ret = iommu_domain_identity_map(si_domain,
243562306a36Sopenharmony_ci					mm_to_dma_pfn_start(start >> PAGE_SHIFT),
243662306a36Sopenharmony_ci					mm_to_dma_pfn_end(end >> PAGE_SHIFT));
243762306a36Sopenharmony_ci			if (ret)
243862306a36Sopenharmony_ci				return ret;
243962306a36Sopenharmony_ci		}
244062306a36Sopenharmony_ci	}
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	return 0;
244362306a36Sopenharmony_ci}
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_cistatic int dmar_domain_attach_device(struct dmar_domain *domain,
244662306a36Sopenharmony_ci				     struct device *dev)
244762306a36Sopenharmony_ci{
244862306a36Sopenharmony_ci	struct device_domain_info *info = dev_iommu_priv_get(dev);
244962306a36Sopenharmony_ci	struct intel_iommu *iommu;
245062306a36Sopenharmony_ci	unsigned long flags;
245162306a36Sopenharmony_ci	u8 bus, devfn;
245262306a36Sopenharmony_ci	int ret;
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	iommu = device_to_iommu(dev, &bus, &devfn);
245562306a36Sopenharmony_ci	if (!iommu)
245662306a36Sopenharmony_ci		return -ENODEV;
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	ret = domain_attach_iommu(domain, iommu);
245962306a36Sopenharmony_ci	if (ret)
246062306a36Sopenharmony_ci		return ret;
246162306a36Sopenharmony_ci	info->domain = domain;
246262306a36Sopenharmony_ci	spin_lock_irqsave(&domain->lock, flags);
246362306a36Sopenharmony_ci	list_add(&info->link, &domain->devices);
246462306a36Sopenharmony_ci	spin_unlock_irqrestore(&domain->lock, flags);
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci	/* PASID table is mandatory for a PCI device in scalable mode. */
246762306a36Sopenharmony_ci	if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) {
246862306a36Sopenharmony_ci		/* Setup the PASID entry for requests without PASID: */
246962306a36Sopenharmony_ci		if (hw_pass_through && domain_type_is_si(domain))
247062306a36Sopenharmony_ci			ret = intel_pasid_setup_pass_through(iommu, domain,
247162306a36Sopenharmony_ci					dev, IOMMU_NO_PASID);
247262306a36Sopenharmony_ci		else if (domain->use_first_level)
247362306a36Sopenharmony_ci			ret = domain_setup_first_level(iommu, domain, dev,
247462306a36Sopenharmony_ci					IOMMU_NO_PASID);
247562306a36Sopenharmony_ci		else
247662306a36Sopenharmony_ci			ret = intel_pasid_setup_second_level(iommu, domain,
247762306a36Sopenharmony_ci					dev, IOMMU_NO_PASID);
247862306a36Sopenharmony_ci		if (ret) {
247962306a36Sopenharmony_ci			dev_err(dev, "Setup RID2PASID failed\n");
248062306a36Sopenharmony_ci			device_block_translation(dev);
248162306a36Sopenharmony_ci			return ret;
248262306a36Sopenharmony_ci		}
248362306a36Sopenharmony_ci	}
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci	ret = domain_context_mapping(domain, dev);
248662306a36Sopenharmony_ci	if (ret) {
248762306a36Sopenharmony_ci		dev_err(dev, "Domain context map failed\n");
248862306a36Sopenharmony_ci		device_block_translation(dev);
248962306a36Sopenharmony_ci		return ret;
249062306a36Sopenharmony_ci	}
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci	if (sm_supported(info->iommu) || !domain_type_is_si(info->domain))
249362306a36Sopenharmony_ci		iommu_enable_pci_caps(info);
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	return 0;
249662306a36Sopenharmony_ci}
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci/**
249962306a36Sopenharmony_ci * device_rmrr_is_relaxable - Test whether the RMRR of this device
250062306a36Sopenharmony_ci * is relaxable (ie. is allowed to be not enforced under some conditions)
250162306a36Sopenharmony_ci * @dev: device handle
250262306a36Sopenharmony_ci *
250362306a36Sopenharmony_ci * We assume that PCI USB devices with RMRRs have them largely
250462306a36Sopenharmony_ci * for historical reasons and that the RMRR space is not actively used post
250562306a36Sopenharmony_ci * boot.  This exclusion may change if vendors begin to abuse it.
250662306a36Sopenharmony_ci *
250762306a36Sopenharmony_ci * The same exception is made for graphics devices, with the requirement that
250862306a36Sopenharmony_ci * any use of the RMRR regions will be torn down before assigning the device
250962306a36Sopenharmony_ci * to a guest.
251062306a36Sopenharmony_ci *
251162306a36Sopenharmony_ci * Return: true if the RMRR is relaxable, false otherwise
251262306a36Sopenharmony_ci */
251362306a36Sopenharmony_cistatic bool device_rmrr_is_relaxable(struct device *dev)
251462306a36Sopenharmony_ci{
251562306a36Sopenharmony_ci	struct pci_dev *pdev;
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	if (!dev_is_pci(dev))
251862306a36Sopenharmony_ci		return false;
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	pdev = to_pci_dev(dev);
252162306a36Sopenharmony_ci	if (IS_USB_DEVICE(pdev) || IS_GFX_DEVICE(pdev))
252262306a36Sopenharmony_ci		return true;
252362306a36Sopenharmony_ci	else
252462306a36Sopenharmony_ci		return false;
252562306a36Sopenharmony_ci}
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci/*
252862306a36Sopenharmony_ci * Return the required default domain type for a specific device.
252962306a36Sopenharmony_ci *
253062306a36Sopenharmony_ci * @dev: the device in query
253162306a36Sopenharmony_ci * @startup: true if this is during early boot
253262306a36Sopenharmony_ci *
253362306a36Sopenharmony_ci * Returns:
253462306a36Sopenharmony_ci *  - IOMMU_DOMAIN_DMA: device requires a dynamic mapping domain
253562306a36Sopenharmony_ci *  - IOMMU_DOMAIN_IDENTITY: device requires an identical mapping domain
253662306a36Sopenharmony_ci *  - 0: both identity and dynamic domains work for this device
253762306a36Sopenharmony_ci */
253862306a36Sopenharmony_cistatic int device_def_domain_type(struct device *dev)
253962306a36Sopenharmony_ci{
254062306a36Sopenharmony_ci	if (dev_is_pci(dev)) {
254162306a36Sopenharmony_ci		struct pci_dev *pdev = to_pci_dev(dev);
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci		if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
254462306a36Sopenharmony_ci			return IOMMU_DOMAIN_IDENTITY;
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_ci		if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
254762306a36Sopenharmony_ci			return IOMMU_DOMAIN_IDENTITY;
254862306a36Sopenharmony_ci	}
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	return 0;
255162306a36Sopenharmony_ci}
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_cistatic void intel_iommu_init_qi(struct intel_iommu *iommu)
255462306a36Sopenharmony_ci{
255562306a36Sopenharmony_ci	/*
255662306a36Sopenharmony_ci	 * Start from the sane iommu hardware state.
255762306a36Sopenharmony_ci	 * If the queued invalidation is already initialized by us
255862306a36Sopenharmony_ci	 * (for example, while enabling interrupt-remapping) then
255962306a36Sopenharmony_ci	 * we got the things already rolling from a sane state.
256062306a36Sopenharmony_ci	 */
256162306a36Sopenharmony_ci	if (!iommu->qi) {
256262306a36Sopenharmony_ci		/*
256362306a36Sopenharmony_ci		 * Clear any previous faults.
256462306a36Sopenharmony_ci		 */
256562306a36Sopenharmony_ci		dmar_fault(-1, iommu);
256662306a36Sopenharmony_ci		/*
256762306a36Sopenharmony_ci		 * Disable queued invalidation if supported and already enabled
256862306a36Sopenharmony_ci		 * before OS handover.
256962306a36Sopenharmony_ci		 */
257062306a36Sopenharmony_ci		dmar_disable_qi(iommu);
257162306a36Sopenharmony_ci	}
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	if (dmar_enable_qi(iommu)) {
257462306a36Sopenharmony_ci		/*
257562306a36Sopenharmony_ci		 * Queued Invalidate not enabled, use Register Based Invalidate
257662306a36Sopenharmony_ci		 */
257762306a36Sopenharmony_ci		iommu->flush.flush_context = __iommu_flush_context;
257862306a36Sopenharmony_ci		iommu->flush.flush_iotlb = __iommu_flush_iotlb;
257962306a36Sopenharmony_ci		pr_info("%s: Using Register based invalidation\n",
258062306a36Sopenharmony_ci			iommu->name);
258162306a36Sopenharmony_ci	} else {
258262306a36Sopenharmony_ci		iommu->flush.flush_context = qi_flush_context;
258362306a36Sopenharmony_ci		iommu->flush.flush_iotlb = qi_flush_iotlb;
258462306a36Sopenharmony_ci		pr_info("%s: Using Queued invalidation\n", iommu->name);
258562306a36Sopenharmony_ci	}
258662306a36Sopenharmony_ci}
258762306a36Sopenharmony_ci
258862306a36Sopenharmony_cistatic int copy_context_table(struct intel_iommu *iommu,
258962306a36Sopenharmony_ci			      struct root_entry *old_re,
259062306a36Sopenharmony_ci			      struct context_entry **tbl,
259162306a36Sopenharmony_ci			      int bus, bool ext)
259262306a36Sopenharmony_ci{
259362306a36Sopenharmony_ci	int tbl_idx, pos = 0, idx, devfn, ret = 0, did;
259462306a36Sopenharmony_ci	struct context_entry *new_ce = NULL, ce;
259562306a36Sopenharmony_ci	struct context_entry *old_ce = NULL;
259662306a36Sopenharmony_ci	struct root_entry re;
259762306a36Sopenharmony_ci	phys_addr_t old_ce_phys;
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci	tbl_idx = ext ? bus * 2 : bus;
260062306a36Sopenharmony_ci	memcpy(&re, old_re, sizeof(re));
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci	for (devfn = 0; devfn < 256; devfn++) {
260362306a36Sopenharmony_ci		/* First calculate the correct index */
260462306a36Sopenharmony_ci		idx = (ext ? devfn * 2 : devfn) % 256;
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci		if (idx == 0) {
260762306a36Sopenharmony_ci			/* First save what we may have and clean up */
260862306a36Sopenharmony_ci			if (new_ce) {
260962306a36Sopenharmony_ci				tbl[tbl_idx] = new_ce;
261062306a36Sopenharmony_ci				__iommu_flush_cache(iommu, new_ce,
261162306a36Sopenharmony_ci						    VTD_PAGE_SIZE);
261262306a36Sopenharmony_ci				pos = 1;
261362306a36Sopenharmony_ci			}
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci			if (old_ce)
261662306a36Sopenharmony_ci				memunmap(old_ce);
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ci			ret = 0;
261962306a36Sopenharmony_ci			if (devfn < 0x80)
262062306a36Sopenharmony_ci				old_ce_phys = root_entry_lctp(&re);
262162306a36Sopenharmony_ci			else
262262306a36Sopenharmony_ci				old_ce_phys = root_entry_uctp(&re);
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci			if (!old_ce_phys) {
262562306a36Sopenharmony_ci				if (ext && devfn == 0) {
262662306a36Sopenharmony_ci					/* No LCTP, try UCTP */
262762306a36Sopenharmony_ci					devfn = 0x7f;
262862306a36Sopenharmony_ci					continue;
262962306a36Sopenharmony_ci				} else {
263062306a36Sopenharmony_ci					goto out;
263162306a36Sopenharmony_ci				}
263262306a36Sopenharmony_ci			}
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci			ret = -ENOMEM;
263562306a36Sopenharmony_ci			old_ce = memremap(old_ce_phys, PAGE_SIZE,
263662306a36Sopenharmony_ci					MEMREMAP_WB);
263762306a36Sopenharmony_ci			if (!old_ce)
263862306a36Sopenharmony_ci				goto out;
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci			new_ce = alloc_pgtable_page(iommu->node, GFP_KERNEL);
264162306a36Sopenharmony_ci			if (!new_ce)
264262306a36Sopenharmony_ci				goto out_unmap;
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_ci			ret = 0;
264562306a36Sopenharmony_ci		}
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci		/* Now copy the context entry */
264862306a36Sopenharmony_ci		memcpy(&ce, old_ce + idx, sizeof(ce));
264962306a36Sopenharmony_ci
265062306a36Sopenharmony_ci		if (!context_present(&ce))
265162306a36Sopenharmony_ci			continue;
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci		did = context_domain_id(&ce);
265462306a36Sopenharmony_ci		if (did >= 0 && did < cap_ndoms(iommu->cap))
265562306a36Sopenharmony_ci			set_bit(did, iommu->domain_ids);
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci		set_context_copied(iommu, bus, devfn);
265862306a36Sopenharmony_ci		new_ce[idx] = ce;
265962306a36Sopenharmony_ci	}
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci	tbl[tbl_idx + pos] = new_ce;
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci	__iommu_flush_cache(iommu, new_ce, VTD_PAGE_SIZE);
266462306a36Sopenharmony_ci
266562306a36Sopenharmony_ciout_unmap:
266662306a36Sopenharmony_ci	memunmap(old_ce);
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ciout:
266962306a36Sopenharmony_ci	return ret;
267062306a36Sopenharmony_ci}
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_cistatic int copy_translation_tables(struct intel_iommu *iommu)
267362306a36Sopenharmony_ci{
267462306a36Sopenharmony_ci	struct context_entry **ctxt_tbls;
267562306a36Sopenharmony_ci	struct root_entry *old_rt;
267662306a36Sopenharmony_ci	phys_addr_t old_rt_phys;
267762306a36Sopenharmony_ci	int ctxt_table_entries;
267862306a36Sopenharmony_ci	u64 rtaddr_reg;
267962306a36Sopenharmony_ci	int bus, ret;
268062306a36Sopenharmony_ci	bool new_ext, ext;
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	rtaddr_reg = dmar_readq(iommu->reg + DMAR_RTADDR_REG);
268362306a36Sopenharmony_ci	ext        = !!(rtaddr_reg & DMA_RTADDR_SMT);
268462306a36Sopenharmony_ci	new_ext    = !!sm_supported(iommu);
268562306a36Sopenharmony_ci
268662306a36Sopenharmony_ci	/*
268762306a36Sopenharmony_ci	 * The RTT bit can only be changed when translation is disabled,
268862306a36Sopenharmony_ci	 * but disabling translation means to open a window for data
268962306a36Sopenharmony_ci	 * corruption. So bail out and don't copy anything if we would
269062306a36Sopenharmony_ci	 * have to change the bit.
269162306a36Sopenharmony_ci	 */
269262306a36Sopenharmony_ci	if (new_ext != ext)
269362306a36Sopenharmony_ci		return -EINVAL;
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	iommu->copied_tables = bitmap_zalloc(BIT_ULL(16), GFP_KERNEL);
269662306a36Sopenharmony_ci	if (!iommu->copied_tables)
269762306a36Sopenharmony_ci		return -ENOMEM;
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci	old_rt_phys = rtaddr_reg & VTD_PAGE_MASK;
270062306a36Sopenharmony_ci	if (!old_rt_phys)
270162306a36Sopenharmony_ci		return -EINVAL;
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_ci	old_rt = memremap(old_rt_phys, PAGE_SIZE, MEMREMAP_WB);
270462306a36Sopenharmony_ci	if (!old_rt)
270562306a36Sopenharmony_ci		return -ENOMEM;
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci	/* This is too big for the stack - allocate it from slab */
270862306a36Sopenharmony_ci	ctxt_table_entries = ext ? 512 : 256;
270962306a36Sopenharmony_ci	ret = -ENOMEM;
271062306a36Sopenharmony_ci	ctxt_tbls = kcalloc(ctxt_table_entries, sizeof(void *), GFP_KERNEL);
271162306a36Sopenharmony_ci	if (!ctxt_tbls)
271262306a36Sopenharmony_ci		goto out_unmap;
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	for (bus = 0; bus < 256; bus++) {
271562306a36Sopenharmony_ci		ret = copy_context_table(iommu, &old_rt[bus],
271662306a36Sopenharmony_ci					 ctxt_tbls, bus, ext);
271762306a36Sopenharmony_ci		if (ret) {
271862306a36Sopenharmony_ci			pr_err("%s: Failed to copy context table for bus %d\n",
271962306a36Sopenharmony_ci				iommu->name, bus);
272062306a36Sopenharmony_ci			continue;
272162306a36Sopenharmony_ci		}
272262306a36Sopenharmony_ci	}
272362306a36Sopenharmony_ci
272462306a36Sopenharmony_ci	spin_lock(&iommu->lock);
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci	/* Context tables are copied, now write them to the root_entry table */
272762306a36Sopenharmony_ci	for (bus = 0; bus < 256; bus++) {
272862306a36Sopenharmony_ci		int idx = ext ? bus * 2 : bus;
272962306a36Sopenharmony_ci		u64 val;
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci		if (ctxt_tbls[idx]) {
273262306a36Sopenharmony_ci			val = virt_to_phys(ctxt_tbls[idx]) | 1;
273362306a36Sopenharmony_ci			iommu->root_entry[bus].lo = val;
273462306a36Sopenharmony_ci		}
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci		if (!ext || !ctxt_tbls[idx + 1])
273762306a36Sopenharmony_ci			continue;
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci		val = virt_to_phys(ctxt_tbls[idx + 1]) | 1;
274062306a36Sopenharmony_ci		iommu->root_entry[bus].hi = val;
274162306a36Sopenharmony_ci	}
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci	spin_unlock(&iommu->lock);
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci	kfree(ctxt_tbls);
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	__iommu_flush_cache(iommu, iommu->root_entry, PAGE_SIZE);
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	ret = 0;
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ciout_unmap:
275262306a36Sopenharmony_ci	memunmap(old_rt);
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_ci	return ret;
275562306a36Sopenharmony_ci}
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_cistatic int __init init_dmars(void)
275862306a36Sopenharmony_ci{
275962306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd;
276062306a36Sopenharmony_ci	struct intel_iommu *iommu;
276162306a36Sopenharmony_ci	int ret;
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci	ret = intel_cap_audit(CAP_AUDIT_STATIC_DMAR, NULL);
276462306a36Sopenharmony_ci	if (ret)
276562306a36Sopenharmony_ci		goto free_iommu;
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_ci	for_each_iommu(iommu, drhd) {
276862306a36Sopenharmony_ci		if (drhd->ignored) {
276962306a36Sopenharmony_ci			iommu_disable_translation(iommu);
277062306a36Sopenharmony_ci			continue;
277162306a36Sopenharmony_ci		}
277262306a36Sopenharmony_ci
277362306a36Sopenharmony_ci		/*
277462306a36Sopenharmony_ci		 * Find the max pasid size of all IOMMU's in the system.
277562306a36Sopenharmony_ci		 * We need to ensure the system pasid table is no bigger
277662306a36Sopenharmony_ci		 * than the smallest supported.
277762306a36Sopenharmony_ci		 */
277862306a36Sopenharmony_ci		if (pasid_supported(iommu)) {
277962306a36Sopenharmony_ci			u32 temp = 2 << ecap_pss(iommu->ecap);
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_ci			intel_pasid_max_id = min_t(u32, temp,
278262306a36Sopenharmony_ci						   intel_pasid_max_id);
278362306a36Sopenharmony_ci		}
278462306a36Sopenharmony_ci
278562306a36Sopenharmony_ci		intel_iommu_init_qi(iommu);
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci		ret = iommu_init_domains(iommu);
278862306a36Sopenharmony_ci		if (ret)
278962306a36Sopenharmony_ci			goto free_iommu;
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ci		init_translation_status(iommu);
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci		if (translation_pre_enabled(iommu) && !is_kdump_kernel()) {
279462306a36Sopenharmony_ci			iommu_disable_translation(iommu);
279562306a36Sopenharmony_ci			clear_translation_pre_enabled(iommu);
279662306a36Sopenharmony_ci			pr_warn("Translation was enabled for %s but we are not in kdump mode\n",
279762306a36Sopenharmony_ci				iommu->name);
279862306a36Sopenharmony_ci		}
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci		/*
280162306a36Sopenharmony_ci		 * TBD:
280262306a36Sopenharmony_ci		 * we could share the same root & context tables
280362306a36Sopenharmony_ci		 * among all IOMMU's. Need to Split it later.
280462306a36Sopenharmony_ci		 */
280562306a36Sopenharmony_ci		ret = iommu_alloc_root_entry(iommu);
280662306a36Sopenharmony_ci		if (ret)
280762306a36Sopenharmony_ci			goto free_iommu;
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci		if (translation_pre_enabled(iommu)) {
281062306a36Sopenharmony_ci			pr_info("Translation already enabled - trying to copy translation structures\n");
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci			ret = copy_translation_tables(iommu);
281362306a36Sopenharmony_ci			if (ret) {
281462306a36Sopenharmony_ci				/*
281562306a36Sopenharmony_ci				 * We found the IOMMU with translation
281662306a36Sopenharmony_ci				 * enabled - but failed to copy over the
281762306a36Sopenharmony_ci				 * old root-entry table. Try to proceed
281862306a36Sopenharmony_ci				 * by disabling translation now and
281962306a36Sopenharmony_ci				 * allocating a clean root-entry table.
282062306a36Sopenharmony_ci				 * This might cause DMAR faults, but
282162306a36Sopenharmony_ci				 * probably the dump will still succeed.
282262306a36Sopenharmony_ci				 */
282362306a36Sopenharmony_ci				pr_err("Failed to copy translation tables from previous kernel for %s\n",
282462306a36Sopenharmony_ci				       iommu->name);
282562306a36Sopenharmony_ci				iommu_disable_translation(iommu);
282662306a36Sopenharmony_ci				clear_translation_pre_enabled(iommu);
282762306a36Sopenharmony_ci			} else {
282862306a36Sopenharmony_ci				pr_info("Copied translation tables from previous kernel for %s\n",
282962306a36Sopenharmony_ci					iommu->name);
283062306a36Sopenharmony_ci			}
283162306a36Sopenharmony_ci		}
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci		if (!ecap_pass_through(iommu->ecap))
283462306a36Sopenharmony_ci			hw_pass_through = 0;
283562306a36Sopenharmony_ci		intel_svm_check(iommu);
283662306a36Sopenharmony_ci	}
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ci	/*
283962306a36Sopenharmony_ci	 * Now that qi is enabled on all iommus, set the root entry and flush
284062306a36Sopenharmony_ci	 * caches. This is required on some Intel X58 chipsets, otherwise the
284162306a36Sopenharmony_ci	 * flush_context function will loop forever and the boot hangs.
284262306a36Sopenharmony_ci	 */
284362306a36Sopenharmony_ci	for_each_active_iommu(iommu, drhd) {
284462306a36Sopenharmony_ci		iommu_flush_write_buffer(iommu);
284562306a36Sopenharmony_ci		iommu_set_root_entry(iommu);
284662306a36Sopenharmony_ci	}
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci#ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA
284962306a36Sopenharmony_ci	dmar_map_gfx = 0;
285062306a36Sopenharmony_ci#endif
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci	if (!dmar_map_gfx)
285362306a36Sopenharmony_ci		iommu_identity_mapping |= IDENTMAP_GFX;
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	check_tylersburg_isoch();
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci	ret = si_domain_init(hw_pass_through);
285862306a36Sopenharmony_ci	if (ret)
285962306a36Sopenharmony_ci		goto free_iommu;
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci	/*
286262306a36Sopenharmony_ci	 * for each drhd
286362306a36Sopenharmony_ci	 *   enable fault log
286462306a36Sopenharmony_ci	 *   global invalidate context cache
286562306a36Sopenharmony_ci	 *   global invalidate iotlb
286662306a36Sopenharmony_ci	 *   enable translation
286762306a36Sopenharmony_ci	 */
286862306a36Sopenharmony_ci	for_each_iommu(iommu, drhd) {
286962306a36Sopenharmony_ci		if (drhd->ignored) {
287062306a36Sopenharmony_ci			/*
287162306a36Sopenharmony_ci			 * we always have to disable PMRs or DMA may fail on
287262306a36Sopenharmony_ci			 * this device
287362306a36Sopenharmony_ci			 */
287462306a36Sopenharmony_ci			if (force_on)
287562306a36Sopenharmony_ci				iommu_disable_protect_mem_regions(iommu);
287662306a36Sopenharmony_ci			continue;
287762306a36Sopenharmony_ci		}
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_ci		iommu_flush_write_buffer(iommu);
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci#ifdef CONFIG_INTEL_IOMMU_SVM
288262306a36Sopenharmony_ci		if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) {
288362306a36Sopenharmony_ci			/*
288462306a36Sopenharmony_ci			 * Call dmar_alloc_hwirq() with dmar_global_lock held,
288562306a36Sopenharmony_ci			 * could cause possible lock race condition.
288662306a36Sopenharmony_ci			 */
288762306a36Sopenharmony_ci			up_write(&dmar_global_lock);
288862306a36Sopenharmony_ci			ret = intel_svm_enable_prq(iommu);
288962306a36Sopenharmony_ci			down_write(&dmar_global_lock);
289062306a36Sopenharmony_ci			if (ret)
289162306a36Sopenharmony_ci				goto free_iommu;
289262306a36Sopenharmony_ci		}
289362306a36Sopenharmony_ci#endif
289462306a36Sopenharmony_ci		ret = dmar_set_interrupt(iommu);
289562306a36Sopenharmony_ci		if (ret)
289662306a36Sopenharmony_ci			goto free_iommu;
289762306a36Sopenharmony_ci	}
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci	return 0;
290062306a36Sopenharmony_ci
290162306a36Sopenharmony_cifree_iommu:
290262306a36Sopenharmony_ci	for_each_active_iommu(iommu, drhd) {
290362306a36Sopenharmony_ci		disable_dmar_iommu(iommu);
290462306a36Sopenharmony_ci		free_dmar_iommu(iommu);
290562306a36Sopenharmony_ci	}
290662306a36Sopenharmony_ci	if (si_domain) {
290762306a36Sopenharmony_ci		domain_exit(si_domain);
290862306a36Sopenharmony_ci		si_domain = NULL;
290962306a36Sopenharmony_ci	}
291062306a36Sopenharmony_ci
291162306a36Sopenharmony_ci	return ret;
291262306a36Sopenharmony_ci}
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_cistatic void __init init_no_remapping_devices(void)
291562306a36Sopenharmony_ci{
291662306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd;
291762306a36Sopenharmony_ci	struct device *dev;
291862306a36Sopenharmony_ci	int i;
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci	for_each_drhd_unit(drhd) {
292162306a36Sopenharmony_ci		if (!drhd->include_all) {
292262306a36Sopenharmony_ci			for_each_active_dev_scope(drhd->devices,
292362306a36Sopenharmony_ci						  drhd->devices_cnt, i, dev)
292462306a36Sopenharmony_ci				break;
292562306a36Sopenharmony_ci			/* ignore DMAR unit if no devices exist */
292662306a36Sopenharmony_ci			if (i == drhd->devices_cnt)
292762306a36Sopenharmony_ci				drhd->ignored = 1;
292862306a36Sopenharmony_ci		}
292962306a36Sopenharmony_ci	}
293062306a36Sopenharmony_ci
293162306a36Sopenharmony_ci	for_each_active_drhd_unit(drhd) {
293262306a36Sopenharmony_ci		if (drhd->include_all)
293362306a36Sopenharmony_ci			continue;
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci		for_each_active_dev_scope(drhd->devices,
293662306a36Sopenharmony_ci					  drhd->devices_cnt, i, dev)
293762306a36Sopenharmony_ci			if (!dev_is_pci(dev) || !IS_GFX_DEVICE(to_pci_dev(dev)))
293862306a36Sopenharmony_ci				break;
293962306a36Sopenharmony_ci		if (i < drhd->devices_cnt)
294062306a36Sopenharmony_ci			continue;
294162306a36Sopenharmony_ci
294262306a36Sopenharmony_ci		/* This IOMMU has *only* gfx devices. Either bypass it or
294362306a36Sopenharmony_ci		   set the gfx_mapped flag, as appropriate */
294462306a36Sopenharmony_ci		drhd->gfx_dedicated = 1;
294562306a36Sopenharmony_ci		if (!dmar_map_gfx)
294662306a36Sopenharmony_ci			drhd->ignored = 1;
294762306a36Sopenharmony_ci	}
294862306a36Sopenharmony_ci}
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci#ifdef CONFIG_SUSPEND
295162306a36Sopenharmony_cistatic int init_iommu_hw(void)
295262306a36Sopenharmony_ci{
295362306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd;
295462306a36Sopenharmony_ci	struct intel_iommu *iommu = NULL;
295562306a36Sopenharmony_ci	int ret;
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci	for_each_active_iommu(iommu, drhd) {
295862306a36Sopenharmony_ci		if (iommu->qi) {
295962306a36Sopenharmony_ci			ret = dmar_reenable_qi(iommu);
296062306a36Sopenharmony_ci			if (ret)
296162306a36Sopenharmony_ci				return ret;
296262306a36Sopenharmony_ci		}
296362306a36Sopenharmony_ci	}
296462306a36Sopenharmony_ci
296562306a36Sopenharmony_ci	for_each_iommu(iommu, drhd) {
296662306a36Sopenharmony_ci		if (drhd->ignored) {
296762306a36Sopenharmony_ci			/*
296862306a36Sopenharmony_ci			 * we always have to disable PMRs or DMA may fail on
296962306a36Sopenharmony_ci			 * this device
297062306a36Sopenharmony_ci			 */
297162306a36Sopenharmony_ci			if (force_on)
297262306a36Sopenharmony_ci				iommu_disable_protect_mem_regions(iommu);
297362306a36Sopenharmony_ci			continue;
297462306a36Sopenharmony_ci		}
297562306a36Sopenharmony_ci
297662306a36Sopenharmony_ci		iommu_flush_write_buffer(iommu);
297762306a36Sopenharmony_ci		iommu_set_root_entry(iommu);
297862306a36Sopenharmony_ci		iommu_enable_translation(iommu);
297962306a36Sopenharmony_ci		iommu_disable_protect_mem_regions(iommu);
298062306a36Sopenharmony_ci	}
298162306a36Sopenharmony_ci
298262306a36Sopenharmony_ci	return 0;
298362306a36Sopenharmony_ci}
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_cistatic void iommu_flush_all(void)
298662306a36Sopenharmony_ci{
298762306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd;
298862306a36Sopenharmony_ci	struct intel_iommu *iommu;
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci	for_each_active_iommu(iommu, drhd) {
299162306a36Sopenharmony_ci		iommu->flush.flush_context(iommu, 0, 0, 0,
299262306a36Sopenharmony_ci					   DMA_CCMD_GLOBAL_INVL);
299362306a36Sopenharmony_ci		iommu->flush.flush_iotlb(iommu, 0, 0, 0,
299462306a36Sopenharmony_ci					 DMA_TLB_GLOBAL_FLUSH);
299562306a36Sopenharmony_ci	}
299662306a36Sopenharmony_ci}
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_cistatic int iommu_suspend(void)
299962306a36Sopenharmony_ci{
300062306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd;
300162306a36Sopenharmony_ci	struct intel_iommu *iommu = NULL;
300262306a36Sopenharmony_ci	unsigned long flag;
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	iommu_flush_all();
300562306a36Sopenharmony_ci
300662306a36Sopenharmony_ci	for_each_active_iommu(iommu, drhd) {
300762306a36Sopenharmony_ci		iommu_disable_translation(iommu);
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci		raw_spin_lock_irqsave(&iommu->register_lock, flag);
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci		iommu->iommu_state[SR_DMAR_FECTL_REG] =
301262306a36Sopenharmony_ci			readl(iommu->reg + DMAR_FECTL_REG);
301362306a36Sopenharmony_ci		iommu->iommu_state[SR_DMAR_FEDATA_REG] =
301462306a36Sopenharmony_ci			readl(iommu->reg + DMAR_FEDATA_REG);
301562306a36Sopenharmony_ci		iommu->iommu_state[SR_DMAR_FEADDR_REG] =
301662306a36Sopenharmony_ci			readl(iommu->reg + DMAR_FEADDR_REG);
301762306a36Sopenharmony_ci		iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
301862306a36Sopenharmony_ci			readl(iommu->reg + DMAR_FEUADDR_REG);
301962306a36Sopenharmony_ci
302062306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
302162306a36Sopenharmony_ci	}
302262306a36Sopenharmony_ci	return 0;
302362306a36Sopenharmony_ci}
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_cistatic void iommu_resume(void)
302662306a36Sopenharmony_ci{
302762306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd;
302862306a36Sopenharmony_ci	struct intel_iommu *iommu = NULL;
302962306a36Sopenharmony_ci	unsigned long flag;
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	if (init_iommu_hw()) {
303262306a36Sopenharmony_ci		if (force_on)
303362306a36Sopenharmony_ci			panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
303462306a36Sopenharmony_ci		else
303562306a36Sopenharmony_ci			WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
303662306a36Sopenharmony_ci		return;
303762306a36Sopenharmony_ci	}
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci	for_each_active_iommu(iommu, drhd) {
304062306a36Sopenharmony_ci
304162306a36Sopenharmony_ci		raw_spin_lock_irqsave(&iommu->register_lock, flag);
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci		writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
304462306a36Sopenharmony_ci			iommu->reg + DMAR_FECTL_REG);
304562306a36Sopenharmony_ci		writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
304662306a36Sopenharmony_ci			iommu->reg + DMAR_FEDATA_REG);
304762306a36Sopenharmony_ci		writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
304862306a36Sopenharmony_ci			iommu->reg + DMAR_FEADDR_REG);
304962306a36Sopenharmony_ci		writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
305062306a36Sopenharmony_ci			iommu->reg + DMAR_FEUADDR_REG);
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
305362306a36Sopenharmony_ci	}
305462306a36Sopenharmony_ci}
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_cistatic struct syscore_ops iommu_syscore_ops = {
305762306a36Sopenharmony_ci	.resume		= iommu_resume,
305862306a36Sopenharmony_ci	.suspend	= iommu_suspend,
305962306a36Sopenharmony_ci};
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_cistatic void __init init_iommu_pm_ops(void)
306262306a36Sopenharmony_ci{
306362306a36Sopenharmony_ci	register_syscore_ops(&iommu_syscore_ops);
306462306a36Sopenharmony_ci}
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci#else
306762306a36Sopenharmony_cistatic inline void init_iommu_pm_ops(void) {}
306862306a36Sopenharmony_ci#endif	/* CONFIG_PM */
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_cistatic int __init rmrr_sanity_check(struct acpi_dmar_reserved_memory *rmrr)
307162306a36Sopenharmony_ci{
307262306a36Sopenharmony_ci	if (!IS_ALIGNED(rmrr->base_address, PAGE_SIZE) ||
307362306a36Sopenharmony_ci	    !IS_ALIGNED(rmrr->end_address + 1, PAGE_SIZE) ||
307462306a36Sopenharmony_ci	    rmrr->end_address <= rmrr->base_address ||
307562306a36Sopenharmony_ci	    arch_rmrr_sanity_check(rmrr))
307662306a36Sopenharmony_ci		return -EINVAL;
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci	return 0;
307962306a36Sopenharmony_ci}
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ciint __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg)
308262306a36Sopenharmony_ci{
308362306a36Sopenharmony_ci	struct acpi_dmar_reserved_memory *rmrr;
308462306a36Sopenharmony_ci	struct dmar_rmrr_unit *rmrru;
308562306a36Sopenharmony_ci
308662306a36Sopenharmony_ci	rmrr = (struct acpi_dmar_reserved_memory *)header;
308762306a36Sopenharmony_ci	if (rmrr_sanity_check(rmrr)) {
308862306a36Sopenharmony_ci		pr_warn(FW_BUG
308962306a36Sopenharmony_ci			   "Your BIOS is broken; bad RMRR [%#018Lx-%#018Lx]\n"
309062306a36Sopenharmony_ci			   "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
309162306a36Sopenharmony_ci			   rmrr->base_address, rmrr->end_address,
309262306a36Sopenharmony_ci			   dmi_get_system_info(DMI_BIOS_VENDOR),
309362306a36Sopenharmony_ci			   dmi_get_system_info(DMI_BIOS_VERSION),
309462306a36Sopenharmony_ci			   dmi_get_system_info(DMI_PRODUCT_VERSION));
309562306a36Sopenharmony_ci		add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
309662306a36Sopenharmony_ci	}
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
309962306a36Sopenharmony_ci	if (!rmrru)
310062306a36Sopenharmony_ci		goto out;
310162306a36Sopenharmony_ci
310262306a36Sopenharmony_ci	rmrru->hdr = header;
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ci	rmrru->base_address = rmrr->base_address;
310562306a36Sopenharmony_ci	rmrru->end_address = rmrr->end_address;
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci	rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1),
310862306a36Sopenharmony_ci				((void *)rmrr) + rmrr->header.length,
310962306a36Sopenharmony_ci				&rmrru->devices_cnt);
311062306a36Sopenharmony_ci	if (rmrru->devices_cnt && rmrru->devices == NULL)
311162306a36Sopenharmony_ci		goto free_rmrru;
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci	list_add(&rmrru->list, &dmar_rmrr_units);
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci	return 0;
311662306a36Sopenharmony_cifree_rmrru:
311762306a36Sopenharmony_ci	kfree(rmrru);
311862306a36Sopenharmony_ciout:
311962306a36Sopenharmony_ci	return -ENOMEM;
312062306a36Sopenharmony_ci}
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_cistatic struct dmar_atsr_unit *dmar_find_atsr(struct acpi_dmar_atsr *atsr)
312362306a36Sopenharmony_ci{
312462306a36Sopenharmony_ci	struct dmar_atsr_unit *atsru;
312562306a36Sopenharmony_ci	struct acpi_dmar_atsr *tmp;
312662306a36Sopenharmony_ci
312762306a36Sopenharmony_ci	list_for_each_entry_rcu(atsru, &dmar_atsr_units, list,
312862306a36Sopenharmony_ci				dmar_rcu_check()) {
312962306a36Sopenharmony_ci		tmp = (struct acpi_dmar_atsr *)atsru->hdr;
313062306a36Sopenharmony_ci		if (atsr->segment != tmp->segment)
313162306a36Sopenharmony_ci			continue;
313262306a36Sopenharmony_ci		if (atsr->header.length != tmp->header.length)
313362306a36Sopenharmony_ci			continue;
313462306a36Sopenharmony_ci		if (memcmp(atsr, tmp, atsr->header.length) == 0)
313562306a36Sopenharmony_ci			return atsru;
313662306a36Sopenharmony_ci	}
313762306a36Sopenharmony_ci
313862306a36Sopenharmony_ci	return NULL;
313962306a36Sopenharmony_ci}
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ciint dmar_parse_one_atsr(struct acpi_dmar_header *hdr, void *arg)
314262306a36Sopenharmony_ci{
314362306a36Sopenharmony_ci	struct acpi_dmar_atsr *atsr;
314462306a36Sopenharmony_ci	struct dmar_atsr_unit *atsru;
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci	if (system_state >= SYSTEM_RUNNING && !intel_iommu_enabled)
314762306a36Sopenharmony_ci		return 0;
314862306a36Sopenharmony_ci
314962306a36Sopenharmony_ci	atsr = container_of(hdr, struct acpi_dmar_atsr, header);
315062306a36Sopenharmony_ci	atsru = dmar_find_atsr(atsr);
315162306a36Sopenharmony_ci	if (atsru)
315262306a36Sopenharmony_ci		return 0;
315362306a36Sopenharmony_ci
315462306a36Sopenharmony_ci	atsru = kzalloc(sizeof(*atsru) + hdr->length, GFP_KERNEL);
315562306a36Sopenharmony_ci	if (!atsru)
315662306a36Sopenharmony_ci		return -ENOMEM;
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci	/*
315962306a36Sopenharmony_ci	 * If memory is allocated from slab by ACPI _DSM method, we need to
316062306a36Sopenharmony_ci	 * copy the memory content because the memory buffer will be freed
316162306a36Sopenharmony_ci	 * on return.
316262306a36Sopenharmony_ci	 */
316362306a36Sopenharmony_ci	atsru->hdr = (void *)(atsru + 1);
316462306a36Sopenharmony_ci	memcpy(atsru->hdr, hdr, hdr->length);
316562306a36Sopenharmony_ci	atsru->include_all = atsr->flags & 0x1;
316662306a36Sopenharmony_ci	if (!atsru->include_all) {
316762306a36Sopenharmony_ci		atsru->devices = dmar_alloc_dev_scope((void *)(atsr + 1),
316862306a36Sopenharmony_ci				(void *)atsr + atsr->header.length,
316962306a36Sopenharmony_ci				&atsru->devices_cnt);
317062306a36Sopenharmony_ci		if (atsru->devices_cnt && atsru->devices == NULL) {
317162306a36Sopenharmony_ci			kfree(atsru);
317262306a36Sopenharmony_ci			return -ENOMEM;
317362306a36Sopenharmony_ci		}
317462306a36Sopenharmony_ci	}
317562306a36Sopenharmony_ci
317662306a36Sopenharmony_ci	list_add_rcu(&atsru->list, &dmar_atsr_units);
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci	return 0;
317962306a36Sopenharmony_ci}
318062306a36Sopenharmony_ci
318162306a36Sopenharmony_cistatic void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru)
318262306a36Sopenharmony_ci{
318362306a36Sopenharmony_ci	dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt);
318462306a36Sopenharmony_ci	kfree(atsru);
318562306a36Sopenharmony_ci}
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ciint dmar_release_one_atsr(struct acpi_dmar_header *hdr, void *arg)
318862306a36Sopenharmony_ci{
318962306a36Sopenharmony_ci	struct acpi_dmar_atsr *atsr;
319062306a36Sopenharmony_ci	struct dmar_atsr_unit *atsru;
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	atsr = container_of(hdr, struct acpi_dmar_atsr, header);
319362306a36Sopenharmony_ci	atsru = dmar_find_atsr(atsr);
319462306a36Sopenharmony_ci	if (atsru) {
319562306a36Sopenharmony_ci		list_del_rcu(&atsru->list);
319662306a36Sopenharmony_ci		synchronize_rcu();
319762306a36Sopenharmony_ci		intel_iommu_free_atsr(atsru);
319862306a36Sopenharmony_ci	}
319962306a36Sopenharmony_ci
320062306a36Sopenharmony_ci	return 0;
320162306a36Sopenharmony_ci}
320262306a36Sopenharmony_ci
320362306a36Sopenharmony_ciint dmar_check_one_atsr(struct acpi_dmar_header *hdr, void *arg)
320462306a36Sopenharmony_ci{
320562306a36Sopenharmony_ci	int i;
320662306a36Sopenharmony_ci	struct device *dev;
320762306a36Sopenharmony_ci	struct acpi_dmar_atsr *atsr;
320862306a36Sopenharmony_ci	struct dmar_atsr_unit *atsru;
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci	atsr = container_of(hdr, struct acpi_dmar_atsr, header);
321162306a36Sopenharmony_ci	atsru = dmar_find_atsr(atsr);
321262306a36Sopenharmony_ci	if (!atsru)
321362306a36Sopenharmony_ci		return 0;
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	if (!atsru->include_all && atsru->devices && atsru->devices_cnt) {
321662306a36Sopenharmony_ci		for_each_active_dev_scope(atsru->devices, atsru->devices_cnt,
321762306a36Sopenharmony_ci					  i, dev)
321862306a36Sopenharmony_ci			return -EBUSY;
321962306a36Sopenharmony_ci	}
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	return 0;
322262306a36Sopenharmony_ci}
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_cistatic struct dmar_satc_unit *dmar_find_satc(struct acpi_dmar_satc *satc)
322562306a36Sopenharmony_ci{
322662306a36Sopenharmony_ci	struct dmar_satc_unit *satcu;
322762306a36Sopenharmony_ci	struct acpi_dmar_satc *tmp;
322862306a36Sopenharmony_ci
322962306a36Sopenharmony_ci	list_for_each_entry_rcu(satcu, &dmar_satc_units, list,
323062306a36Sopenharmony_ci				dmar_rcu_check()) {
323162306a36Sopenharmony_ci		tmp = (struct acpi_dmar_satc *)satcu->hdr;
323262306a36Sopenharmony_ci		if (satc->segment != tmp->segment)
323362306a36Sopenharmony_ci			continue;
323462306a36Sopenharmony_ci		if (satc->header.length != tmp->header.length)
323562306a36Sopenharmony_ci			continue;
323662306a36Sopenharmony_ci		if (memcmp(satc, tmp, satc->header.length) == 0)
323762306a36Sopenharmony_ci			return satcu;
323862306a36Sopenharmony_ci	}
323962306a36Sopenharmony_ci
324062306a36Sopenharmony_ci	return NULL;
324162306a36Sopenharmony_ci}
324262306a36Sopenharmony_ci
324362306a36Sopenharmony_ciint dmar_parse_one_satc(struct acpi_dmar_header *hdr, void *arg)
324462306a36Sopenharmony_ci{
324562306a36Sopenharmony_ci	struct acpi_dmar_satc *satc;
324662306a36Sopenharmony_ci	struct dmar_satc_unit *satcu;
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci	if (system_state >= SYSTEM_RUNNING && !intel_iommu_enabled)
324962306a36Sopenharmony_ci		return 0;
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci	satc = container_of(hdr, struct acpi_dmar_satc, header);
325262306a36Sopenharmony_ci	satcu = dmar_find_satc(satc);
325362306a36Sopenharmony_ci	if (satcu)
325462306a36Sopenharmony_ci		return 0;
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_ci	satcu = kzalloc(sizeof(*satcu) + hdr->length, GFP_KERNEL);
325762306a36Sopenharmony_ci	if (!satcu)
325862306a36Sopenharmony_ci		return -ENOMEM;
325962306a36Sopenharmony_ci
326062306a36Sopenharmony_ci	satcu->hdr = (void *)(satcu + 1);
326162306a36Sopenharmony_ci	memcpy(satcu->hdr, hdr, hdr->length);
326262306a36Sopenharmony_ci	satcu->atc_required = satc->flags & 0x1;
326362306a36Sopenharmony_ci	satcu->devices = dmar_alloc_dev_scope((void *)(satc + 1),
326462306a36Sopenharmony_ci					      (void *)satc + satc->header.length,
326562306a36Sopenharmony_ci					      &satcu->devices_cnt);
326662306a36Sopenharmony_ci	if (satcu->devices_cnt && !satcu->devices) {
326762306a36Sopenharmony_ci		kfree(satcu);
326862306a36Sopenharmony_ci		return -ENOMEM;
326962306a36Sopenharmony_ci	}
327062306a36Sopenharmony_ci	list_add_rcu(&satcu->list, &dmar_satc_units);
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci	return 0;
327362306a36Sopenharmony_ci}
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_cistatic int intel_iommu_add(struct dmar_drhd_unit *dmaru)
327662306a36Sopenharmony_ci{
327762306a36Sopenharmony_ci	int sp, ret;
327862306a36Sopenharmony_ci	struct intel_iommu *iommu = dmaru->iommu;
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_ci	ret = intel_cap_audit(CAP_AUDIT_HOTPLUG_DMAR, iommu);
328162306a36Sopenharmony_ci	if (ret)
328262306a36Sopenharmony_ci		goto out;
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci	if (hw_pass_through && !ecap_pass_through(iommu->ecap)) {
328562306a36Sopenharmony_ci		pr_warn("%s: Doesn't support hardware pass through.\n",
328662306a36Sopenharmony_ci			iommu->name);
328762306a36Sopenharmony_ci		return -ENXIO;
328862306a36Sopenharmony_ci	}
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	sp = domain_update_iommu_superpage(NULL, iommu) - 1;
329162306a36Sopenharmony_ci	if (sp >= 0 && !(cap_super_page_val(iommu->cap) & (1 << sp))) {
329262306a36Sopenharmony_ci		pr_warn("%s: Doesn't support large page.\n",
329362306a36Sopenharmony_ci			iommu->name);
329462306a36Sopenharmony_ci		return -ENXIO;
329562306a36Sopenharmony_ci	}
329662306a36Sopenharmony_ci
329762306a36Sopenharmony_ci	/*
329862306a36Sopenharmony_ci	 * Disable translation if already enabled prior to OS handover.
329962306a36Sopenharmony_ci	 */
330062306a36Sopenharmony_ci	if (iommu->gcmd & DMA_GCMD_TE)
330162306a36Sopenharmony_ci		iommu_disable_translation(iommu);
330262306a36Sopenharmony_ci
330362306a36Sopenharmony_ci	ret = iommu_init_domains(iommu);
330462306a36Sopenharmony_ci	if (ret == 0)
330562306a36Sopenharmony_ci		ret = iommu_alloc_root_entry(iommu);
330662306a36Sopenharmony_ci	if (ret)
330762306a36Sopenharmony_ci		goto out;
330862306a36Sopenharmony_ci
330962306a36Sopenharmony_ci	intel_svm_check(iommu);
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_ci	if (dmaru->ignored) {
331262306a36Sopenharmony_ci		/*
331362306a36Sopenharmony_ci		 * we always have to disable PMRs or DMA may fail on this device
331462306a36Sopenharmony_ci		 */
331562306a36Sopenharmony_ci		if (force_on)
331662306a36Sopenharmony_ci			iommu_disable_protect_mem_regions(iommu);
331762306a36Sopenharmony_ci		return 0;
331862306a36Sopenharmony_ci	}
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci	intel_iommu_init_qi(iommu);
332162306a36Sopenharmony_ci	iommu_flush_write_buffer(iommu);
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci#ifdef CONFIG_INTEL_IOMMU_SVM
332462306a36Sopenharmony_ci	if (pasid_supported(iommu) && ecap_prs(iommu->ecap)) {
332562306a36Sopenharmony_ci		ret = intel_svm_enable_prq(iommu);
332662306a36Sopenharmony_ci		if (ret)
332762306a36Sopenharmony_ci			goto disable_iommu;
332862306a36Sopenharmony_ci	}
332962306a36Sopenharmony_ci#endif
333062306a36Sopenharmony_ci	ret = dmar_set_interrupt(iommu);
333162306a36Sopenharmony_ci	if (ret)
333262306a36Sopenharmony_ci		goto disable_iommu;
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci	iommu_set_root_entry(iommu);
333562306a36Sopenharmony_ci	iommu_enable_translation(iommu);
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ci	iommu_disable_protect_mem_regions(iommu);
333862306a36Sopenharmony_ci	return 0;
333962306a36Sopenharmony_ci
334062306a36Sopenharmony_cidisable_iommu:
334162306a36Sopenharmony_ci	disable_dmar_iommu(iommu);
334262306a36Sopenharmony_ciout:
334362306a36Sopenharmony_ci	free_dmar_iommu(iommu);
334462306a36Sopenharmony_ci	return ret;
334562306a36Sopenharmony_ci}
334662306a36Sopenharmony_ci
334762306a36Sopenharmony_ciint dmar_iommu_hotplug(struct dmar_drhd_unit *dmaru, bool insert)
334862306a36Sopenharmony_ci{
334962306a36Sopenharmony_ci	int ret = 0;
335062306a36Sopenharmony_ci	struct intel_iommu *iommu = dmaru->iommu;
335162306a36Sopenharmony_ci
335262306a36Sopenharmony_ci	if (!intel_iommu_enabled)
335362306a36Sopenharmony_ci		return 0;
335462306a36Sopenharmony_ci	if (iommu == NULL)
335562306a36Sopenharmony_ci		return -EINVAL;
335662306a36Sopenharmony_ci
335762306a36Sopenharmony_ci	if (insert) {
335862306a36Sopenharmony_ci		ret = intel_iommu_add(dmaru);
335962306a36Sopenharmony_ci	} else {
336062306a36Sopenharmony_ci		disable_dmar_iommu(iommu);
336162306a36Sopenharmony_ci		free_dmar_iommu(iommu);
336262306a36Sopenharmony_ci	}
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	return ret;
336562306a36Sopenharmony_ci}
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_cistatic void intel_iommu_free_dmars(void)
336862306a36Sopenharmony_ci{
336962306a36Sopenharmony_ci	struct dmar_rmrr_unit *rmrru, *rmrr_n;
337062306a36Sopenharmony_ci	struct dmar_atsr_unit *atsru, *atsr_n;
337162306a36Sopenharmony_ci	struct dmar_satc_unit *satcu, *satc_n;
337262306a36Sopenharmony_ci
337362306a36Sopenharmony_ci	list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
337462306a36Sopenharmony_ci		list_del(&rmrru->list);
337562306a36Sopenharmony_ci		dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
337662306a36Sopenharmony_ci		kfree(rmrru);
337762306a36Sopenharmony_ci	}
337862306a36Sopenharmony_ci
337962306a36Sopenharmony_ci	list_for_each_entry_safe(atsru, atsr_n, &dmar_atsr_units, list) {
338062306a36Sopenharmony_ci		list_del(&atsru->list);
338162306a36Sopenharmony_ci		intel_iommu_free_atsr(atsru);
338262306a36Sopenharmony_ci	}
338362306a36Sopenharmony_ci	list_for_each_entry_safe(satcu, satc_n, &dmar_satc_units, list) {
338462306a36Sopenharmony_ci		list_del(&satcu->list);
338562306a36Sopenharmony_ci		dmar_free_dev_scope(&satcu->devices, &satcu->devices_cnt);
338662306a36Sopenharmony_ci		kfree(satcu);
338762306a36Sopenharmony_ci	}
338862306a36Sopenharmony_ci}
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_cistatic struct dmar_satc_unit *dmar_find_matched_satc_unit(struct pci_dev *dev)
339162306a36Sopenharmony_ci{
339262306a36Sopenharmony_ci	struct dmar_satc_unit *satcu;
339362306a36Sopenharmony_ci	struct acpi_dmar_satc *satc;
339462306a36Sopenharmony_ci	struct device *tmp;
339562306a36Sopenharmony_ci	int i;
339662306a36Sopenharmony_ci
339762306a36Sopenharmony_ci	dev = pci_physfn(dev);
339862306a36Sopenharmony_ci	rcu_read_lock();
339962306a36Sopenharmony_ci
340062306a36Sopenharmony_ci	list_for_each_entry_rcu(satcu, &dmar_satc_units, list) {
340162306a36Sopenharmony_ci		satc = container_of(satcu->hdr, struct acpi_dmar_satc, header);
340262306a36Sopenharmony_ci		if (satc->segment != pci_domain_nr(dev->bus))
340362306a36Sopenharmony_ci			continue;
340462306a36Sopenharmony_ci		for_each_dev_scope(satcu->devices, satcu->devices_cnt, i, tmp)
340562306a36Sopenharmony_ci			if (to_pci_dev(tmp) == dev)
340662306a36Sopenharmony_ci				goto out;
340762306a36Sopenharmony_ci	}
340862306a36Sopenharmony_ci	satcu = NULL;
340962306a36Sopenharmony_ciout:
341062306a36Sopenharmony_ci	rcu_read_unlock();
341162306a36Sopenharmony_ci	return satcu;
341262306a36Sopenharmony_ci}
341362306a36Sopenharmony_ci
341462306a36Sopenharmony_cistatic int dmar_ats_supported(struct pci_dev *dev, struct intel_iommu *iommu)
341562306a36Sopenharmony_ci{
341662306a36Sopenharmony_ci	int i, ret = 1;
341762306a36Sopenharmony_ci	struct pci_bus *bus;
341862306a36Sopenharmony_ci	struct pci_dev *bridge = NULL;
341962306a36Sopenharmony_ci	struct device *tmp;
342062306a36Sopenharmony_ci	struct acpi_dmar_atsr *atsr;
342162306a36Sopenharmony_ci	struct dmar_atsr_unit *atsru;
342262306a36Sopenharmony_ci	struct dmar_satc_unit *satcu;
342362306a36Sopenharmony_ci
342462306a36Sopenharmony_ci	dev = pci_physfn(dev);
342562306a36Sopenharmony_ci	satcu = dmar_find_matched_satc_unit(dev);
342662306a36Sopenharmony_ci	if (satcu)
342762306a36Sopenharmony_ci		/*
342862306a36Sopenharmony_ci		 * This device supports ATS as it is in SATC table.
342962306a36Sopenharmony_ci		 * When IOMMU is in legacy mode, enabling ATS is done
343062306a36Sopenharmony_ci		 * automatically by HW for the device that requires
343162306a36Sopenharmony_ci		 * ATS, hence OS should not enable this device ATS
343262306a36Sopenharmony_ci		 * to avoid duplicated TLB invalidation.
343362306a36Sopenharmony_ci		 */
343462306a36Sopenharmony_ci		return !(satcu->atc_required && !sm_supported(iommu));
343562306a36Sopenharmony_ci
343662306a36Sopenharmony_ci	for (bus = dev->bus; bus; bus = bus->parent) {
343762306a36Sopenharmony_ci		bridge = bus->self;
343862306a36Sopenharmony_ci		/* If it's an integrated device, allow ATS */
343962306a36Sopenharmony_ci		if (!bridge)
344062306a36Sopenharmony_ci			return 1;
344162306a36Sopenharmony_ci		/* Connected via non-PCIe: no ATS */
344262306a36Sopenharmony_ci		if (!pci_is_pcie(bridge) ||
344362306a36Sopenharmony_ci		    pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE)
344462306a36Sopenharmony_ci			return 0;
344562306a36Sopenharmony_ci		/* If we found the root port, look it up in the ATSR */
344662306a36Sopenharmony_ci		if (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT)
344762306a36Sopenharmony_ci			break;
344862306a36Sopenharmony_ci	}
344962306a36Sopenharmony_ci
345062306a36Sopenharmony_ci	rcu_read_lock();
345162306a36Sopenharmony_ci	list_for_each_entry_rcu(atsru, &dmar_atsr_units, list) {
345262306a36Sopenharmony_ci		atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
345362306a36Sopenharmony_ci		if (atsr->segment != pci_domain_nr(dev->bus))
345462306a36Sopenharmony_ci			continue;
345562306a36Sopenharmony_ci
345662306a36Sopenharmony_ci		for_each_dev_scope(atsru->devices, atsru->devices_cnt, i, tmp)
345762306a36Sopenharmony_ci			if (tmp == &bridge->dev)
345862306a36Sopenharmony_ci				goto out;
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci		if (atsru->include_all)
346162306a36Sopenharmony_ci			goto out;
346262306a36Sopenharmony_ci	}
346362306a36Sopenharmony_ci	ret = 0;
346462306a36Sopenharmony_ciout:
346562306a36Sopenharmony_ci	rcu_read_unlock();
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ci	return ret;
346862306a36Sopenharmony_ci}
346962306a36Sopenharmony_ci
347062306a36Sopenharmony_ciint dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
347162306a36Sopenharmony_ci{
347262306a36Sopenharmony_ci	int ret;
347362306a36Sopenharmony_ci	struct dmar_rmrr_unit *rmrru;
347462306a36Sopenharmony_ci	struct dmar_atsr_unit *atsru;
347562306a36Sopenharmony_ci	struct dmar_satc_unit *satcu;
347662306a36Sopenharmony_ci	struct acpi_dmar_atsr *atsr;
347762306a36Sopenharmony_ci	struct acpi_dmar_reserved_memory *rmrr;
347862306a36Sopenharmony_ci	struct acpi_dmar_satc *satc;
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_ci	if (!intel_iommu_enabled && system_state >= SYSTEM_RUNNING)
348162306a36Sopenharmony_ci		return 0;
348262306a36Sopenharmony_ci
348362306a36Sopenharmony_ci	list_for_each_entry(rmrru, &dmar_rmrr_units, list) {
348462306a36Sopenharmony_ci		rmrr = container_of(rmrru->hdr,
348562306a36Sopenharmony_ci				    struct acpi_dmar_reserved_memory, header);
348662306a36Sopenharmony_ci		if (info->event == BUS_NOTIFY_ADD_DEVICE) {
348762306a36Sopenharmony_ci			ret = dmar_insert_dev_scope(info, (void *)(rmrr + 1),
348862306a36Sopenharmony_ci				((void *)rmrr) + rmrr->header.length,
348962306a36Sopenharmony_ci				rmrr->segment, rmrru->devices,
349062306a36Sopenharmony_ci				rmrru->devices_cnt);
349162306a36Sopenharmony_ci			if (ret < 0)
349262306a36Sopenharmony_ci				return ret;
349362306a36Sopenharmony_ci		} else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
349462306a36Sopenharmony_ci			dmar_remove_dev_scope(info, rmrr->segment,
349562306a36Sopenharmony_ci				rmrru->devices, rmrru->devices_cnt);
349662306a36Sopenharmony_ci		}
349762306a36Sopenharmony_ci	}
349862306a36Sopenharmony_ci
349962306a36Sopenharmony_ci	list_for_each_entry(atsru, &dmar_atsr_units, list) {
350062306a36Sopenharmony_ci		if (atsru->include_all)
350162306a36Sopenharmony_ci			continue;
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_ci		atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
350462306a36Sopenharmony_ci		if (info->event == BUS_NOTIFY_ADD_DEVICE) {
350562306a36Sopenharmony_ci			ret = dmar_insert_dev_scope(info, (void *)(atsr + 1),
350662306a36Sopenharmony_ci					(void *)atsr + atsr->header.length,
350762306a36Sopenharmony_ci					atsr->segment, atsru->devices,
350862306a36Sopenharmony_ci					atsru->devices_cnt);
350962306a36Sopenharmony_ci			if (ret > 0)
351062306a36Sopenharmony_ci				break;
351162306a36Sopenharmony_ci			else if (ret < 0)
351262306a36Sopenharmony_ci				return ret;
351362306a36Sopenharmony_ci		} else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
351462306a36Sopenharmony_ci			if (dmar_remove_dev_scope(info, atsr->segment,
351562306a36Sopenharmony_ci					atsru->devices, atsru->devices_cnt))
351662306a36Sopenharmony_ci				break;
351762306a36Sopenharmony_ci		}
351862306a36Sopenharmony_ci	}
351962306a36Sopenharmony_ci	list_for_each_entry(satcu, &dmar_satc_units, list) {
352062306a36Sopenharmony_ci		satc = container_of(satcu->hdr, struct acpi_dmar_satc, header);
352162306a36Sopenharmony_ci		if (info->event == BUS_NOTIFY_ADD_DEVICE) {
352262306a36Sopenharmony_ci			ret = dmar_insert_dev_scope(info, (void *)(satc + 1),
352362306a36Sopenharmony_ci					(void *)satc + satc->header.length,
352462306a36Sopenharmony_ci					satc->segment, satcu->devices,
352562306a36Sopenharmony_ci					satcu->devices_cnt);
352662306a36Sopenharmony_ci			if (ret > 0)
352762306a36Sopenharmony_ci				break;
352862306a36Sopenharmony_ci			else if (ret < 0)
352962306a36Sopenharmony_ci				return ret;
353062306a36Sopenharmony_ci		} else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
353162306a36Sopenharmony_ci			if (dmar_remove_dev_scope(info, satc->segment,
353262306a36Sopenharmony_ci					satcu->devices, satcu->devices_cnt))
353362306a36Sopenharmony_ci				break;
353462306a36Sopenharmony_ci		}
353562306a36Sopenharmony_ci	}
353662306a36Sopenharmony_ci
353762306a36Sopenharmony_ci	return 0;
353862306a36Sopenharmony_ci}
353962306a36Sopenharmony_ci
354062306a36Sopenharmony_cistatic int intel_iommu_memory_notifier(struct notifier_block *nb,
354162306a36Sopenharmony_ci				       unsigned long val, void *v)
354262306a36Sopenharmony_ci{
354362306a36Sopenharmony_ci	struct memory_notify *mhp = v;
354462306a36Sopenharmony_ci	unsigned long start_vpfn = mm_to_dma_pfn_start(mhp->start_pfn);
354562306a36Sopenharmony_ci	unsigned long last_vpfn = mm_to_dma_pfn_end(mhp->start_pfn +
354662306a36Sopenharmony_ci			mhp->nr_pages - 1);
354762306a36Sopenharmony_ci
354862306a36Sopenharmony_ci	switch (val) {
354962306a36Sopenharmony_ci	case MEM_GOING_ONLINE:
355062306a36Sopenharmony_ci		if (iommu_domain_identity_map(si_domain,
355162306a36Sopenharmony_ci					      start_vpfn, last_vpfn)) {
355262306a36Sopenharmony_ci			pr_warn("Failed to build identity map for [%lx-%lx]\n",
355362306a36Sopenharmony_ci				start_vpfn, last_vpfn);
355462306a36Sopenharmony_ci			return NOTIFY_BAD;
355562306a36Sopenharmony_ci		}
355662306a36Sopenharmony_ci		break;
355762306a36Sopenharmony_ci
355862306a36Sopenharmony_ci	case MEM_OFFLINE:
355962306a36Sopenharmony_ci	case MEM_CANCEL_ONLINE:
356062306a36Sopenharmony_ci		{
356162306a36Sopenharmony_ci			struct dmar_drhd_unit *drhd;
356262306a36Sopenharmony_ci			struct intel_iommu *iommu;
356362306a36Sopenharmony_ci			LIST_HEAD(freelist);
356462306a36Sopenharmony_ci
356562306a36Sopenharmony_ci			domain_unmap(si_domain, start_vpfn, last_vpfn, &freelist);
356662306a36Sopenharmony_ci
356762306a36Sopenharmony_ci			rcu_read_lock();
356862306a36Sopenharmony_ci			for_each_active_iommu(iommu, drhd)
356962306a36Sopenharmony_ci				iommu_flush_iotlb_psi(iommu, si_domain,
357062306a36Sopenharmony_ci					start_vpfn, mhp->nr_pages,
357162306a36Sopenharmony_ci					list_empty(&freelist), 0);
357262306a36Sopenharmony_ci			rcu_read_unlock();
357362306a36Sopenharmony_ci			put_pages_list(&freelist);
357462306a36Sopenharmony_ci		}
357562306a36Sopenharmony_ci		break;
357662306a36Sopenharmony_ci	}
357762306a36Sopenharmony_ci
357862306a36Sopenharmony_ci	return NOTIFY_OK;
357962306a36Sopenharmony_ci}
358062306a36Sopenharmony_ci
358162306a36Sopenharmony_cistatic struct notifier_block intel_iommu_memory_nb = {
358262306a36Sopenharmony_ci	.notifier_call = intel_iommu_memory_notifier,
358362306a36Sopenharmony_ci	.priority = 0
358462306a36Sopenharmony_ci};
358562306a36Sopenharmony_ci
358662306a36Sopenharmony_cistatic void intel_disable_iommus(void)
358762306a36Sopenharmony_ci{
358862306a36Sopenharmony_ci	struct intel_iommu *iommu = NULL;
358962306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd;
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci	for_each_iommu(iommu, drhd)
359262306a36Sopenharmony_ci		iommu_disable_translation(iommu);
359362306a36Sopenharmony_ci}
359462306a36Sopenharmony_ci
359562306a36Sopenharmony_civoid intel_iommu_shutdown(void)
359662306a36Sopenharmony_ci{
359762306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd;
359862306a36Sopenharmony_ci	struct intel_iommu *iommu = NULL;
359962306a36Sopenharmony_ci
360062306a36Sopenharmony_ci	if (no_iommu || dmar_disabled)
360162306a36Sopenharmony_ci		return;
360262306a36Sopenharmony_ci
360362306a36Sopenharmony_ci	down_write(&dmar_global_lock);
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_ci	/* Disable PMRs explicitly here. */
360662306a36Sopenharmony_ci	for_each_iommu(iommu, drhd)
360762306a36Sopenharmony_ci		iommu_disable_protect_mem_regions(iommu);
360862306a36Sopenharmony_ci
360962306a36Sopenharmony_ci	/* Make sure the IOMMUs are switched off */
361062306a36Sopenharmony_ci	intel_disable_iommus();
361162306a36Sopenharmony_ci
361262306a36Sopenharmony_ci	up_write(&dmar_global_lock);
361362306a36Sopenharmony_ci}
361462306a36Sopenharmony_ci
361562306a36Sopenharmony_cistatic inline struct intel_iommu *dev_to_intel_iommu(struct device *dev)
361662306a36Sopenharmony_ci{
361762306a36Sopenharmony_ci	struct iommu_device *iommu_dev = dev_to_iommu_device(dev);
361862306a36Sopenharmony_ci
361962306a36Sopenharmony_ci	return container_of(iommu_dev, struct intel_iommu, iommu);
362062306a36Sopenharmony_ci}
362162306a36Sopenharmony_ci
362262306a36Sopenharmony_cistatic ssize_t version_show(struct device *dev,
362362306a36Sopenharmony_ci			    struct device_attribute *attr, char *buf)
362462306a36Sopenharmony_ci{
362562306a36Sopenharmony_ci	struct intel_iommu *iommu = dev_to_intel_iommu(dev);
362662306a36Sopenharmony_ci	u32 ver = readl(iommu->reg + DMAR_VER_REG);
362762306a36Sopenharmony_ci	return sysfs_emit(buf, "%d:%d\n",
362862306a36Sopenharmony_ci			  DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver));
362962306a36Sopenharmony_ci}
363062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(version);
363162306a36Sopenharmony_ci
363262306a36Sopenharmony_cistatic ssize_t address_show(struct device *dev,
363362306a36Sopenharmony_ci			    struct device_attribute *attr, char *buf)
363462306a36Sopenharmony_ci{
363562306a36Sopenharmony_ci	struct intel_iommu *iommu = dev_to_intel_iommu(dev);
363662306a36Sopenharmony_ci	return sysfs_emit(buf, "%llx\n", iommu->reg_phys);
363762306a36Sopenharmony_ci}
363862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(address);
363962306a36Sopenharmony_ci
364062306a36Sopenharmony_cistatic ssize_t cap_show(struct device *dev,
364162306a36Sopenharmony_ci			struct device_attribute *attr, char *buf)
364262306a36Sopenharmony_ci{
364362306a36Sopenharmony_ci	struct intel_iommu *iommu = dev_to_intel_iommu(dev);
364462306a36Sopenharmony_ci	return sysfs_emit(buf, "%llx\n", iommu->cap);
364562306a36Sopenharmony_ci}
364662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(cap);
364762306a36Sopenharmony_ci
364862306a36Sopenharmony_cistatic ssize_t ecap_show(struct device *dev,
364962306a36Sopenharmony_ci			 struct device_attribute *attr, char *buf)
365062306a36Sopenharmony_ci{
365162306a36Sopenharmony_ci	struct intel_iommu *iommu = dev_to_intel_iommu(dev);
365262306a36Sopenharmony_ci	return sysfs_emit(buf, "%llx\n", iommu->ecap);
365362306a36Sopenharmony_ci}
365462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(ecap);
365562306a36Sopenharmony_ci
365662306a36Sopenharmony_cistatic ssize_t domains_supported_show(struct device *dev,
365762306a36Sopenharmony_ci				      struct device_attribute *attr, char *buf)
365862306a36Sopenharmony_ci{
365962306a36Sopenharmony_ci	struct intel_iommu *iommu = dev_to_intel_iommu(dev);
366062306a36Sopenharmony_ci	return sysfs_emit(buf, "%ld\n", cap_ndoms(iommu->cap));
366162306a36Sopenharmony_ci}
366262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(domains_supported);
366362306a36Sopenharmony_ci
366462306a36Sopenharmony_cistatic ssize_t domains_used_show(struct device *dev,
366562306a36Sopenharmony_ci				 struct device_attribute *attr, char *buf)
366662306a36Sopenharmony_ci{
366762306a36Sopenharmony_ci	struct intel_iommu *iommu = dev_to_intel_iommu(dev);
366862306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n",
366962306a36Sopenharmony_ci			  bitmap_weight(iommu->domain_ids,
367062306a36Sopenharmony_ci					cap_ndoms(iommu->cap)));
367162306a36Sopenharmony_ci}
367262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(domains_used);
367362306a36Sopenharmony_ci
367462306a36Sopenharmony_cistatic struct attribute *intel_iommu_attrs[] = {
367562306a36Sopenharmony_ci	&dev_attr_version.attr,
367662306a36Sopenharmony_ci	&dev_attr_address.attr,
367762306a36Sopenharmony_ci	&dev_attr_cap.attr,
367862306a36Sopenharmony_ci	&dev_attr_ecap.attr,
367962306a36Sopenharmony_ci	&dev_attr_domains_supported.attr,
368062306a36Sopenharmony_ci	&dev_attr_domains_used.attr,
368162306a36Sopenharmony_ci	NULL,
368262306a36Sopenharmony_ci};
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_cistatic struct attribute_group intel_iommu_group = {
368562306a36Sopenharmony_ci	.name = "intel-iommu",
368662306a36Sopenharmony_ci	.attrs = intel_iommu_attrs,
368762306a36Sopenharmony_ci};
368862306a36Sopenharmony_ci
368962306a36Sopenharmony_ciconst struct attribute_group *intel_iommu_groups[] = {
369062306a36Sopenharmony_ci	&intel_iommu_group,
369162306a36Sopenharmony_ci	NULL,
369262306a36Sopenharmony_ci};
369362306a36Sopenharmony_ci
369462306a36Sopenharmony_cistatic inline bool has_external_pci(void)
369562306a36Sopenharmony_ci{
369662306a36Sopenharmony_ci	struct pci_dev *pdev = NULL;
369762306a36Sopenharmony_ci
369862306a36Sopenharmony_ci	for_each_pci_dev(pdev)
369962306a36Sopenharmony_ci		if (pdev->external_facing) {
370062306a36Sopenharmony_ci			pci_dev_put(pdev);
370162306a36Sopenharmony_ci			return true;
370262306a36Sopenharmony_ci		}
370362306a36Sopenharmony_ci
370462306a36Sopenharmony_ci	return false;
370562306a36Sopenharmony_ci}
370662306a36Sopenharmony_ci
370762306a36Sopenharmony_cistatic int __init platform_optin_force_iommu(void)
370862306a36Sopenharmony_ci{
370962306a36Sopenharmony_ci	if (!dmar_platform_optin() || no_platform_optin || !has_external_pci())
371062306a36Sopenharmony_ci		return 0;
371162306a36Sopenharmony_ci
371262306a36Sopenharmony_ci	if (no_iommu || dmar_disabled)
371362306a36Sopenharmony_ci		pr_info("Intel-IOMMU force enabled due to platform opt in\n");
371462306a36Sopenharmony_ci
371562306a36Sopenharmony_ci	/*
371662306a36Sopenharmony_ci	 * If Intel-IOMMU is disabled by default, we will apply identity
371762306a36Sopenharmony_ci	 * map for all devices except those marked as being untrusted.
371862306a36Sopenharmony_ci	 */
371962306a36Sopenharmony_ci	if (dmar_disabled)
372062306a36Sopenharmony_ci		iommu_set_default_passthrough(false);
372162306a36Sopenharmony_ci
372262306a36Sopenharmony_ci	dmar_disabled = 0;
372362306a36Sopenharmony_ci	no_iommu = 0;
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_ci	return 1;
372662306a36Sopenharmony_ci}
372762306a36Sopenharmony_ci
372862306a36Sopenharmony_cistatic int __init probe_acpi_namespace_devices(void)
372962306a36Sopenharmony_ci{
373062306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd;
373162306a36Sopenharmony_ci	/* To avoid a -Wunused-but-set-variable warning. */
373262306a36Sopenharmony_ci	struct intel_iommu *iommu __maybe_unused;
373362306a36Sopenharmony_ci	struct device *dev;
373462306a36Sopenharmony_ci	int i, ret = 0;
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_ci	for_each_active_iommu(iommu, drhd) {
373762306a36Sopenharmony_ci		for_each_active_dev_scope(drhd->devices,
373862306a36Sopenharmony_ci					  drhd->devices_cnt, i, dev) {
373962306a36Sopenharmony_ci			struct acpi_device_physical_node *pn;
374062306a36Sopenharmony_ci			struct acpi_device *adev;
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_ci			if (dev->bus != &acpi_bus_type)
374362306a36Sopenharmony_ci				continue;
374462306a36Sopenharmony_ci
374562306a36Sopenharmony_ci			adev = to_acpi_device(dev);
374662306a36Sopenharmony_ci			mutex_lock(&adev->physical_node_lock);
374762306a36Sopenharmony_ci			list_for_each_entry(pn,
374862306a36Sopenharmony_ci					    &adev->physical_node_list, node) {
374962306a36Sopenharmony_ci				ret = iommu_probe_device(pn->dev);
375062306a36Sopenharmony_ci				if (ret)
375162306a36Sopenharmony_ci					break;
375262306a36Sopenharmony_ci			}
375362306a36Sopenharmony_ci			mutex_unlock(&adev->physical_node_lock);
375462306a36Sopenharmony_ci
375562306a36Sopenharmony_ci			if (ret)
375662306a36Sopenharmony_ci				return ret;
375762306a36Sopenharmony_ci		}
375862306a36Sopenharmony_ci	}
375962306a36Sopenharmony_ci
376062306a36Sopenharmony_ci	return 0;
376162306a36Sopenharmony_ci}
376262306a36Sopenharmony_ci
376362306a36Sopenharmony_cistatic __init int tboot_force_iommu(void)
376462306a36Sopenharmony_ci{
376562306a36Sopenharmony_ci	if (!tboot_enabled())
376662306a36Sopenharmony_ci		return 0;
376762306a36Sopenharmony_ci
376862306a36Sopenharmony_ci	if (no_iommu || dmar_disabled)
376962306a36Sopenharmony_ci		pr_warn("Forcing Intel-IOMMU to enabled\n");
377062306a36Sopenharmony_ci
377162306a36Sopenharmony_ci	dmar_disabled = 0;
377262306a36Sopenharmony_ci	no_iommu = 0;
377362306a36Sopenharmony_ci
377462306a36Sopenharmony_ci	return 1;
377562306a36Sopenharmony_ci}
377662306a36Sopenharmony_ci
377762306a36Sopenharmony_ciint __init intel_iommu_init(void)
377862306a36Sopenharmony_ci{
377962306a36Sopenharmony_ci	int ret = -ENODEV;
378062306a36Sopenharmony_ci	struct dmar_drhd_unit *drhd;
378162306a36Sopenharmony_ci	struct intel_iommu *iommu;
378262306a36Sopenharmony_ci
378362306a36Sopenharmony_ci	/*
378462306a36Sopenharmony_ci	 * Intel IOMMU is required for a TXT/tboot launch or platform
378562306a36Sopenharmony_ci	 * opt in, so enforce that.
378662306a36Sopenharmony_ci	 */
378762306a36Sopenharmony_ci	force_on = (!intel_iommu_tboot_noforce && tboot_force_iommu()) ||
378862306a36Sopenharmony_ci		    platform_optin_force_iommu();
378962306a36Sopenharmony_ci
379062306a36Sopenharmony_ci	down_write(&dmar_global_lock);
379162306a36Sopenharmony_ci	if (dmar_table_init()) {
379262306a36Sopenharmony_ci		if (force_on)
379362306a36Sopenharmony_ci			panic("tboot: Failed to initialize DMAR table\n");
379462306a36Sopenharmony_ci		goto out_free_dmar;
379562306a36Sopenharmony_ci	}
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_ci	if (dmar_dev_scope_init() < 0) {
379862306a36Sopenharmony_ci		if (force_on)
379962306a36Sopenharmony_ci			panic("tboot: Failed to initialize DMAR device scope\n");
380062306a36Sopenharmony_ci		goto out_free_dmar;
380162306a36Sopenharmony_ci	}
380262306a36Sopenharmony_ci
380362306a36Sopenharmony_ci	up_write(&dmar_global_lock);
380462306a36Sopenharmony_ci
380562306a36Sopenharmony_ci	/*
380662306a36Sopenharmony_ci	 * The bus notifier takes the dmar_global_lock, so lockdep will
380762306a36Sopenharmony_ci	 * complain later when we register it under the lock.
380862306a36Sopenharmony_ci	 */
380962306a36Sopenharmony_ci	dmar_register_bus_notifier();
381062306a36Sopenharmony_ci
381162306a36Sopenharmony_ci	down_write(&dmar_global_lock);
381262306a36Sopenharmony_ci
381362306a36Sopenharmony_ci	if (!no_iommu)
381462306a36Sopenharmony_ci		intel_iommu_debugfs_init();
381562306a36Sopenharmony_ci
381662306a36Sopenharmony_ci	if (no_iommu || dmar_disabled) {
381762306a36Sopenharmony_ci		/*
381862306a36Sopenharmony_ci		 * We exit the function here to ensure IOMMU's remapping and
381962306a36Sopenharmony_ci		 * mempool aren't setup, which means that the IOMMU's PMRs
382062306a36Sopenharmony_ci		 * won't be disabled via the call to init_dmars(). So disable
382162306a36Sopenharmony_ci		 * it explicitly here. The PMRs were setup by tboot prior to
382262306a36Sopenharmony_ci		 * calling SENTER, but the kernel is expected to reset/tear
382362306a36Sopenharmony_ci		 * down the PMRs.
382462306a36Sopenharmony_ci		 */
382562306a36Sopenharmony_ci		if (intel_iommu_tboot_noforce) {
382662306a36Sopenharmony_ci			for_each_iommu(iommu, drhd)
382762306a36Sopenharmony_ci				iommu_disable_protect_mem_regions(iommu);
382862306a36Sopenharmony_ci		}
382962306a36Sopenharmony_ci
383062306a36Sopenharmony_ci		/*
383162306a36Sopenharmony_ci		 * Make sure the IOMMUs are switched off, even when we
383262306a36Sopenharmony_ci		 * boot into a kexec kernel and the previous kernel left
383362306a36Sopenharmony_ci		 * them enabled
383462306a36Sopenharmony_ci		 */
383562306a36Sopenharmony_ci		intel_disable_iommus();
383662306a36Sopenharmony_ci		goto out_free_dmar;
383762306a36Sopenharmony_ci	}
383862306a36Sopenharmony_ci
383962306a36Sopenharmony_ci	if (list_empty(&dmar_rmrr_units))
384062306a36Sopenharmony_ci		pr_info("No RMRR found\n");
384162306a36Sopenharmony_ci
384262306a36Sopenharmony_ci	if (list_empty(&dmar_atsr_units))
384362306a36Sopenharmony_ci		pr_info("No ATSR found\n");
384462306a36Sopenharmony_ci
384562306a36Sopenharmony_ci	if (list_empty(&dmar_satc_units))
384662306a36Sopenharmony_ci		pr_info("No SATC found\n");
384762306a36Sopenharmony_ci
384862306a36Sopenharmony_ci	init_no_remapping_devices();
384962306a36Sopenharmony_ci
385062306a36Sopenharmony_ci	ret = init_dmars();
385162306a36Sopenharmony_ci	if (ret) {
385262306a36Sopenharmony_ci		if (force_on)
385362306a36Sopenharmony_ci			panic("tboot: Failed to initialize DMARs\n");
385462306a36Sopenharmony_ci		pr_err("Initialization failed\n");
385562306a36Sopenharmony_ci		goto out_free_dmar;
385662306a36Sopenharmony_ci	}
385762306a36Sopenharmony_ci	up_write(&dmar_global_lock);
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_ci	init_iommu_pm_ops();
386062306a36Sopenharmony_ci
386162306a36Sopenharmony_ci	down_read(&dmar_global_lock);
386262306a36Sopenharmony_ci	for_each_active_iommu(iommu, drhd) {
386362306a36Sopenharmony_ci		/*
386462306a36Sopenharmony_ci		 * The flush queue implementation does not perform
386562306a36Sopenharmony_ci		 * page-selective invalidations that are required for efficient
386662306a36Sopenharmony_ci		 * TLB flushes in virtual environments.  The benefit of batching
386762306a36Sopenharmony_ci		 * is likely to be much lower than the overhead of synchronizing
386862306a36Sopenharmony_ci		 * the virtual and physical IOMMU page-tables.
386962306a36Sopenharmony_ci		 */
387062306a36Sopenharmony_ci		if (cap_caching_mode(iommu->cap) &&
387162306a36Sopenharmony_ci		    !first_level_by_default(IOMMU_DOMAIN_DMA)) {
387262306a36Sopenharmony_ci			pr_info_once("IOMMU batching disallowed due to virtualization\n");
387362306a36Sopenharmony_ci			iommu_set_dma_strict();
387462306a36Sopenharmony_ci		}
387562306a36Sopenharmony_ci		iommu_device_sysfs_add(&iommu->iommu, NULL,
387662306a36Sopenharmony_ci				       intel_iommu_groups,
387762306a36Sopenharmony_ci				       "%s", iommu->name);
387862306a36Sopenharmony_ci		iommu_device_register(&iommu->iommu, &intel_iommu_ops, NULL);
387962306a36Sopenharmony_ci
388062306a36Sopenharmony_ci		iommu_pmu_register(iommu);
388162306a36Sopenharmony_ci	}
388262306a36Sopenharmony_ci	up_read(&dmar_global_lock);
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci	if (si_domain && !hw_pass_through)
388562306a36Sopenharmony_ci		register_memory_notifier(&intel_iommu_memory_nb);
388662306a36Sopenharmony_ci
388762306a36Sopenharmony_ci	down_read(&dmar_global_lock);
388862306a36Sopenharmony_ci	if (probe_acpi_namespace_devices())
388962306a36Sopenharmony_ci		pr_warn("ACPI name space devices didn't probe correctly\n");
389062306a36Sopenharmony_ci
389162306a36Sopenharmony_ci	/* Finally, we enable the DMA remapping hardware. */
389262306a36Sopenharmony_ci	for_each_iommu(iommu, drhd) {
389362306a36Sopenharmony_ci		if (!drhd->ignored && !translation_pre_enabled(iommu))
389462306a36Sopenharmony_ci			iommu_enable_translation(iommu);
389562306a36Sopenharmony_ci
389662306a36Sopenharmony_ci		iommu_disable_protect_mem_regions(iommu);
389762306a36Sopenharmony_ci	}
389862306a36Sopenharmony_ci	up_read(&dmar_global_lock);
389962306a36Sopenharmony_ci
390062306a36Sopenharmony_ci	pr_info("Intel(R) Virtualization Technology for Directed I/O\n");
390162306a36Sopenharmony_ci
390262306a36Sopenharmony_ci	intel_iommu_enabled = 1;
390362306a36Sopenharmony_ci
390462306a36Sopenharmony_ci	return 0;
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ciout_free_dmar:
390762306a36Sopenharmony_ci	intel_iommu_free_dmars();
390862306a36Sopenharmony_ci	up_write(&dmar_global_lock);
390962306a36Sopenharmony_ci	return ret;
391062306a36Sopenharmony_ci}
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_cistatic int domain_context_clear_one_cb(struct pci_dev *pdev, u16 alias, void *opaque)
391362306a36Sopenharmony_ci{
391462306a36Sopenharmony_ci	struct device_domain_info *info = opaque;
391562306a36Sopenharmony_ci
391662306a36Sopenharmony_ci	domain_context_clear_one(info, PCI_BUS_NUM(alias), alias & 0xff);
391762306a36Sopenharmony_ci	return 0;
391862306a36Sopenharmony_ci}
391962306a36Sopenharmony_ci
392062306a36Sopenharmony_ci/*
392162306a36Sopenharmony_ci * NB - intel-iommu lacks any sort of reference counting for the users of
392262306a36Sopenharmony_ci * dependent devices.  If multiple endpoints have intersecting dependent
392362306a36Sopenharmony_ci * devices, unbinding the driver from any one of them will possibly leave
392462306a36Sopenharmony_ci * the others unable to operate.
392562306a36Sopenharmony_ci */
392662306a36Sopenharmony_cistatic void domain_context_clear(struct device_domain_info *info)
392762306a36Sopenharmony_ci{
392862306a36Sopenharmony_ci	if (!dev_is_pci(info->dev))
392962306a36Sopenharmony_ci		domain_context_clear_one(info, info->bus, info->devfn);
393062306a36Sopenharmony_ci
393162306a36Sopenharmony_ci	pci_for_each_dma_alias(to_pci_dev(info->dev),
393262306a36Sopenharmony_ci			       &domain_context_clear_one_cb, info);
393362306a36Sopenharmony_ci}
393462306a36Sopenharmony_ci
393562306a36Sopenharmony_cistatic void dmar_remove_one_dev_info(struct device *dev)
393662306a36Sopenharmony_ci{
393762306a36Sopenharmony_ci	struct device_domain_info *info = dev_iommu_priv_get(dev);
393862306a36Sopenharmony_ci	struct dmar_domain *domain = info->domain;
393962306a36Sopenharmony_ci	struct intel_iommu *iommu = info->iommu;
394062306a36Sopenharmony_ci	unsigned long flags;
394162306a36Sopenharmony_ci
394262306a36Sopenharmony_ci	if (!dev_is_real_dma_subdevice(info->dev)) {
394362306a36Sopenharmony_ci		if (dev_is_pci(info->dev) && sm_supported(iommu))
394462306a36Sopenharmony_ci			intel_pasid_tear_down_entry(iommu, info->dev,
394562306a36Sopenharmony_ci					IOMMU_NO_PASID, false);
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci		iommu_disable_pci_caps(info);
394862306a36Sopenharmony_ci		domain_context_clear(info);
394962306a36Sopenharmony_ci	}
395062306a36Sopenharmony_ci
395162306a36Sopenharmony_ci	spin_lock_irqsave(&domain->lock, flags);
395262306a36Sopenharmony_ci	list_del(&info->link);
395362306a36Sopenharmony_ci	spin_unlock_irqrestore(&domain->lock, flags);
395462306a36Sopenharmony_ci
395562306a36Sopenharmony_ci	domain_detach_iommu(domain, iommu);
395662306a36Sopenharmony_ci	info->domain = NULL;
395762306a36Sopenharmony_ci}
395862306a36Sopenharmony_ci
395962306a36Sopenharmony_ci/*
396062306a36Sopenharmony_ci * Clear the page table pointer in context or pasid table entries so that
396162306a36Sopenharmony_ci * all DMA requests without PASID from the device are blocked. If the page
396262306a36Sopenharmony_ci * table has been set, clean up the data structures.
396362306a36Sopenharmony_ci */
396462306a36Sopenharmony_cistatic void device_block_translation(struct device *dev)
396562306a36Sopenharmony_ci{
396662306a36Sopenharmony_ci	struct device_domain_info *info = dev_iommu_priv_get(dev);
396762306a36Sopenharmony_ci	struct intel_iommu *iommu = info->iommu;
396862306a36Sopenharmony_ci	unsigned long flags;
396962306a36Sopenharmony_ci
397062306a36Sopenharmony_ci	iommu_disable_pci_caps(info);
397162306a36Sopenharmony_ci	if (!dev_is_real_dma_subdevice(dev)) {
397262306a36Sopenharmony_ci		if (sm_supported(iommu))
397362306a36Sopenharmony_ci			intel_pasid_tear_down_entry(iommu, dev,
397462306a36Sopenharmony_ci						    IOMMU_NO_PASID, false);
397562306a36Sopenharmony_ci		else
397662306a36Sopenharmony_ci			domain_context_clear(info);
397762306a36Sopenharmony_ci	}
397862306a36Sopenharmony_ci
397962306a36Sopenharmony_ci	if (!info->domain)
398062306a36Sopenharmony_ci		return;
398162306a36Sopenharmony_ci
398262306a36Sopenharmony_ci	spin_lock_irqsave(&info->domain->lock, flags);
398362306a36Sopenharmony_ci	list_del(&info->link);
398462306a36Sopenharmony_ci	spin_unlock_irqrestore(&info->domain->lock, flags);
398562306a36Sopenharmony_ci
398662306a36Sopenharmony_ci	domain_detach_iommu(info->domain, iommu);
398762306a36Sopenharmony_ci	info->domain = NULL;
398862306a36Sopenharmony_ci}
398962306a36Sopenharmony_ci
399062306a36Sopenharmony_cistatic int md_domain_init(struct dmar_domain *domain, int guest_width)
399162306a36Sopenharmony_ci{
399262306a36Sopenharmony_ci	int adjust_width;
399362306a36Sopenharmony_ci
399462306a36Sopenharmony_ci	/* calculate AGAW */
399562306a36Sopenharmony_ci	domain->gaw = guest_width;
399662306a36Sopenharmony_ci	adjust_width = guestwidth_to_adjustwidth(guest_width);
399762306a36Sopenharmony_ci	domain->agaw = width_to_agaw(adjust_width);
399862306a36Sopenharmony_ci
399962306a36Sopenharmony_ci	domain->iommu_coherency = false;
400062306a36Sopenharmony_ci	domain->iommu_superpage = 0;
400162306a36Sopenharmony_ci	domain->max_addr = 0;
400262306a36Sopenharmony_ci
400362306a36Sopenharmony_ci	/* always allocate the top pgd */
400462306a36Sopenharmony_ci	domain->pgd = alloc_pgtable_page(domain->nid, GFP_ATOMIC);
400562306a36Sopenharmony_ci	if (!domain->pgd)
400662306a36Sopenharmony_ci		return -ENOMEM;
400762306a36Sopenharmony_ci	domain_flush_cache(domain, domain->pgd, PAGE_SIZE);
400862306a36Sopenharmony_ci	return 0;
400962306a36Sopenharmony_ci}
401062306a36Sopenharmony_ci
401162306a36Sopenharmony_cistatic int blocking_domain_attach_dev(struct iommu_domain *domain,
401262306a36Sopenharmony_ci				      struct device *dev)
401362306a36Sopenharmony_ci{
401462306a36Sopenharmony_ci	device_block_translation(dev);
401562306a36Sopenharmony_ci	return 0;
401662306a36Sopenharmony_ci}
401762306a36Sopenharmony_ci
401862306a36Sopenharmony_cistatic struct iommu_domain blocking_domain = {
401962306a36Sopenharmony_ci	.ops = &(const struct iommu_domain_ops) {
402062306a36Sopenharmony_ci		.attach_dev	= blocking_domain_attach_dev,
402162306a36Sopenharmony_ci		.free		= intel_iommu_domain_free
402262306a36Sopenharmony_ci	}
402362306a36Sopenharmony_ci};
402462306a36Sopenharmony_ci
402562306a36Sopenharmony_cistatic struct iommu_domain *intel_iommu_domain_alloc(unsigned type)
402662306a36Sopenharmony_ci{
402762306a36Sopenharmony_ci	struct dmar_domain *dmar_domain;
402862306a36Sopenharmony_ci	struct iommu_domain *domain;
402962306a36Sopenharmony_ci
403062306a36Sopenharmony_ci	switch (type) {
403162306a36Sopenharmony_ci	case IOMMU_DOMAIN_BLOCKED:
403262306a36Sopenharmony_ci		return &blocking_domain;
403362306a36Sopenharmony_ci	case IOMMU_DOMAIN_DMA:
403462306a36Sopenharmony_ci	case IOMMU_DOMAIN_UNMANAGED:
403562306a36Sopenharmony_ci		dmar_domain = alloc_domain(type);
403662306a36Sopenharmony_ci		if (!dmar_domain) {
403762306a36Sopenharmony_ci			pr_err("Can't allocate dmar_domain\n");
403862306a36Sopenharmony_ci			return NULL;
403962306a36Sopenharmony_ci		}
404062306a36Sopenharmony_ci		if (md_domain_init(dmar_domain, DEFAULT_DOMAIN_ADDRESS_WIDTH)) {
404162306a36Sopenharmony_ci			pr_err("Domain initialization failed\n");
404262306a36Sopenharmony_ci			domain_exit(dmar_domain);
404362306a36Sopenharmony_ci			return NULL;
404462306a36Sopenharmony_ci		}
404562306a36Sopenharmony_ci
404662306a36Sopenharmony_ci		domain = &dmar_domain->domain;
404762306a36Sopenharmony_ci		domain->geometry.aperture_start = 0;
404862306a36Sopenharmony_ci		domain->geometry.aperture_end   =
404962306a36Sopenharmony_ci				__DOMAIN_MAX_ADDR(dmar_domain->gaw);
405062306a36Sopenharmony_ci		domain->geometry.force_aperture = true;
405162306a36Sopenharmony_ci
405262306a36Sopenharmony_ci		return domain;
405362306a36Sopenharmony_ci	case IOMMU_DOMAIN_IDENTITY:
405462306a36Sopenharmony_ci		return &si_domain->domain;
405562306a36Sopenharmony_ci	case IOMMU_DOMAIN_SVA:
405662306a36Sopenharmony_ci		return intel_svm_domain_alloc();
405762306a36Sopenharmony_ci	default:
405862306a36Sopenharmony_ci		return NULL;
405962306a36Sopenharmony_ci	}
406062306a36Sopenharmony_ci
406162306a36Sopenharmony_ci	return NULL;
406262306a36Sopenharmony_ci}
406362306a36Sopenharmony_ci
406462306a36Sopenharmony_cistatic void intel_iommu_domain_free(struct iommu_domain *domain)
406562306a36Sopenharmony_ci{
406662306a36Sopenharmony_ci	if (domain != &si_domain->domain && domain != &blocking_domain)
406762306a36Sopenharmony_ci		domain_exit(to_dmar_domain(domain));
406862306a36Sopenharmony_ci}
406962306a36Sopenharmony_ci
407062306a36Sopenharmony_cistatic int prepare_domain_attach_device(struct iommu_domain *domain,
407162306a36Sopenharmony_ci					struct device *dev)
407262306a36Sopenharmony_ci{
407362306a36Sopenharmony_ci	struct dmar_domain *dmar_domain = to_dmar_domain(domain);
407462306a36Sopenharmony_ci	struct intel_iommu *iommu;
407562306a36Sopenharmony_ci	int addr_width;
407662306a36Sopenharmony_ci
407762306a36Sopenharmony_ci	iommu = device_to_iommu(dev, NULL, NULL);
407862306a36Sopenharmony_ci	if (!iommu)
407962306a36Sopenharmony_ci		return -ENODEV;
408062306a36Sopenharmony_ci
408162306a36Sopenharmony_ci	if (dmar_domain->force_snooping && !ecap_sc_support(iommu->ecap))
408262306a36Sopenharmony_ci		return -EINVAL;
408362306a36Sopenharmony_ci
408462306a36Sopenharmony_ci	/* check if this iommu agaw is sufficient for max mapped address */
408562306a36Sopenharmony_ci	addr_width = agaw_to_width(iommu->agaw);
408662306a36Sopenharmony_ci	if (addr_width > cap_mgaw(iommu->cap))
408762306a36Sopenharmony_ci		addr_width = cap_mgaw(iommu->cap);
408862306a36Sopenharmony_ci
408962306a36Sopenharmony_ci	if (dmar_domain->max_addr > (1LL << addr_width))
409062306a36Sopenharmony_ci		return -EINVAL;
409162306a36Sopenharmony_ci	dmar_domain->gaw = addr_width;
409262306a36Sopenharmony_ci
409362306a36Sopenharmony_ci	/*
409462306a36Sopenharmony_ci	 * Knock out extra levels of page tables if necessary
409562306a36Sopenharmony_ci	 */
409662306a36Sopenharmony_ci	while (iommu->agaw < dmar_domain->agaw) {
409762306a36Sopenharmony_ci		struct dma_pte *pte;
409862306a36Sopenharmony_ci
409962306a36Sopenharmony_ci		pte = dmar_domain->pgd;
410062306a36Sopenharmony_ci		if (dma_pte_present(pte)) {
410162306a36Sopenharmony_ci			dmar_domain->pgd = phys_to_virt(dma_pte_addr(pte));
410262306a36Sopenharmony_ci			free_pgtable_page(pte);
410362306a36Sopenharmony_ci		}
410462306a36Sopenharmony_ci		dmar_domain->agaw--;
410562306a36Sopenharmony_ci	}
410662306a36Sopenharmony_ci
410762306a36Sopenharmony_ci	return 0;
410862306a36Sopenharmony_ci}
410962306a36Sopenharmony_ci
411062306a36Sopenharmony_cistatic int intel_iommu_attach_device(struct iommu_domain *domain,
411162306a36Sopenharmony_ci				     struct device *dev)
411262306a36Sopenharmony_ci{
411362306a36Sopenharmony_ci	struct device_domain_info *info = dev_iommu_priv_get(dev);
411462306a36Sopenharmony_ci	int ret;
411562306a36Sopenharmony_ci
411662306a36Sopenharmony_ci	if (info->domain)
411762306a36Sopenharmony_ci		device_block_translation(dev);
411862306a36Sopenharmony_ci
411962306a36Sopenharmony_ci	ret = prepare_domain_attach_device(domain, dev);
412062306a36Sopenharmony_ci	if (ret)
412162306a36Sopenharmony_ci		return ret;
412262306a36Sopenharmony_ci
412362306a36Sopenharmony_ci	return dmar_domain_attach_device(to_dmar_domain(domain), dev);
412462306a36Sopenharmony_ci}
412562306a36Sopenharmony_ci
412662306a36Sopenharmony_cistatic int intel_iommu_map(struct iommu_domain *domain,
412762306a36Sopenharmony_ci			   unsigned long iova, phys_addr_t hpa,
412862306a36Sopenharmony_ci			   size_t size, int iommu_prot, gfp_t gfp)
412962306a36Sopenharmony_ci{
413062306a36Sopenharmony_ci	struct dmar_domain *dmar_domain = to_dmar_domain(domain);
413162306a36Sopenharmony_ci	u64 max_addr;
413262306a36Sopenharmony_ci	int prot = 0;
413362306a36Sopenharmony_ci
413462306a36Sopenharmony_ci	if (iommu_prot & IOMMU_READ)
413562306a36Sopenharmony_ci		prot |= DMA_PTE_READ;
413662306a36Sopenharmony_ci	if (iommu_prot & IOMMU_WRITE)
413762306a36Sopenharmony_ci		prot |= DMA_PTE_WRITE;
413862306a36Sopenharmony_ci	if (dmar_domain->set_pte_snp)
413962306a36Sopenharmony_ci		prot |= DMA_PTE_SNP;
414062306a36Sopenharmony_ci
414162306a36Sopenharmony_ci	max_addr = iova + size;
414262306a36Sopenharmony_ci	if (dmar_domain->max_addr < max_addr) {
414362306a36Sopenharmony_ci		u64 end;
414462306a36Sopenharmony_ci
414562306a36Sopenharmony_ci		/* check if minimum agaw is sufficient for mapped address */
414662306a36Sopenharmony_ci		end = __DOMAIN_MAX_ADDR(dmar_domain->gaw) + 1;
414762306a36Sopenharmony_ci		if (end < max_addr) {
414862306a36Sopenharmony_ci			pr_err("%s: iommu width (%d) is not "
414962306a36Sopenharmony_ci			       "sufficient for the mapped address (%llx)\n",
415062306a36Sopenharmony_ci			       __func__, dmar_domain->gaw, max_addr);
415162306a36Sopenharmony_ci			return -EFAULT;
415262306a36Sopenharmony_ci		}
415362306a36Sopenharmony_ci		dmar_domain->max_addr = max_addr;
415462306a36Sopenharmony_ci	}
415562306a36Sopenharmony_ci	/* Round up size to next multiple of PAGE_SIZE, if it and
415662306a36Sopenharmony_ci	   the low bits of hpa would take us onto the next page */
415762306a36Sopenharmony_ci	size = aligned_nrpages(hpa, size);
415862306a36Sopenharmony_ci	return __domain_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
415962306a36Sopenharmony_ci				hpa >> VTD_PAGE_SHIFT, size, prot, gfp);
416062306a36Sopenharmony_ci}
416162306a36Sopenharmony_ci
416262306a36Sopenharmony_cistatic int intel_iommu_map_pages(struct iommu_domain *domain,
416362306a36Sopenharmony_ci				 unsigned long iova, phys_addr_t paddr,
416462306a36Sopenharmony_ci				 size_t pgsize, size_t pgcount,
416562306a36Sopenharmony_ci				 int prot, gfp_t gfp, size_t *mapped)
416662306a36Sopenharmony_ci{
416762306a36Sopenharmony_ci	unsigned long pgshift = __ffs(pgsize);
416862306a36Sopenharmony_ci	size_t size = pgcount << pgshift;
416962306a36Sopenharmony_ci	int ret;
417062306a36Sopenharmony_ci
417162306a36Sopenharmony_ci	if (pgsize != SZ_4K && pgsize != SZ_2M && pgsize != SZ_1G)
417262306a36Sopenharmony_ci		return -EINVAL;
417362306a36Sopenharmony_ci
417462306a36Sopenharmony_ci	if (!IS_ALIGNED(iova | paddr, pgsize))
417562306a36Sopenharmony_ci		return -EINVAL;
417662306a36Sopenharmony_ci
417762306a36Sopenharmony_ci	ret = intel_iommu_map(domain, iova, paddr, size, prot, gfp);
417862306a36Sopenharmony_ci	if (!ret && mapped)
417962306a36Sopenharmony_ci		*mapped = size;
418062306a36Sopenharmony_ci
418162306a36Sopenharmony_ci	return ret;
418262306a36Sopenharmony_ci}
418362306a36Sopenharmony_ci
418462306a36Sopenharmony_cistatic size_t intel_iommu_unmap(struct iommu_domain *domain,
418562306a36Sopenharmony_ci				unsigned long iova, size_t size,
418662306a36Sopenharmony_ci				struct iommu_iotlb_gather *gather)
418762306a36Sopenharmony_ci{
418862306a36Sopenharmony_ci	struct dmar_domain *dmar_domain = to_dmar_domain(domain);
418962306a36Sopenharmony_ci	unsigned long start_pfn, last_pfn;
419062306a36Sopenharmony_ci	int level = 0;
419162306a36Sopenharmony_ci
419262306a36Sopenharmony_ci	/* Cope with horrid API which requires us to unmap more than the
419362306a36Sopenharmony_ci	   size argument if it happens to be a large-page mapping. */
419462306a36Sopenharmony_ci	if (unlikely(!pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT,
419562306a36Sopenharmony_ci				     &level, GFP_ATOMIC)))
419662306a36Sopenharmony_ci		return 0;
419762306a36Sopenharmony_ci
419862306a36Sopenharmony_ci	if (size < VTD_PAGE_SIZE << level_to_offset_bits(level))
419962306a36Sopenharmony_ci		size = VTD_PAGE_SIZE << level_to_offset_bits(level);
420062306a36Sopenharmony_ci
420162306a36Sopenharmony_ci	start_pfn = iova >> VTD_PAGE_SHIFT;
420262306a36Sopenharmony_ci	last_pfn = (iova + size - 1) >> VTD_PAGE_SHIFT;
420362306a36Sopenharmony_ci
420462306a36Sopenharmony_ci	domain_unmap(dmar_domain, start_pfn, last_pfn, &gather->freelist);
420562306a36Sopenharmony_ci
420662306a36Sopenharmony_ci	if (dmar_domain->max_addr == iova + size)
420762306a36Sopenharmony_ci		dmar_domain->max_addr = iova;
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci	/*
421062306a36Sopenharmony_ci	 * We do not use page-selective IOTLB invalidation in flush queue,
421162306a36Sopenharmony_ci	 * so there is no need to track page and sync iotlb.
421262306a36Sopenharmony_ci	 */
421362306a36Sopenharmony_ci	if (!iommu_iotlb_gather_queued(gather))
421462306a36Sopenharmony_ci		iommu_iotlb_gather_add_page(domain, gather, iova, size);
421562306a36Sopenharmony_ci
421662306a36Sopenharmony_ci	return size;
421762306a36Sopenharmony_ci}
421862306a36Sopenharmony_ci
421962306a36Sopenharmony_cistatic size_t intel_iommu_unmap_pages(struct iommu_domain *domain,
422062306a36Sopenharmony_ci				      unsigned long iova,
422162306a36Sopenharmony_ci				      size_t pgsize, size_t pgcount,
422262306a36Sopenharmony_ci				      struct iommu_iotlb_gather *gather)
422362306a36Sopenharmony_ci{
422462306a36Sopenharmony_ci	unsigned long pgshift = __ffs(pgsize);
422562306a36Sopenharmony_ci	size_t size = pgcount << pgshift;
422662306a36Sopenharmony_ci
422762306a36Sopenharmony_ci	return intel_iommu_unmap(domain, iova, size, gather);
422862306a36Sopenharmony_ci}
422962306a36Sopenharmony_ci
423062306a36Sopenharmony_cistatic void intel_iommu_tlb_sync(struct iommu_domain *domain,
423162306a36Sopenharmony_ci				 struct iommu_iotlb_gather *gather)
423262306a36Sopenharmony_ci{
423362306a36Sopenharmony_ci	struct dmar_domain *dmar_domain = to_dmar_domain(domain);
423462306a36Sopenharmony_ci	unsigned long iova_pfn = IOVA_PFN(gather->start);
423562306a36Sopenharmony_ci	size_t size = gather->end - gather->start;
423662306a36Sopenharmony_ci	struct iommu_domain_info *info;
423762306a36Sopenharmony_ci	unsigned long start_pfn;
423862306a36Sopenharmony_ci	unsigned long nrpages;
423962306a36Sopenharmony_ci	unsigned long i;
424062306a36Sopenharmony_ci
424162306a36Sopenharmony_ci	nrpages = aligned_nrpages(gather->start, size);
424262306a36Sopenharmony_ci	start_pfn = mm_to_dma_pfn_start(iova_pfn);
424362306a36Sopenharmony_ci
424462306a36Sopenharmony_ci	xa_for_each(&dmar_domain->iommu_array, i, info)
424562306a36Sopenharmony_ci		iommu_flush_iotlb_psi(info->iommu, dmar_domain,
424662306a36Sopenharmony_ci				      start_pfn, nrpages,
424762306a36Sopenharmony_ci				      list_empty(&gather->freelist), 0);
424862306a36Sopenharmony_ci
424962306a36Sopenharmony_ci	put_pages_list(&gather->freelist);
425062306a36Sopenharmony_ci}
425162306a36Sopenharmony_ci
425262306a36Sopenharmony_cistatic phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
425362306a36Sopenharmony_ci					    dma_addr_t iova)
425462306a36Sopenharmony_ci{
425562306a36Sopenharmony_ci	struct dmar_domain *dmar_domain = to_dmar_domain(domain);
425662306a36Sopenharmony_ci	struct dma_pte *pte;
425762306a36Sopenharmony_ci	int level = 0;
425862306a36Sopenharmony_ci	u64 phys = 0;
425962306a36Sopenharmony_ci
426062306a36Sopenharmony_ci	pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level,
426162306a36Sopenharmony_ci			     GFP_ATOMIC);
426262306a36Sopenharmony_ci	if (pte && dma_pte_present(pte))
426362306a36Sopenharmony_ci		phys = dma_pte_addr(pte) +
426462306a36Sopenharmony_ci			(iova & (BIT_MASK(level_to_offset_bits(level) +
426562306a36Sopenharmony_ci						VTD_PAGE_SHIFT) - 1));
426662306a36Sopenharmony_ci
426762306a36Sopenharmony_ci	return phys;
426862306a36Sopenharmony_ci}
426962306a36Sopenharmony_ci
427062306a36Sopenharmony_cistatic bool domain_support_force_snooping(struct dmar_domain *domain)
427162306a36Sopenharmony_ci{
427262306a36Sopenharmony_ci	struct device_domain_info *info;
427362306a36Sopenharmony_ci	bool support = true;
427462306a36Sopenharmony_ci
427562306a36Sopenharmony_ci	assert_spin_locked(&domain->lock);
427662306a36Sopenharmony_ci	list_for_each_entry(info, &domain->devices, link) {
427762306a36Sopenharmony_ci		if (!ecap_sc_support(info->iommu->ecap)) {
427862306a36Sopenharmony_ci			support = false;
427962306a36Sopenharmony_ci			break;
428062306a36Sopenharmony_ci		}
428162306a36Sopenharmony_ci	}
428262306a36Sopenharmony_ci
428362306a36Sopenharmony_ci	return support;
428462306a36Sopenharmony_ci}
428562306a36Sopenharmony_ci
428662306a36Sopenharmony_cistatic void domain_set_force_snooping(struct dmar_domain *domain)
428762306a36Sopenharmony_ci{
428862306a36Sopenharmony_ci	struct device_domain_info *info;
428962306a36Sopenharmony_ci
429062306a36Sopenharmony_ci	assert_spin_locked(&domain->lock);
429162306a36Sopenharmony_ci	/*
429262306a36Sopenharmony_ci	 * Second level page table supports per-PTE snoop control. The
429362306a36Sopenharmony_ci	 * iommu_map() interface will handle this by setting SNP bit.
429462306a36Sopenharmony_ci	 */
429562306a36Sopenharmony_ci	if (!domain->use_first_level) {
429662306a36Sopenharmony_ci		domain->set_pte_snp = true;
429762306a36Sopenharmony_ci		return;
429862306a36Sopenharmony_ci	}
429962306a36Sopenharmony_ci
430062306a36Sopenharmony_ci	list_for_each_entry(info, &domain->devices, link)
430162306a36Sopenharmony_ci		intel_pasid_setup_page_snoop_control(info->iommu, info->dev,
430262306a36Sopenharmony_ci						     IOMMU_NO_PASID);
430362306a36Sopenharmony_ci}
430462306a36Sopenharmony_ci
430562306a36Sopenharmony_cistatic bool intel_iommu_enforce_cache_coherency(struct iommu_domain *domain)
430662306a36Sopenharmony_ci{
430762306a36Sopenharmony_ci	struct dmar_domain *dmar_domain = to_dmar_domain(domain);
430862306a36Sopenharmony_ci	unsigned long flags;
430962306a36Sopenharmony_ci
431062306a36Sopenharmony_ci	if (dmar_domain->force_snooping)
431162306a36Sopenharmony_ci		return true;
431262306a36Sopenharmony_ci
431362306a36Sopenharmony_ci	spin_lock_irqsave(&dmar_domain->lock, flags);
431462306a36Sopenharmony_ci	if (!domain_support_force_snooping(dmar_domain) ||
431562306a36Sopenharmony_ci	    (!dmar_domain->use_first_level && dmar_domain->has_mappings)) {
431662306a36Sopenharmony_ci		spin_unlock_irqrestore(&dmar_domain->lock, flags);
431762306a36Sopenharmony_ci		return false;
431862306a36Sopenharmony_ci	}
431962306a36Sopenharmony_ci
432062306a36Sopenharmony_ci	domain_set_force_snooping(dmar_domain);
432162306a36Sopenharmony_ci	dmar_domain->force_snooping = true;
432262306a36Sopenharmony_ci	spin_unlock_irqrestore(&dmar_domain->lock, flags);
432362306a36Sopenharmony_ci
432462306a36Sopenharmony_ci	return true;
432562306a36Sopenharmony_ci}
432662306a36Sopenharmony_ci
432762306a36Sopenharmony_cistatic bool intel_iommu_capable(struct device *dev, enum iommu_cap cap)
432862306a36Sopenharmony_ci{
432962306a36Sopenharmony_ci	struct device_domain_info *info = dev_iommu_priv_get(dev);
433062306a36Sopenharmony_ci
433162306a36Sopenharmony_ci	switch (cap) {
433262306a36Sopenharmony_ci	case IOMMU_CAP_CACHE_COHERENCY:
433362306a36Sopenharmony_ci	case IOMMU_CAP_DEFERRED_FLUSH:
433462306a36Sopenharmony_ci		return true;
433562306a36Sopenharmony_ci	case IOMMU_CAP_PRE_BOOT_PROTECTION:
433662306a36Sopenharmony_ci		return dmar_platform_optin();
433762306a36Sopenharmony_ci	case IOMMU_CAP_ENFORCE_CACHE_COHERENCY:
433862306a36Sopenharmony_ci		return ecap_sc_support(info->iommu->ecap);
433962306a36Sopenharmony_ci	default:
434062306a36Sopenharmony_ci		return false;
434162306a36Sopenharmony_ci	}
434262306a36Sopenharmony_ci}
434362306a36Sopenharmony_ci
434462306a36Sopenharmony_cistatic struct iommu_device *intel_iommu_probe_device(struct device *dev)
434562306a36Sopenharmony_ci{
434662306a36Sopenharmony_ci	struct pci_dev *pdev = dev_is_pci(dev) ? to_pci_dev(dev) : NULL;
434762306a36Sopenharmony_ci	struct device_domain_info *info;
434862306a36Sopenharmony_ci	struct intel_iommu *iommu;
434962306a36Sopenharmony_ci	u8 bus, devfn;
435062306a36Sopenharmony_ci	int ret;
435162306a36Sopenharmony_ci
435262306a36Sopenharmony_ci	iommu = device_to_iommu(dev, &bus, &devfn);
435362306a36Sopenharmony_ci	if (!iommu || !iommu->iommu.ops)
435462306a36Sopenharmony_ci		return ERR_PTR(-ENODEV);
435562306a36Sopenharmony_ci
435662306a36Sopenharmony_ci	info = kzalloc(sizeof(*info), GFP_KERNEL);
435762306a36Sopenharmony_ci	if (!info)
435862306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
435962306a36Sopenharmony_ci
436062306a36Sopenharmony_ci	if (dev_is_real_dma_subdevice(dev)) {
436162306a36Sopenharmony_ci		info->bus = pdev->bus->number;
436262306a36Sopenharmony_ci		info->devfn = pdev->devfn;
436362306a36Sopenharmony_ci		info->segment = pci_domain_nr(pdev->bus);
436462306a36Sopenharmony_ci	} else {
436562306a36Sopenharmony_ci		info->bus = bus;
436662306a36Sopenharmony_ci		info->devfn = devfn;
436762306a36Sopenharmony_ci		info->segment = iommu->segment;
436862306a36Sopenharmony_ci	}
436962306a36Sopenharmony_ci
437062306a36Sopenharmony_ci	info->dev = dev;
437162306a36Sopenharmony_ci	info->iommu = iommu;
437262306a36Sopenharmony_ci	if (dev_is_pci(dev)) {
437362306a36Sopenharmony_ci		if (ecap_dev_iotlb_support(iommu->ecap) &&
437462306a36Sopenharmony_ci		    pci_ats_supported(pdev) &&
437562306a36Sopenharmony_ci		    dmar_ats_supported(pdev, iommu)) {
437662306a36Sopenharmony_ci			info->ats_supported = 1;
437762306a36Sopenharmony_ci			info->dtlb_extra_inval = dev_needs_extra_dtlb_flush(pdev);
437862306a36Sopenharmony_ci
437962306a36Sopenharmony_ci			/*
438062306a36Sopenharmony_ci			 * For IOMMU that supports device IOTLB throttling
438162306a36Sopenharmony_ci			 * (DIT), we assign PFSID to the invalidation desc
438262306a36Sopenharmony_ci			 * of a VF such that IOMMU HW can gauge queue depth
438362306a36Sopenharmony_ci			 * at PF level. If DIT is not set, PFSID will be
438462306a36Sopenharmony_ci			 * treated as reserved, which should be set to 0.
438562306a36Sopenharmony_ci			 */
438662306a36Sopenharmony_ci			if (ecap_dit(iommu->ecap))
438762306a36Sopenharmony_ci				info->pfsid = pci_dev_id(pci_physfn(pdev));
438862306a36Sopenharmony_ci			info->ats_qdep = pci_ats_queue_depth(pdev);
438962306a36Sopenharmony_ci		}
439062306a36Sopenharmony_ci		if (sm_supported(iommu)) {
439162306a36Sopenharmony_ci			if (pasid_supported(iommu)) {
439262306a36Sopenharmony_ci				int features = pci_pasid_features(pdev);
439362306a36Sopenharmony_ci
439462306a36Sopenharmony_ci				if (features >= 0)
439562306a36Sopenharmony_ci					info->pasid_supported = features | 1;
439662306a36Sopenharmony_ci			}
439762306a36Sopenharmony_ci
439862306a36Sopenharmony_ci			if (info->ats_supported && ecap_prs(iommu->ecap) &&
439962306a36Sopenharmony_ci			    pci_pri_supported(pdev))
440062306a36Sopenharmony_ci				info->pri_supported = 1;
440162306a36Sopenharmony_ci		}
440262306a36Sopenharmony_ci	}
440362306a36Sopenharmony_ci
440462306a36Sopenharmony_ci	dev_iommu_priv_set(dev, info);
440562306a36Sopenharmony_ci
440662306a36Sopenharmony_ci	if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) {
440762306a36Sopenharmony_ci		ret = intel_pasid_alloc_table(dev);
440862306a36Sopenharmony_ci		if (ret) {
440962306a36Sopenharmony_ci			dev_err(dev, "PASID table allocation failed\n");
441062306a36Sopenharmony_ci			dev_iommu_priv_set(dev, NULL);
441162306a36Sopenharmony_ci			kfree(info);
441262306a36Sopenharmony_ci			return ERR_PTR(ret);
441362306a36Sopenharmony_ci		}
441462306a36Sopenharmony_ci	}
441562306a36Sopenharmony_ci
441662306a36Sopenharmony_ci	return &iommu->iommu;
441762306a36Sopenharmony_ci}
441862306a36Sopenharmony_ci
441962306a36Sopenharmony_cistatic void intel_iommu_release_device(struct device *dev)
442062306a36Sopenharmony_ci{
442162306a36Sopenharmony_ci	struct device_domain_info *info = dev_iommu_priv_get(dev);
442262306a36Sopenharmony_ci
442362306a36Sopenharmony_ci	dmar_remove_one_dev_info(dev);
442462306a36Sopenharmony_ci	intel_pasid_free_table(dev);
442562306a36Sopenharmony_ci	dev_iommu_priv_set(dev, NULL);
442662306a36Sopenharmony_ci	kfree(info);
442762306a36Sopenharmony_ci	set_dma_ops(dev, NULL);
442862306a36Sopenharmony_ci}
442962306a36Sopenharmony_ci
443062306a36Sopenharmony_cistatic void intel_iommu_probe_finalize(struct device *dev)
443162306a36Sopenharmony_ci{
443262306a36Sopenharmony_ci	set_dma_ops(dev, NULL);
443362306a36Sopenharmony_ci	iommu_setup_dma_ops(dev, 0, U64_MAX);
443462306a36Sopenharmony_ci}
443562306a36Sopenharmony_ci
443662306a36Sopenharmony_cistatic void intel_iommu_get_resv_regions(struct device *device,
443762306a36Sopenharmony_ci					 struct list_head *head)
443862306a36Sopenharmony_ci{
443962306a36Sopenharmony_ci	int prot = DMA_PTE_READ | DMA_PTE_WRITE;
444062306a36Sopenharmony_ci	struct iommu_resv_region *reg;
444162306a36Sopenharmony_ci	struct dmar_rmrr_unit *rmrr;
444262306a36Sopenharmony_ci	struct device *i_dev;
444362306a36Sopenharmony_ci	int i;
444462306a36Sopenharmony_ci
444562306a36Sopenharmony_ci	rcu_read_lock();
444662306a36Sopenharmony_ci	for_each_rmrr_units(rmrr) {
444762306a36Sopenharmony_ci		for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt,
444862306a36Sopenharmony_ci					  i, i_dev) {
444962306a36Sopenharmony_ci			struct iommu_resv_region *resv;
445062306a36Sopenharmony_ci			enum iommu_resv_type type;
445162306a36Sopenharmony_ci			size_t length;
445262306a36Sopenharmony_ci
445362306a36Sopenharmony_ci			if (i_dev != device &&
445462306a36Sopenharmony_ci			    !is_downstream_to_pci_bridge(device, i_dev))
445562306a36Sopenharmony_ci				continue;
445662306a36Sopenharmony_ci
445762306a36Sopenharmony_ci			length = rmrr->end_address - rmrr->base_address + 1;
445862306a36Sopenharmony_ci
445962306a36Sopenharmony_ci			type = device_rmrr_is_relaxable(device) ?
446062306a36Sopenharmony_ci				IOMMU_RESV_DIRECT_RELAXABLE : IOMMU_RESV_DIRECT;
446162306a36Sopenharmony_ci
446262306a36Sopenharmony_ci			resv = iommu_alloc_resv_region(rmrr->base_address,
446362306a36Sopenharmony_ci						       length, prot, type,
446462306a36Sopenharmony_ci						       GFP_ATOMIC);
446562306a36Sopenharmony_ci			if (!resv)
446662306a36Sopenharmony_ci				break;
446762306a36Sopenharmony_ci
446862306a36Sopenharmony_ci			list_add_tail(&resv->list, head);
446962306a36Sopenharmony_ci		}
447062306a36Sopenharmony_ci	}
447162306a36Sopenharmony_ci	rcu_read_unlock();
447262306a36Sopenharmony_ci
447362306a36Sopenharmony_ci#ifdef CONFIG_INTEL_IOMMU_FLOPPY_WA
447462306a36Sopenharmony_ci	if (dev_is_pci(device)) {
447562306a36Sopenharmony_ci		struct pci_dev *pdev = to_pci_dev(device);
447662306a36Sopenharmony_ci
447762306a36Sopenharmony_ci		if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) {
447862306a36Sopenharmony_ci			reg = iommu_alloc_resv_region(0, 1UL << 24, prot,
447962306a36Sopenharmony_ci					IOMMU_RESV_DIRECT_RELAXABLE,
448062306a36Sopenharmony_ci					GFP_KERNEL);
448162306a36Sopenharmony_ci			if (reg)
448262306a36Sopenharmony_ci				list_add_tail(&reg->list, head);
448362306a36Sopenharmony_ci		}
448462306a36Sopenharmony_ci	}
448562306a36Sopenharmony_ci#endif /* CONFIG_INTEL_IOMMU_FLOPPY_WA */
448662306a36Sopenharmony_ci
448762306a36Sopenharmony_ci	reg = iommu_alloc_resv_region(IOAPIC_RANGE_START,
448862306a36Sopenharmony_ci				      IOAPIC_RANGE_END - IOAPIC_RANGE_START + 1,
448962306a36Sopenharmony_ci				      0, IOMMU_RESV_MSI, GFP_KERNEL);
449062306a36Sopenharmony_ci	if (!reg)
449162306a36Sopenharmony_ci		return;
449262306a36Sopenharmony_ci	list_add_tail(&reg->list, head);
449362306a36Sopenharmony_ci}
449462306a36Sopenharmony_ci
449562306a36Sopenharmony_cistatic struct iommu_group *intel_iommu_device_group(struct device *dev)
449662306a36Sopenharmony_ci{
449762306a36Sopenharmony_ci	if (dev_is_pci(dev))
449862306a36Sopenharmony_ci		return pci_device_group(dev);
449962306a36Sopenharmony_ci	return generic_device_group(dev);
450062306a36Sopenharmony_ci}
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_cistatic int intel_iommu_enable_sva(struct device *dev)
450362306a36Sopenharmony_ci{
450462306a36Sopenharmony_ci	struct device_domain_info *info = dev_iommu_priv_get(dev);
450562306a36Sopenharmony_ci	struct intel_iommu *iommu;
450662306a36Sopenharmony_ci
450762306a36Sopenharmony_ci	if (!info || dmar_disabled)
450862306a36Sopenharmony_ci		return -EINVAL;
450962306a36Sopenharmony_ci
451062306a36Sopenharmony_ci	iommu = info->iommu;
451162306a36Sopenharmony_ci	if (!iommu)
451262306a36Sopenharmony_ci		return -EINVAL;
451362306a36Sopenharmony_ci
451462306a36Sopenharmony_ci	if (!(iommu->flags & VTD_FLAG_SVM_CAPABLE))
451562306a36Sopenharmony_ci		return -ENODEV;
451662306a36Sopenharmony_ci
451762306a36Sopenharmony_ci	if (!info->pasid_enabled || !info->ats_enabled)
451862306a36Sopenharmony_ci		return -EINVAL;
451962306a36Sopenharmony_ci
452062306a36Sopenharmony_ci	/*
452162306a36Sopenharmony_ci	 * Devices having device-specific I/O fault handling should not
452262306a36Sopenharmony_ci	 * support PCI/PRI. The IOMMU side has no means to check the
452362306a36Sopenharmony_ci	 * capability of device-specific IOPF.  Therefore, IOMMU can only
452462306a36Sopenharmony_ci	 * default that if the device driver enables SVA on a non-PRI
452562306a36Sopenharmony_ci	 * device, it will handle IOPF in its own way.
452662306a36Sopenharmony_ci	 */
452762306a36Sopenharmony_ci	if (!info->pri_supported)
452862306a36Sopenharmony_ci		return 0;
452962306a36Sopenharmony_ci
453062306a36Sopenharmony_ci	/* Devices supporting PRI should have it enabled. */
453162306a36Sopenharmony_ci	if (!info->pri_enabled)
453262306a36Sopenharmony_ci		return -EINVAL;
453362306a36Sopenharmony_ci
453462306a36Sopenharmony_ci	return 0;
453562306a36Sopenharmony_ci}
453662306a36Sopenharmony_ci
453762306a36Sopenharmony_cistatic int intel_iommu_enable_iopf(struct device *dev)
453862306a36Sopenharmony_ci{
453962306a36Sopenharmony_ci	struct pci_dev *pdev = dev_is_pci(dev) ? to_pci_dev(dev) : NULL;
454062306a36Sopenharmony_ci	struct device_domain_info *info = dev_iommu_priv_get(dev);
454162306a36Sopenharmony_ci	struct intel_iommu *iommu;
454262306a36Sopenharmony_ci	int ret;
454362306a36Sopenharmony_ci
454462306a36Sopenharmony_ci	if (!pdev || !info || !info->ats_enabled || !info->pri_supported)
454562306a36Sopenharmony_ci		return -ENODEV;
454662306a36Sopenharmony_ci
454762306a36Sopenharmony_ci	if (info->pri_enabled)
454862306a36Sopenharmony_ci		return -EBUSY;
454962306a36Sopenharmony_ci
455062306a36Sopenharmony_ci	iommu = info->iommu;
455162306a36Sopenharmony_ci	if (!iommu)
455262306a36Sopenharmony_ci		return -EINVAL;
455362306a36Sopenharmony_ci
455462306a36Sopenharmony_ci	/* PASID is required in PRG Response Message. */
455562306a36Sopenharmony_ci	if (info->pasid_enabled && !pci_prg_resp_pasid_required(pdev))
455662306a36Sopenharmony_ci		return -EINVAL;
455762306a36Sopenharmony_ci
455862306a36Sopenharmony_ci	ret = pci_reset_pri(pdev);
455962306a36Sopenharmony_ci	if (ret)
456062306a36Sopenharmony_ci		return ret;
456162306a36Sopenharmony_ci
456262306a36Sopenharmony_ci	ret = iopf_queue_add_device(iommu->iopf_queue, dev);
456362306a36Sopenharmony_ci	if (ret)
456462306a36Sopenharmony_ci		return ret;
456562306a36Sopenharmony_ci
456662306a36Sopenharmony_ci	ret = iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev);
456762306a36Sopenharmony_ci	if (ret)
456862306a36Sopenharmony_ci		goto iopf_remove_device;
456962306a36Sopenharmony_ci
457062306a36Sopenharmony_ci	ret = pci_enable_pri(pdev, PRQ_DEPTH);
457162306a36Sopenharmony_ci	if (ret)
457262306a36Sopenharmony_ci		goto iopf_unregister_handler;
457362306a36Sopenharmony_ci	info->pri_enabled = 1;
457462306a36Sopenharmony_ci
457562306a36Sopenharmony_ci	return 0;
457662306a36Sopenharmony_ci
457762306a36Sopenharmony_ciiopf_unregister_handler:
457862306a36Sopenharmony_ci	iommu_unregister_device_fault_handler(dev);
457962306a36Sopenharmony_ciiopf_remove_device:
458062306a36Sopenharmony_ci	iopf_queue_remove_device(iommu->iopf_queue, dev);
458162306a36Sopenharmony_ci
458262306a36Sopenharmony_ci	return ret;
458362306a36Sopenharmony_ci}
458462306a36Sopenharmony_ci
458562306a36Sopenharmony_cistatic int intel_iommu_disable_iopf(struct device *dev)
458662306a36Sopenharmony_ci{
458762306a36Sopenharmony_ci	struct device_domain_info *info = dev_iommu_priv_get(dev);
458862306a36Sopenharmony_ci	struct intel_iommu *iommu = info->iommu;
458962306a36Sopenharmony_ci
459062306a36Sopenharmony_ci	if (!info->pri_enabled)
459162306a36Sopenharmony_ci		return -EINVAL;
459262306a36Sopenharmony_ci
459362306a36Sopenharmony_ci	/*
459462306a36Sopenharmony_ci	 * PCIe spec states that by clearing PRI enable bit, the Page
459562306a36Sopenharmony_ci	 * Request Interface will not issue new page requests, but has
459662306a36Sopenharmony_ci	 * outstanding page requests that have been transmitted or are
459762306a36Sopenharmony_ci	 * queued for transmission. This is supposed to be called after
459862306a36Sopenharmony_ci	 * the device driver has stopped DMA, all PASIDs have been
459962306a36Sopenharmony_ci	 * unbound and the outstanding PRQs have been drained.
460062306a36Sopenharmony_ci	 */
460162306a36Sopenharmony_ci	pci_disable_pri(to_pci_dev(dev));
460262306a36Sopenharmony_ci	info->pri_enabled = 0;
460362306a36Sopenharmony_ci
460462306a36Sopenharmony_ci	/*
460562306a36Sopenharmony_ci	 * With PRI disabled and outstanding PRQs drained, unregistering
460662306a36Sopenharmony_ci	 * fault handler and removing device from iopf queue should never
460762306a36Sopenharmony_ci	 * fail.
460862306a36Sopenharmony_ci	 */
460962306a36Sopenharmony_ci	WARN_ON(iommu_unregister_device_fault_handler(dev));
461062306a36Sopenharmony_ci	WARN_ON(iopf_queue_remove_device(iommu->iopf_queue, dev));
461162306a36Sopenharmony_ci
461262306a36Sopenharmony_ci	return 0;
461362306a36Sopenharmony_ci}
461462306a36Sopenharmony_ci
461562306a36Sopenharmony_cistatic int
461662306a36Sopenharmony_ciintel_iommu_dev_enable_feat(struct device *dev, enum iommu_dev_features feat)
461762306a36Sopenharmony_ci{
461862306a36Sopenharmony_ci	switch (feat) {
461962306a36Sopenharmony_ci	case IOMMU_DEV_FEAT_IOPF:
462062306a36Sopenharmony_ci		return intel_iommu_enable_iopf(dev);
462162306a36Sopenharmony_ci
462262306a36Sopenharmony_ci	case IOMMU_DEV_FEAT_SVA:
462362306a36Sopenharmony_ci		return intel_iommu_enable_sva(dev);
462462306a36Sopenharmony_ci
462562306a36Sopenharmony_ci	default:
462662306a36Sopenharmony_ci		return -ENODEV;
462762306a36Sopenharmony_ci	}
462862306a36Sopenharmony_ci}
462962306a36Sopenharmony_ci
463062306a36Sopenharmony_cistatic int
463162306a36Sopenharmony_ciintel_iommu_dev_disable_feat(struct device *dev, enum iommu_dev_features feat)
463262306a36Sopenharmony_ci{
463362306a36Sopenharmony_ci	switch (feat) {
463462306a36Sopenharmony_ci	case IOMMU_DEV_FEAT_IOPF:
463562306a36Sopenharmony_ci		return intel_iommu_disable_iopf(dev);
463662306a36Sopenharmony_ci
463762306a36Sopenharmony_ci	case IOMMU_DEV_FEAT_SVA:
463862306a36Sopenharmony_ci		return 0;
463962306a36Sopenharmony_ci
464062306a36Sopenharmony_ci	default:
464162306a36Sopenharmony_ci		return -ENODEV;
464262306a36Sopenharmony_ci	}
464362306a36Sopenharmony_ci}
464462306a36Sopenharmony_ci
464562306a36Sopenharmony_cistatic bool intel_iommu_is_attach_deferred(struct device *dev)
464662306a36Sopenharmony_ci{
464762306a36Sopenharmony_ci	struct device_domain_info *info = dev_iommu_priv_get(dev);
464862306a36Sopenharmony_ci
464962306a36Sopenharmony_ci	return translation_pre_enabled(info->iommu) && !info->domain;
465062306a36Sopenharmony_ci}
465162306a36Sopenharmony_ci
465262306a36Sopenharmony_ci/*
465362306a36Sopenharmony_ci * Check that the device does not live on an external facing PCI port that is
465462306a36Sopenharmony_ci * marked as untrusted. Such devices should not be able to apply quirks and
465562306a36Sopenharmony_ci * thus not be able to bypass the IOMMU restrictions.
465662306a36Sopenharmony_ci */
465762306a36Sopenharmony_cistatic bool risky_device(struct pci_dev *pdev)
465862306a36Sopenharmony_ci{
465962306a36Sopenharmony_ci	if (pdev->untrusted) {
466062306a36Sopenharmony_ci		pci_info(pdev,
466162306a36Sopenharmony_ci			 "Skipping IOMMU quirk for dev [%04X:%04X] on untrusted PCI link\n",
466262306a36Sopenharmony_ci			 pdev->vendor, pdev->device);
466362306a36Sopenharmony_ci		pci_info(pdev, "Please check with your BIOS/Platform vendor about this\n");
466462306a36Sopenharmony_ci		return true;
466562306a36Sopenharmony_ci	}
466662306a36Sopenharmony_ci	return false;
466762306a36Sopenharmony_ci}
466862306a36Sopenharmony_ci
466962306a36Sopenharmony_cistatic void intel_iommu_iotlb_sync_map(struct iommu_domain *domain,
467062306a36Sopenharmony_ci				       unsigned long iova, size_t size)
467162306a36Sopenharmony_ci{
467262306a36Sopenharmony_ci	struct dmar_domain *dmar_domain = to_dmar_domain(domain);
467362306a36Sopenharmony_ci	unsigned long pages = aligned_nrpages(iova, size);
467462306a36Sopenharmony_ci	unsigned long pfn = iova >> VTD_PAGE_SHIFT;
467562306a36Sopenharmony_ci	struct iommu_domain_info *info;
467662306a36Sopenharmony_ci	unsigned long i;
467762306a36Sopenharmony_ci
467862306a36Sopenharmony_ci	xa_for_each(&dmar_domain->iommu_array, i, info)
467962306a36Sopenharmony_ci		__mapping_notify_one(info->iommu, dmar_domain, pfn, pages);
468062306a36Sopenharmony_ci}
468162306a36Sopenharmony_ci
468262306a36Sopenharmony_cistatic void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
468362306a36Sopenharmony_ci{
468462306a36Sopenharmony_ci	struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL);
468562306a36Sopenharmony_ci	struct dev_pasid_info *curr, *dev_pasid = NULL;
468662306a36Sopenharmony_ci	struct dmar_domain *dmar_domain;
468762306a36Sopenharmony_ci	struct iommu_domain *domain;
468862306a36Sopenharmony_ci	unsigned long flags;
468962306a36Sopenharmony_ci
469062306a36Sopenharmony_ci	domain = iommu_get_domain_for_dev_pasid(dev, pasid, 0);
469162306a36Sopenharmony_ci	if (WARN_ON_ONCE(!domain))
469262306a36Sopenharmony_ci		goto out_tear_down;
469362306a36Sopenharmony_ci
469462306a36Sopenharmony_ci	/*
469562306a36Sopenharmony_ci	 * The SVA implementation needs to handle its own stuffs like the mm
469662306a36Sopenharmony_ci	 * notification. Before consolidating that code into iommu core, let
469762306a36Sopenharmony_ci	 * the intel sva code handle it.
469862306a36Sopenharmony_ci	 */
469962306a36Sopenharmony_ci	if (domain->type == IOMMU_DOMAIN_SVA) {
470062306a36Sopenharmony_ci		intel_svm_remove_dev_pasid(dev, pasid);
470162306a36Sopenharmony_ci		goto out_tear_down;
470262306a36Sopenharmony_ci	}
470362306a36Sopenharmony_ci
470462306a36Sopenharmony_ci	dmar_domain = to_dmar_domain(domain);
470562306a36Sopenharmony_ci	spin_lock_irqsave(&dmar_domain->lock, flags);
470662306a36Sopenharmony_ci	list_for_each_entry(curr, &dmar_domain->dev_pasids, link_domain) {
470762306a36Sopenharmony_ci		if (curr->dev == dev && curr->pasid == pasid) {
470862306a36Sopenharmony_ci			list_del(&curr->link_domain);
470962306a36Sopenharmony_ci			dev_pasid = curr;
471062306a36Sopenharmony_ci			break;
471162306a36Sopenharmony_ci		}
471262306a36Sopenharmony_ci	}
471362306a36Sopenharmony_ci	WARN_ON_ONCE(!dev_pasid);
471462306a36Sopenharmony_ci	spin_unlock_irqrestore(&dmar_domain->lock, flags);
471562306a36Sopenharmony_ci
471662306a36Sopenharmony_ci	domain_detach_iommu(dmar_domain, iommu);
471762306a36Sopenharmony_ci	kfree(dev_pasid);
471862306a36Sopenharmony_ciout_tear_down:
471962306a36Sopenharmony_ci	intel_pasid_tear_down_entry(iommu, dev, pasid, false);
472062306a36Sopenharmony_ci	intel_drain_pasid_prq(dev, pasid);
472162306a36Sopenharmony_ci}
472262306a36Sopenharmony_ci
472362306a36Sopenharmony_cistatic int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
472462306a36Sopenharmony_ci				     struct device *dev, ioasid_t pasid)
472562306a36Sopenharmony_ci{
472662306a36Sopenharmony_ci	struct device_domain_info *info = dev_iommu_priv_get(dev);
472762306a36Sopenharmony_ci	struct dmar_domain *dmar_domain = to_dmar_domain(domain);
472862306a36Sopenharmony_ci	struct intel_iommu *iommu = info->iommu;
472962306a36Sopenharmony_ci	struct dev_pasid_info *dev_pasid;
473062306a36Sopenharmony_ci	unsigned long flags;
473162306a36Sopenharmony_ci	int ret;
473262306a36Sopenharmony_ci
473362306a36Sopenharmony_ci	if (!pasid_supported(iommu) || dev_is_real_dma_subdevice(dev))
473462306a36Sopenharmony_ci		return -EOPNOTSUPP;
473562306a36Sopenharmony_ci
473662306a36Sopenharmony_ci	if (context_copied(iommu, info->bus, info->devfn))
473762306a36Sopenharmony_ci		return -EBUSY;
473862306a36Sopenharmony_ci
473962306a36Sopenharmony_ci	ret = prepare_domain_attach_device(domain, dev);
474062306a36Sopenharmony_ci	if (ret)
474162306a36Sopenharmony_ci		return ret;
474262306a36Sopenharmony_ci
474362306a36Sopenharmony_ci	dev_pasid = kzalloc(sizeof(*dev_pasid), GFP_KERNEL);
474462306a36Sopenharmony_ci	if (!dev_pasid)
474562306a36Sopenharmony_ci		return -ENOMEM;
474662306a36Sopenharmony_ci
474762306a36Sopenharmony_ci	ret = domain_attach_iommu(dmar_domain, iommu);
474862306a36Sopenharmony_ci	if (ret)
474962306a36Sopenharmony_ci		goto out_free;
475062306a36Sopenharmony_ci
475162306a36Sopenharmony_ci	if (domain_type_is_si(dmar_domain))
475262306a36Sopenharmony_ci		ret = intel_pasid_setup_pass_through(iommu, dmar_domain,
475362306a36Sopenharmony_ci						     dev, pasid);
475462306a36Sopenharmony_ci	else if (dmar_domain->use_first_level)
475562306a36Sopenharmony_ci		ret = domain_setup_first_level(iommu, dmar_domain,
475662306a36Sopenharmony_ci					       dev, pasid);
475762306a36Sopenharmony_ci	else
475862306a36Sopenharmony_ci		ret = intel_pasid_setup_second_level(iommu, dmar_domain,
475962306a36Sopenharmony_ci						     dev, pasid);
476062306a36Sopenharmony_ci	if (ret)
476162306a36Sopenharmony_ci		goto out_detach_iommu;
476262306a36Sopenharmony_ci
476362306a36Sopenharmony_ci	dev_pasid->dev = dev;
476462306a36Sopenharmony_ci	dev_pasid->pasid = pasid;
476562306a36Sopenharmony_ci	spin_lock_irqsave(&dmar_domain->lock, flags);
476662306a36Sopenharmony_ci	list_add(&dev_pasid->link_domain, &dmar_domain->dev_pasids);
476762306a36Sopenharmony_ci	spin_unlock_irqrestore(&dmar_domain->lock, flags);
476862306a36Sopenharmony_ci
476962306a36Sopenharmony_ci	return 0;
477062306a36Sopenharmony_ciout_detach_iommu:
477162306a36Sopenharmony_ci	domain_detach_iommu(dmar_domain, iommu);
477262306a36Sopenharmony_ciout_free:
477362306a36Sopenharmony_ci	kfree(dev_pasid);
477462306a36Sopenharmony_ci	return ret;
477562306a36Sopenharmony_ci}
477662306a36Sopenharmony_ci
477762306a36Sopenharmony_cistatic void *intel_iommu_hw_info(struct device *dev, u32 *length, u32 *type)
477862306a36Sopenharmony_ci{
477962306a36Sopenharmony_ci	struct device_domain_info *info = dev_iommu_priv_get(dev);
478062306a36Sopenharmony_ci	struct intel_iommu *iommu = info->iommu;
478162306a36Sopenharmony_ci	struct iommu_hw_info_vtd *vtd;
478262306a36Sopenharmony_ci
478362306a36Sopenharmony_ci	vtd = kzalloc(sizeof(*vtd), GFP_KERNEL);
478462306a36Sopenharmony_ci	if (!vtd)
478562306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
478662306a36Sopenharmony_ci
478762306a36Sopenharmony_ci	vtd->cap_reg = iommu->cap;
478862306a36Sopenharmony_ci	vtd->ecap_reg = iommu->ecap;
478962306a36Sopenharmony_ci	*length = sizeof(*vtd);
479062306a36Sopenharmony_ci	*type = IOMMU_HW_INFO_TYPE_INTEL_VTD;
479162306a36Sopenharmony_ci	return vtd;
479262306a36Sopenharmony_ci}
479362306a36Sopenharmony_ci
479462306a36Sopenharmony_ciconst struct iommu_ops intel_iommu_ops = {
479562306a36Sopenharmony_ci	.capable		= intel_iommu_capable,
479662306a36Sopenharmony_ci	.hw_info		= intel_iommu_hw_info,
479762306a36Sopenharmony_ci	.domain_alloc		= intel_iommu_domain_alloc,
479862306a36Sopenharmony_ci	.probe_device		= intel_iommu_probe_device,
479962306a36Sopenharmony_ci	.probe_finalize		= intel_iommu_probe_finalize,
480062306a36Sopenharmony_ci	.release_device		= intel_iommu_release_device,
480162306a36Sopenharmony_ci	.get_resv_regions	= intel_iommu_get_resv_regions,
480262306a36Sopenharmony_ci	.device_group		= intel_iommu_device_group,
480362306a36Sopenharmony_ci	.dev_enable_feat	= intel_iommu_dev_enable_feat,
480462306a36Sopenharmony_ci	.dev_disable_feat	= intel_iommu_dev_disable_feat,
480562306a36Sopenharmony_ci	.is_attach_deferred	= intel_iommu_is_attach_deferred,
480662306a36Sopenharmony_ci	.def_domain_type	= device_def_domain_type,
480762306a36Sopenharmony_ci	.remove_dev_pasid	= intel_iommu_remove_dev_pasid,
480862306a36Sopenharmony_ci	.pgsize_bitmap		= SZ_4K,
480962306a36Sopenharmony_ci#ifdef CONFIG_INTEL_IOMMU_SVM
481062306a36Sopenharmony_ci	.page_response		= intel_svm_page_response,
481162306a36Sopenharmony_ci#endif
481262306a36Sopenharmony_ci	.default_domain_ops = &(const struct iommu_domain_ops) {
481362306a36Sopenharmony_ci		.attach_dev		= intel_iommu_attach_device,
481462306a36Sopenharmony_ci		.set_dev_pasid		= intel_iommu_set_dev_pasid,
481562306a36Sopenharmony_ci		.map_pages		= intel_iommu_map_pages,
481662306a36Sopenharmony_ci		.unmap_pages		= intel_iommu_unmap_pages,
481762306a36Sopenharmony_ci		.iotlb_sync_map		= intel_iommu_iotlb_sync_map,
481862306a36Sopenharmony_ci		.flush_iotlb_all        = intel_flush_iotlb_all,
481962306a36Sopenharmony_ci		.iotlb_sync		= intel_iommu_tlb_sync,
482062306a36Sopenharmony_ci		.iova_to_phys		= intel_iommu_iova_to_phys,
482162306a36Sopenharmony_ci		.free			= intel_iommu_domain_free,
482262306a36Sopenharmony_ci		.enforce_cache_coherency = intel_iommu_enforce_cache_coherency,
482362306a36Sopenharmony_ci	}
482462306a36Sopenharmony_ci};
482562306a36Sopenharmony_ci
482662306a36Sopenharmony_cistatic void quirk_iommu_igfx(struct pci_dev *dev)
482762306a36Sopenharmony_ci{
482862306a36Sopenharmony_ci	if (risky_device(dev))
482962306a36Sopenharmony_ci		return;
483062306a36Sopenharmony_ci
483162306a36Sopenharmony_ci	pci_info(dev, "Disabling IOMMU for graphics on this chipset\n");
483262306a36Sopenharmony_ci	dmar_map_gfx = 0;
483362306a36Sopenharmony_ci}
483462306a36Sopenharmony_ci
483562306a36Sopenharmony_ci/* G4x/GM45 integrated gfx dmar support is totally busted. */
483662306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx);
483762306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx);
483862306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_igfx);
483962306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_igfx);
484062306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_igfx);
484162306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_igfx);
484262306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_igfx);
484362306a36Sopenharmony_ci
484462306a36Sopenharmony_ci/* Broadwell igfx malfunctions with dmar */
484562306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1606, quirk_iommu_igfx);
484662306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160B, quirk_iommu_igfx);
484762306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160E, quirk_iommu_igfx);
484862306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1602, quirk_iommu_igfx);
484962306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160A, quirk_iommu_igfx);
485062306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x160D, quirk_iommu_igfx);
485162306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1616, quirk_iommu_igfx);
485262306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x161B, quirk_iommu_igfx);
485362306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x161E, quirk_iommu_igfx);
485462306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1612, quirk_iommu_igfx);
485562306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x161A, quirk_iommu_igfx);
485662306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x161D, quirk_iommu_igfx);
485762306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1626, quirk_iommu_igfx);
485862306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x162B, quirk_iommu_igfx);
485962306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x162E, quirk_iommu_igfx);
486062306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1622, quirk_iommu_igfx);
486162306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x162A, quirk_iommu_igfx);
486262306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x162D, quirk_iommu_igfx);
486362306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1636, quirk_iommu_igfx);
486462306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163B, quirk_iommu_igfx);
486562306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163E, quirk_iommu_igfx);
486662306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx);
486762306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx);
486862306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx);
486962306a36Sopenharmony_ci
487062306a36Sopenharmony_cistatic void quirk_iommu_rwbf(struct pci_dev *dev)
487162306a36Sopenharmony_ci{
487262306a36Sopenharmony_ci	if (risky_device(dev))
487362306a36Sopenharmony_ci		return;
487462306a36Sopenharmony_ci
487562306a36Sopenharmony_ci	/*
487662306a36Sopenharmony_ci	 * Mobile 4 Series Chipset neglects to set RWBF capability,
487762306a36Sopenharmony_ci	 * but needs it. Same seems to hold for the desktop versions.
487862306a36Sopenharmony_ci	 */
487962306a36Sopenharmony_ci	pci_info(dev, "Forcing write-buffer flush capability\n");
488062306a36Sopenharmony_ci	rwbf_quirk = 1;
488162306a36Sopenharmony_ci}
488262306a36Sopenharmony_ci
488362306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
488462306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_rwbf);
488562306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e10, quirk_iommu_rwbf);
488662306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e20, quirk_iommu_rwbf);
488762306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e30, quirk_iommu_rwbf);
488862306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e40, quirk_iommu_rwbf);
488962306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e90, quirk_iommu_rwbf);
489062306a36Sopenharmony_ci
489162306a36Sopenharmony_ci#define GGC 0x52
489262306a36Sopenharmony_ci#define GGC_MEMORY_SIZE_MASK	(0xf << 8)
489362306a36Sopenharmony_ci#define GGC_MEMORY_SIZE_NONE	(0x0 << 8)
489462306a36Sopenharmony_ci#define GGC_MEMORY_SIZE_1M	(0x1 << 8)
489562306a36Sopenharmony_ci#define GGC_MEMORY_SIZE_2M	(0x3 << 8)
489662306a36Sopenharmony_ci#define GGC_MEMORY_VT_ENABLED	(0x8 << 8)
489762306a36Sopenharmony_ci#define GGC_MEMORY_SIZE_2M_VT	(0x9 << 8)
489862306a36Sopenharmony_ci#define GGC_MEMORY_SIZE_3M_VT	(0xa << 8)
489962306a36Sopenharmony_ci#define GGC_MEMORY_SIZE_4M_VT	(0xb << 8)
490062306a36Sopenharmony_ci
490162306a36Sopenharmony_cistatic void quirk_calpella_no_shadow_gtt(struct pci_dev *dev)
490262306a36Sopenharmony_ci{
490362306a36Sopenharmony_ci	unsigned short ggc;
490462306a36Sopenharmony_ci
490562306a36Sopenharmony_ci	if (risky_device(dev))
490662306a36Sopenharmony_ci		return;
490762306a36Sopenharmony_ci
490862306a36Sopenharmony_ci	if (pci_read_config_word(dev, GGC, &ggc))
490962306a36Sopenharmony_ci		return;
491062306a36Sopenharmony_ci
491162306a36Sopenharmony_ci	if (!(ggc & GGC_MEMORY_VT_ENABLED)) {
491262306a36Sopenharmony_ci		pci_info(dev, "BIOS has allocated no shadow GTT; disabling IOMMU for graphics\n");
491362306a36Sopenharmony_ci		dmar_map_gfx = 0;
491462306a36Sopenharmony_ci	} else if (dmar_map_gfx) {
491562306a36Sopenharmony_ci		/* we have to ensure the gfx device is idle before we flush */
491662306a36Sopenharmony_ci		pci_info(dev, "Disabling batched IOTLB flush on Ironlake\n");
491762306a36Sopenharmony_ci		iommu_set_dma_strict();
491862306a36Sopenharmony_ci	}
491962306a36Sopenharmony_ci}
492062306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0040, quirk_calpella_no_shadow_gtt);
492162306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0044, quirk_calpella_no_shadow_gtt);
492262306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0062, quirk_calpella_no_shadow_gtt);
492362306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x006a, quirk_calpella_no_shadow_gtt);
492462306a36Sopenharmony_ci
492562306a36Sopenharmony_cistatic void quirk_igfx_skip_te_disable(struct pci_dev *dev)
492662306a36Sopenharmony_ci{
492762306a36Sopenharmony_ci	unsigned short ver;
492862306a36Sopenharmony_ci
492962306a36Sopenharmony_ci	if (!IS_GFX_DEVICE(dev))
493062306a36Sopenharmony_ci		return;
493162306a36Sopenharmony_ci
493262306a36Sopenharmony_ci	ver = (dev->device >> 8) & 0xff;
493362306a36Sopenharmony_ci	if (ver != 0x45 && ver != 0x46 && ver != 0x4c &&
493462306a36Sopenharmony_ci	    ver != 0x4e && ver != 0x8a && ver != 0x98 &&
493562306a36Sopenharmony_ci	    ver != 0x9a && ver != 0xa7 && ver != 0x7d)
493662306a36Sopenharmony_ci		return;
493762306a36Sopenharmony_ci
493862306a36Sopenharmony_ci	if (risky_device(dev))
493962306a36Sopenharmony_ci		return;
494062306a36Sopenharmony_ci
494162306a36Sopenharmony_ci	pci_info(dev, "Skip IOMMU disabling for graphics\n");
494262306a36Sopenharmony_ci	iommu_skip_te_disable = 1;
494362306a36Sopenharmony_ci}
494462306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_igfx_skip_te_disable);
494562306a36Sopenharmony_ci
494662306a36Sopenharmony_ci/* On Tylersburg chipsets, some BIOSes have been known to enable the
494762306a36Sopenharmony_ci   ISOCH DMAR unit for the Azalia sound device, but not give it any
494862306a36Sopenharmony_ci   TLB entries, which causes it to deadlock. Check for that.  We do
494962306a36Sopenharmony_ci   this in a function called from init_dmars(), instead of in a PCI
495062306a36Sopenharmony_ci   quirk, because we don't want to print the obnoxious "BIOS broken"
495162306a36Sopenharmony_ci   message if VT-d is actually disabled.
495262306a36Sopenharmony_ci*/
495362306a36Sopenharmony_cistatic void __init check_tylersburg_isoch(void)
495462306a36Sopenharmony_ci{
495562306a36Sopenharmony_ci	struct pci_dev *pdev;
495662306a36Sopenharmony_ci	uint32_t vtisochctrl;
495762306a36Sopenharmony_ci
495862306a36Sopenharmony_ci	/* If there's no Azalia in the system anyway, forget it. */
495962306a36Sopenharmony_ci	pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
496062306a36Sopenharmony_ci	if (!pdev)
496162306a36Sopenharmony_ci		return;
496262306a36Sopenharmony_ci
496362306a36Sopenharmony_ci	if (risky_device(pdev)) {
496462306a36Sopenharmony_ci		pci_dev_put(pdev);
496562306a36Sopenharmony_ci		return;
496662306a36Sopenharmony_ci	}
496762306a36Sopenharmony_ci
496862306a36Sopenharmony_ci	pci_dev_put(pdev);
496962306a36Sopenharmony_ci
497062306a36Sopenharmony_ci	/* System Management Registers. Might be hidden, in which case
497162306a36Sopenharmony_ci	   we can't do the sanity check. But that's OK, because the
497262306a36Sopenharmony_ci	   known-broken BIOSes _don't_ actually hide it, so far. */
497362306a36Sopenharmony_ci	pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
497462306a36Sopenharmony_ci	if (!pdev)
497562306a36Sopenharmony_ci		return;
497662306a36Sopenharmony_ci
497762306a36Sopenharmony_ci	if (risky_device(pdev)) {
497862306a36Sopenharmony_ci		pci_dev_put(pdev);
497962306a36Sopenharmony_ci		return;
498062306a36Sopenharmony_ci	}
498162306a36Sopenharmony_ci
498262306a36Sopenharmony_ci	if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
498362306a36Sopenharmony_ci		pci_dev_put(pdev);
498462306a36Sopenharmony_ci		return;
498562306a36Sopenharmony_ci	}
498662306a36Sopenharmony_ci
498762306a36Sopenharmony_ci	pci_dev_put(pdev);
498862306a36Sopenharmony_ci
498962306a36Sopenharmony_ci	/* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
499062306a36Sopenharmony_ci	if (vtisochctrl & 1)
499162306a36Sopenharmony_ci		return;
499262306a36Sopenharmony_ci
499362306a36Sopenharmony_ci	/* Drop all bits other than the number of TLB entries */
499462306a36Sopenharmony_ci	vtisochctrl &= 0x1c;
499562306a36Sopenharmony_ci
499662306a36Sopenharmony_ci	/* If we have the recommended number of TLB entries (16), fine. */
499762306a36Sopenharmony_ci	if (vtisochctrl == 0x10)
499862306a36Sopenharmony_ci		return;
499962306a36Sopenharmony_ci
500062306a36Sopenharmony_ci	/* Zero TLB entries? You get to ride the short bus to school. */
500162306a36Sopenharmony_ci	if (!vtisochctrl) {
500262306a36Sopenharmony_ci		WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
500362306a36Sopenharmony_ci		     "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
500462306a36Sopenharmony_ci		     dmi_get_system_info(DMI_BIOS_VENDOR),
500562306a36Sopenharmony_ci		     dmi_get_system_info(DMI_BIOS_VERSION),
500662306a36Sopenharmony_ci		     dmi_get_system_info(DMI_PRODUCT_VERSION));
500762306a36Sopenharmony_ci		iommu_identity_mapping |= IDENTMAP_AZALIA;
500862306a36Sopenharmony_ci		return;
500962306a36Sopenharmony_ci	}
501062306a36Sopenharmony_ci
501162306a36Sopenharmony_ci	pr_warn("Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
501262306a36Sopenharmony_ci	       vtisochctrl);
501362306a36Sopenharmony_ci}
501462306a36Sopenharmony_ci
501562306a36Sopenharmony_ci/*
501662306a36Sopenharmony_ci * Here we deal with a device TLB defect where device may inadvertently issue ATS
501762306a36Sopenharmony_ci * invalidation completion before posted writes initiated with translated address
501862306a36Sopenharmony_ci * that utilized translations matching the invalidation address range, violating
501962306a36Sopenharmony_ci * the invalidation completion ordering.
502062306a36Sopenharmony_ci * Therefore, any use cases that cannot guarantee DMA is stopped before unmap is
502162306a36Sopenharmony_ci * vulnerable to this defect. In other words, any dTLB invalidation initiated not
502262306a36Sopenharmony_ci * under the control of the trusted/privileged host device driver must use this
502362306a36Sopenharmony_ci * quirk.
502462306a36Sopenharmony_ci * Device TLBs are invalidated under the following six conditions:
502562306a36Sopenharmony_ci * 1. Device driver does DMA API unmap IOVA
502662306a36Sopenharmony_ci * 2. Device driver unbind a PASID from a process, sva_unbind_device()
502762306a36Sopenharmony_ci * 3. PASID is torn down, after PASID cache is flushed. e.g. process
502862306a36Sopenharmony_ci *    exit_mmap() due to crash
502962306a36Sopenharmony_ci * 4. Under SVA usage, called by mmu_notifier.invalidate_range() where
503062306a36Sopenharmony_ci *    VM has to free pages that were unmapped
503162306a36Sopenharmony_ci * 5. Userspace driver unmaps a DMA buffer
503262306a36Sopenharmony_ci * 6. Cache invalidation in vSVA usage (upcoming)
503362306a36Sopenharmony_ci *
503462306a36Sopenharmony_ci * For #1 and #2, device drivers are responsible for stopping DMA traffic
503562306a36Sopenharmony_ci * before unmap/unbind. For #3, iommu driver gets mmu_notifier to
503662306a36Sopenharmony_ci * invalidate TLB the same way as normal user unmap which will use this quirk.
503762306a36Sopenharmony_ci * The dTLB invalidation after PASID cache flush does not need this quirk.
503862306a36Sopenharmony_ci *
503962306a36Sopenharmony_ci * As a reminder, #6 will *NEED* this quirk as we enable nested translation.
504062306a36Sopenharmony_ci */
504162306a36Sopenharmony_civoid quirk_extra_dev_tlb_flush(struct device_domain_info *info,
504262306a36Sopenharmony_ci			       unsigned long address, unsigned long mask,
504362306a36Sopenharmony_ci			       u32 pasid, u16 qdep)
504462306a36Sopenharmony_ci{
504562306a36Sopenharmony_ci	u16 sid;
504662306a36Sopenharmony_ci
504762306a36Sopenharmony_ci	if (likely(!info->dtlb_extra_inval))
504862306a36Sopenharmony_ci		return;
504962306a36Sopenharmony_ci
505062306a36Sopenharmony_ci	sid = PCI_DEVID(info->bus, info->devfn);
505162306a36Sopenharmony_ci	if (pasid == IOMMU_NO_PASID) {
505262306a36Sopenharmony_ci		qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
505362306a36Sopenharmony_ci				   qdep, address, mask);
505462306a36Sopenharmony_ci	} else {
505562306a36Sopenharmony_ci		qi_flush_dev_iotlb_pasid(info->iommu, sid, info->pfsid,
505662306a36Sopenharmony_ci					 pasid, qdep, address, mask);
505762306a36Sopenharmony_ci	}
505862306a36Sopenharmony_ci}
505962306a36Sopenharmony_ci
506062306a36Sopenharmony_ci#define ecmd_get_status_code(res)	(((res) & 0xff) >> 1)
506162306a36Sopenharmony_ci
506262306a36Sopenharmony_ci/*
506362306a36Sopenharmony_ci * Function to submit a command to the enhanced command interface. The
506462306a36Sopenharmony_ci * valid enhanced command descriptions are defined in Table 47 of the
506562306a36Sopenharmony_ci * VT-d spec. The VT-d hardware implementation may support some but not
506662306a36Sopenharmony_ci * all commands, which can be determined by checking the Enhanced
506762306a36Sopenharmony_ci * Command Capability Register.
506862306a36Sopenharmony_ci *
506962306a36Sopenharmony_ci * Return values:
507062306a36Sopenharmony_ci *  - 0: Command successful without any error;
507162306a36Sopenharmony_ci *  - Negative: software error value;
507262306a36Sopenharmony_ci *  - Nonzero positive: failure status code defined in Table 48.
507362306a36Sopenharmony_ci */
507462306a36Sopenharmony_ciint ecmd_submit_sync(struct intel_iommu *iommu, u8 ecmd, u64 oa, u64 ob)
507562306a36Sopenharmony_ci{
507662306a36Sopenharmony_ci	unsigned long flags;
507762306a36Sopenharmony_ci	u64 res;
507862306a36Sopenharmony_ci	int ret;
507962306a36Sopenharmony_ci
508062306a36Sopenharmony_ci	if (!cap_ecmds(iommu->cap))
508162306a36Sopenharmony_ci		return -ENODEV;
508262306a36Sopenharmony_ci
508362306a36Sopenharmony_ci	raw_spin_lock_irqsave(&iommu->register_lock, flags);
508462306a36Sopenharmony_ci
508562306a36Sopenharmony_ci	res = dmar_readq(iommu->reg + DMAR_ECRSP_REG);
508662306a36Sopenharmony_ci	if (res & DMA_ECMD_ECRSP_IP) {
508762306a36Sopenharmony_ci		ret = -EBUSY;
508862306a36Sopenharmony_ci		goto err;
508962306a36Sopenharmony_ci	}
509062306a36Sopenharmony_ci
509162306a36Sopenharmony_ci	/*
509262306a36Sopenharmony_ci	 * Unconditionally write the operand B, because
509362306a36Sopenharmony_ci	 * - There is no side effect if an ecmd doesn't require an
509462306a36Sopenharmony_ci	 *   operand B, but we set the register to some value.
509562306a36Sopenharmony_ci	 * - It's not invoked in any critical path. The extra MMIO
509662306a36Sopenharmony_ci	 *   write doesn't bring any performance concerns.
509762306a36Sopenharmony_ci	 */
509862306a36Sopenharmony_ci	dmar_writeq(iommu->reg + DMAR_ECEO_REG, ob);
509962306a36Sopenharmony_ci	dmar_writeq(iommu->reg + DMAR_ECMD_REG, ecmd | (oa << DMA_ECMD_OA_SHIFT));
510062306a36Sopenharmony_ci
510162306a36Sopenharmony_ci	IOMMU_WAIT_OP(iommu, DMAR_ECRSP_REG, dmar_readq,
510262306a36Sopenharmony_ci		      !(res & DMA_ECMD_ECRSP_IP), res);
510362306a36Sopenharmony_ci
510462306a36Sopenharmony_ci	if (res & DMA_ECMD_ECRSP_IP) {
510562306a36Sopenharmony_ci		ret = -ETIMEDOUT;
510662306a36Sopenharmony_ci		goto err;
510762306a36Sopenharmony_ci	}
510862306a36Sopenharmony_ci
510962306a36Sopenharmony_ci	ret = ecmd_get_status_code(res);
511062306a36Sopenharmony_cierr:
511162306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
511262306a36Sopenharmony_ci
511362306a36Sopenharmony_ci	return ret;
511462306a36Sopenharmony_ci}
5115