xref: /linux/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c (revision 7b26bc6582b13a52a42a4a9765e8f30d58a81198)
12d7ca2c4SAndrew Murray // SPDX-License-Identifier: GPL-2.0
248ec83bcSWill Deacon /*
348ec83bcSWill Deacon  * IOMMU API for ARM architected SMMUv3 implementations.
448ec83bcSWill Deacon  *
548ec83bcSWill Deacon  * Copyright (C) 2015 ARM Limited
648ec83bcSWill Deacon  *
748ec83bcSWill Deacon  * Author: Will Deacon <will.deacon@arm.com>
848ec83bcSWill Deacon  *
948ec83bcSWill Deacon  * This driver is powered by bad coffee and bombay mix.
1048ec83bcSWill Deacon  */
1148ec83bcSWill Deacon 
12e4dadfa8SLorenzo Pieralisi #include <linux/acpi.h>
13e4dadfa8SLorenzo Pieralisi #include <linux/acpi_iort.h>
141cf9e54eSRobin Murphy #include <linux/bitops.h>
15b63b3439SWill Deacon #include <linux/crash_dump.h>
1648ec83bcSWill Deacon #include <linux/delay.h>
1748ec83bcSWill Deacon #include <linux/err.h>
1848ec83bcSWill Deacon #include <linux/interrupt.h>
19b77cf11fSRob Herring #include <linux/io-pgtable.h>
2048ec83bcSWill Deacon #include <linux/iopoll.h>
216e8fa740SWill Deacon #include <linux/module.h>
22166bdbd2SMarc Zyngier #include <linux/msi.h>
2348ec83bcSWill Deacon #include <linux/of.h>
2448ec83bcSWill Deacon #include <linux/of_address.h>
25941a802dSWill Deacon #include <linux/of_platform.h>
2648ec83bcSWill Deacon #include <linux/pci.h>
279ce27afcSJean-Philippe Brucker #include <linux/pci-ats.h>
2848ec83bcSWill Deacon #include <linux/platform_device.h>
2956e1a4ccSJason Gunthorpe #include <linux/string_choices.h>
30eb054d67SJoao Martins #include <kunit/visibility.h>
3148ec83bcSWill Deacon #include <uapi/linux/iommufd.h>
32e881e783SJean-Philippe Brucker 
33f2042ed2SRobin Murphy #include "arm-smmu-v3.h"
3450019f09SEric Auger #include "../../dma-iommu.h"
35bd07a20aSBarry Song 
36bd07a20aSBarry Song static bool disable_msipolling;
37bd07a20aSBarry Song module_param(disable_msipolling, bool, 0444);
38bd07a20aSBarry Song MODULE_PARM_DESC(disable_msipolling,
39bd07a20aSBarry Song 	"Disable MSI-based polling for CMD_SYNC completion.");
4052acd7d8SShameer Kolothum 
41eb054d67SJoao Martins static const struct iommu_ops arm_smmu_ops;
4252acd7d8SShameer Kolothum static struct iommu_dirty_ops arm_smmu_dirty_ops;
43166bdbd2SMarc Zyngier 
44166bdbd2SMarc Zyngier enum arm_smmu_msi_index {
45166bdbd2SMarc Zyngier 	EVTQ_MSI_INDEX,
46166bdbd2SMarc Zyngier 	GERROR_MSI_INDEX,
47166bdbd2SMarc Zyngier 	PRIQ_MSI_INDEX,
48166bdbd2SMarc Zyngier 	ARM_SMMU_MAX_MSIS,
49166bdbd2SMarc Zyngier };
50de31c355SJason Gunthorpe 
51de31c355SJason Gunthorpe #define NUM_ENTRY_QWORDS 8
5278a5fbe8SJason Gunthorpe static_assert(sizeof(struct arm_smmu_ste) == NUM_ENTRY_QWORDS * sizeof(u64));
537da51af9SJason Gunthorpe static_assert(sizeof(struct arm_smmu_cd) == NUM_ENTRY_QWORDS * sizeof(u64));
54166bdbd2SMarc Zyngier 
55166bdbd2SMarc Zyngier static phys_addr_t arm_smmu_msi_cfg[ARM_SMMU_MAX_MSIS][3] = {
56166bdbd2SMarc Zyngier 	[EVTQ_MSI_INDEX] = {
57166bdbd2SMarc Zyngier 		ARM_SMMU_EVTQ_IRQ_CFG0,
58166bdbd2SMarc Zyngier 		ARM_SMMU_EVTQ_IRQ_CFG1,
59166bdbd2SMarc Zyngier 		ARM_SMMU_EVTQ_IRQ_CFG2,
60166bdbd2SMarc Zyngier 	},
61166bdbd2SMarc Zyngier 	[GERROR_MSI_INDEX] = {
62166bdbd2SMarc Zyngier 		ARM_SMMU_GERROR_IRQ_CFG0,
63166bdbd2SMarc Zyngier 		ARM_SMMU_GERROR_IRQ_CFG1,
64166bdbd2SMarc Zyngier 		ARM_SMMU_GERROR_IRQ_CFG2,
65166bdbd2SMarc Zyngier 	},
66166bdbd2SMarc Zyngier 	[PRIQ_MSI_INDEX] = {
67166bdbd2SMarc Zyngier 		ARM_SMMU_PRIQ_IRQ_CFG0,
68166bdbd2SMarc Zyngier 		ARM_SMMU_PRIQ_IRQ_CFG1,
69166bdbd2SMarc Zyngier 		ARM_SMMU_PRIQ_IRQ_CFG2,
70166bdbd2SMarc Zyngier 	},
71166bdbd2SMarc Zyngier };
725e92946cSZhen Lei 
735e92946cSZhen Lei struct arm_smmu_option_prop {
745e92946cSZhen Lei 	u32 opt;
755e92946cSZhen Lei 	const char *prop;
765e92946cSZhen Lei };
773f1ce8e8SJean-Philippe Brucker 
783f1ce8e8SJean-Philippe Brucker DEFINE_XARRAY_ALLOC1(arm_smmu_asid_xa);
790299a1a8SJean-Philippe Brucker DEFINE_MUTEX(arm_smmu_asid_lock);
805e92946cSZhen Lei 
815e92946cSZhen Lei static struct arm_smmu_option_prop arm_smmu_options[] = {
82e5b829deSLinu Cherian 	{ ARM_SMMU_OPT_SKIP_PREFETCH, "hisilicon,broken-prefetch-cmd" },
835e92946cSZhen Lei 	{ ARM_SMMU_OPT_PAGE0_REGS_ONLY, "cavium,cn9900-broken-page1-regspace"},
845e92946cSZhen Lei 	{ 0, NULL},
855e92946cSZhen Lei };
86d8cd2006SJason Gunthorpe 
87eb054d67SJoao Martins static const char * const event_str[] = {
88b2f4c0fcSJason Gunthorpe 	[EVT_ID_BAD_STREAMID_CONFIG] = "C_BAD_STREAMID",
89d8cd2006SJason Gunthorpe 	[EVT_ID_STE_FETCH_FAULT] = "F_STE_FETCH",
905e92946cSZhen Lei 	[EVT_ID_BAD_STE_CONFIG] = "C_BAD_STE",
915e92946cSZhen Lei 	[EVT_ID_STREAM_DISABLED_FAULT] = "F_STREAM_DISABLED",
925e92946cSZhen Lei 	[EVT_ID_BAD_SUBSTREAMID_CONFIG] = "C_BAD_SUBSTREAMID",
935e92946cSZhen Lei 	[EVT_ID_CD_FETCH_FAULT] = "F_CD_FETCH",
945e92946cSZhen Lei 	[EVT_ID_BAD_CD_CONFIG] = "C_BAD_CD",
955e92946cSZhen Lei 	[EVT_ID_TRANSLATION_FAULT] = "F_TRANSLATION",
965e92946cSZhen Lei 	[EVT_ID_ADDR_SIZE_FAULT] = "F_ADDR_SIZE",
975e92946cSZhen Lei 	[EVT_ID_ACCESS_FAULT] = "F_ACCESS",
985e92946cSZhen Lei 	[EVT_ID_PERMISSION_FAULT] = "F_PERMISSION",
995e92946cSZhen Lei 	[EVT_ID_VMS_FETCH_FAULT] = "F_VMS_FETCH",
1005e92946cSZhen Lei };
1015e92946cSZhen Lei 
1025e92946cSZhen Lei static const char * const event_class_str[] = {
1035e92946cSZhen Lei 	[0] = "CD fetch",
10448ec83bcSWill Deacon 	[1] = "Stage 1 translation table fetch",
105587e6c10SWill Deacon 	[2] = "Input address caused fault",
106587e6c10SWill Deacon 	[3] = "Reserved",
107587e6c10SWill Deacon };
108587e6c10SWill Deacon 
109587e6c10SWill Deacon static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master);
110587e6c10SWill Deacon 
parse_driver_options(struct arm_smmu_device * smmu)111587e6c10SWill Deacon static void parse_driver_options(struct arm_smmu_device *smmu)
112587e6c10SWill Deacon {
113587e6c10SWill Deacon 	int i = 0;
114587e6c10SWill Deacon 
115587e6c10SWill Deacon 	do {
116587e6c10SWill Deacon 		if (of_property_read_bool(smmu->dev->of_node,
117587e6c10SWill Deacon 						arm_smmu_options[i].prop)) {
118587e6c10SWill Deacon 			smmu->options |= arm_smmu_options[i].opt;
119587e6c10SWill Deacon 			dev_notice(smmu->dev, "option %s\n",
1207c288a5bSWill Deacon 				arm_smmu_options[i].prop);
12148ec83bcSWill Deacon 		}
12248ec83bcSWill Deacon 	} while (arm_smmu_options[++i].opt);
12348ec83bcSWill Deacon }
12448ec83bcSWill Deacon 
12548ec83bcSWill Deacon /* Low-level queue manipulation functions */
queue_has_space(struct arm_smmu_ll_queue * q,u32 n)1267c288a5bSWill Deacon static bool queue_has_space(struct arm_smmu_ll_queue *q, u32 n)
12748ec83bcSWill Deacon {
12848ec83bcSWill Deacon 	u32 space, prod, cons;
12948ec83bcSWill Deacon 
13048ec83bcSWill Deacon 	prod = Q_IDX(q, q->prod);
13148ec83bcSWill Deacon 	cons = Q_IDX(q, q->cons);
132587e6c10SWill Deacon 
13348ec83bcSWill Deacon 	if (Q_WRP(q, q->prod) == Q_WRP(q, q->cons))
134587e6c10SWill Deacon 		space = (1 << q->max_n_shift) - (prod - cons);
135587e6c10SWill Deacon 	else
136587e6c10SWill Deacon 		space = cons - prod;
137587e6c10SWill Deacon 
13848ec83bcSWill Deacon 	return space >= n;
13948ec83bcSWill Deacon }
1402a8868f1SWill Deacon 
queue_full(struct arm_smmu_ll_queue * q)14148ec83bcSWill Deacon static bool queue_full(struct arm_smmu_ll_queue *q)
142a868e853SWill Deacon {
143a868e853SWill Deacon 	return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) &&
144a868e853SWill Deacon 	       Q_WRP(q, q->prod) != Q_WRP(q, q->cons);
145a868e853SWill Deacon }
146a76a3777SZhou Wang 
queue_empty(struct arm_smmu_ll_queue * q)14752be8637SWill Deacon static bool queue_empty(struct arm_smmu_ll_queue *q)
14848ec83bcSWill Deacon {
14948ec83bcSWill Deacon 	return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) &&
1507c288a5bSWill Deacon 	       Q_WRP(q, q->prod) == Q_WRP(q, q->cons);
1512a8868f1SWill Deacon }
1527c288a5bSWill Deacon 
queue_consumed(struct arm_smmu_ll_queue * q,u32 prod)1537c288a5bSWill Deacon static bool queue_consumed(struct arm_smmu_ll_queue *q, u32 prod)
1542a8868f1SWill Deacon {
1552a8868f1SWill Deacon 	return ((Q_WRP(q, q->cons) == Q_WRP(q, prod)) &&
15667ea0b7cSTomas Krcka 		(Q_IDX(q, q->cons) > Q_IDX(q, prod))) ||
15767ea0b7cSTomas Krcka 	       ((Q_WRP(q, q->cons) != Q_WRP(q, prod)) &&
15867ea0b7cSTomas Krcka 		(Q_IDX(q, q->cons) <= Q_IDX(q, prod)));
15967ea0b7cSTomas Krcka }
16067ea0b7cSTomas Krcka 
queue_sync_cons_out(struct arm_smmu_queue * q)16167ea0b7cSTomas Krcka static void queue_sync_cons_out(struct arm_smmu_queue *q)
16267ea0b7cSTomas Krcka {
16367ea0b7cSTomas Krcka 	/*
16467ea0b7cSTomas Krcka 	 * Ensure that all CPU accesses (reads and writes) to the queue
16567ea0b7cSTomas Krcka 	 * are complete before we update the cons pointer.
16667ea0b7cSTomas Krcka 	 */
16767ea0b7cSTomas Krcka 	__iomb();
1682a8868f1SWill Deacon 	writel_relaxed(q->llq.cons, q->cons_reg);
16948ec83bcSWill Deacon }
170a76a3777SZhou Wang 
queue_inc_cons(struct arm_smmu_ll_queue * q)17148ec83bcSWill Deacon static void queue_inc_cons(struct arm_smmu_ll_queue *q)
172a76a3777SZhou Wang {
173a76a3777SZhou Wang 	u32 cons = (Q_WRP(q, q->cons) | Q_IDX(q, q->cons)) + 1;
174a76a3777SZhou Wang 	q->cons = Q_OVF(q->cons) | Q_WRP(q, cons) | Q_IDX(q, cons);
175a76a3777SZhou Wang }
176a76a3777SZhou Wang 
queue_sync_cons_ovf(struct arm_smmu_queue * q)177a76a3777SZhou Wang static void queue_sync_cons_ovf(struct arm_smmu_queue *q)
178a76a3777SZhou Wang {
17948ec83bcSWill Deacon 	struct arm_smmu_ll_queue *llq = &q->llq;
18052be8637SWill Deacon 
18148ec83bcSWill Deacon 	if (likely(Q_OVF(llq->prod) == Q_OVF(llq->cons)))
18248ec83bcSWill Deacon 		return;
18352be8637SWill Deacon 
18448ec83bcSWill Deacon 	llq->cons = Q_OVF(llq->prod) | Q_WRP(llq, llq->cons) |
18548ec83bcSWill Deacon 		      Q_IDX(llq, llq->cons);
18648ec83bcSWill Deacon 	queue_sync_cons_out(q);
187587e6c10SWill Deacon }
18848ec83bcSWill Deacon 
queue_sync_prod_in(struct arm_smmu_queue * q)189587e6c10SWill Deacon static int queue_sync_prod_in(struct arm_smmu_queue *q)
190587e6c10SWill Deacon {
19148ec83bcSWill Deacon 	u32 prod;
19248ec83bcSWill Deacon 	int ret = 0;
193587e6c10SWill Deacon 
194587e6c10SWill Deacon 	/*
19548ec83bcSWill Deacon 	 * We can't use the _relaxed() variant here, as we must prevent
196587e6c10SWill Deacon 	 * speculative reads of the queue before we have determined that
197587e6c10SWill Deacon 	 * prod has indeed moved.
198587e6c10SWill Deacon 	 */
199587e6c10SWill Deacon 	prod = readl(q->prod_reg);
20048ec83bcSWill Deacon 
201b847de4eSSunil Goutham 	if (Q_OVF(prod) != Q_OVF(q->llq.prod))
202587e6c10SWill Deacon 		ret = -EOVERFLOW;
20348ec83bcSWill Deacon 
204587e6c10SWill Deacon 	q->llq.prod = prod;
20548ec83bcSWill Deacon 	return ret;
20648ec83bcSWill Deacon }
207587e6c10SWill Deacon 
queue_inc_prod_n(struct arm_smmu_ll_queue * q,int n)20848ec83bcSWill Deacon static u32 queue_inc_prod_n(struct arm_smmu_ll_queue *q, int n)
209587e6c10SWill Deacon {
21048ec83bcSWill Deacon 	u32 prod = (Q_WRP(q, q->prod) | Q_IDX(q, q->prod)) + n;
2118ff0f723SRobin Murphy 	return Q_OVF(q->prod) | Q_WRP(q, prod) | Q_IDX(q, prod);
212587e6c10SWill Deacon }
213587e6c10SWill Deacon 
queue_poll_init(struct arm_smmu_device * smmu,struct arm_smmu_queue_poll * qp)214587e6c10SWill Deacon static void queue_poll_init(struct arm_smmu_device *smmu,
21548ec83bcSWill Deacon 			    struct arm_smmu_queue_poll *qp)
21648ec83bcSWill Deacon {
21748ec83bcSWill Deacon 	qp->delay = 1;
21848ec83bcSWill Deacon 	qp->spin_cnt = 0;
21948ec83bcSWill Deacon 	qp->wfe = !!(smmu->features & ARM_SMMU_FEAT_SEV);
22048ec83bcSWill Deacon 	qp->timeout = ktime_add_us(ktime_get(), ARM_SMMU_POLL_TIMEOUT_US);
22148ec83bcSWill Deacon }
22248ec83bcSWill Deacon 
queue_poll(struct arm_smmu_queue_poll * qp)22348ec83bcSWill Deacon static int queue_poll(struct arm_smmu_queue_poll *qp)
22448ec83bcSWill Deacon {
22548ec83bcSWill Deacon 	if (ktime_compare(ktime_get(), qp->timeout) > 0)
22648ec83bcSWill Deacon 		return -ETIMEDOUT;
22748ec83bcSWill Deacon 
228376cdf66SJean-Philippe Brucker 	if (qp->wfe) {
22948ec83bcSWill Deacon 		wfe();
23048ec83bcSWill Deacon 	} else if (++qp->spin_cnt < ARM_SMMU_POLL_SPIN_COUNT) {
23148ec83bcSWill Deacon 		cpu_relax();
23248ec83bcSWill Deacon 	} else {
23348ec83bcSWill Deacon 		udelay(qp->delay);
23448ec83bcSWill Deacon 		qp->delay *= 2;
23548ec83bcSWill Deacon 		qp->spin_cnt = 0;
23648ec83bcSWill Deacon 	}
23748ec83bcSWill Deacon 
2387c288a5bSWill Deacon 	return 0;
23948ec83bcSWill Deacon }
24048ec83bcSWill Deacon 
queue_write(__le64 * dst,u64 * src,size_t n_dwords)24152be8637SWill Deacon static void queue_write(__le64 *dst, u64 *src, size_t n_dwords)
2427c288a5bSWill Deacon {
2432a8868f1SWill Deacon 	int i;
24448ec83bcSWill Deacon 
24548ec83bcSWill Deacon 	for (i = 0; i < n_dwords; ++i)
24648ec83bcSWill Deacon 		*dst++ = cpu_to_le64(*src++);
24748ec83bcSWill Deacon }
24848ec83bcSWill Deacon 
queue_read(u64 * dst,__le64 * src,size_t n_dwords)24948ec83bcSWill Deacon static void queue_read(u64 *dst, __le64 *src, size_t n_dwords)
250d25f6eadSWill Deacon {
2517417b99cSRobin Murphy 	int i;
25248ec83bcSWill Deacon 
25348ec83bcSWill Deacon 	for (i = 0; i < n_dwords; ++i)
25448ec83bcSWill Deacon 		*dst++ = le64_to_cpu(*src++);
25548ec83bcSWill Deacon }
25648ec83bcSWill Deacon 
queue_remove_raw(struct arm_smmu_queue * q,u64 * ent)25748ec83bcSWill Deacon static int queue_remove_raw(struct arm_smmu_queue *q, u64 *ent)
2587417b99cSRobin Murphy {
25948ec83bcSWill Deacon 	if (queue_empty(&q->llq))
26087f42391SJean-Philippe Brucker 		return -EAGAIN;
26187f42391SJean-Philippe Brucker 
262df561f66SGustavo A. R. Silva 	queue_read(ent, Q_ENT(q, q->llq.cons), q->ent_dwords);
26348ec83bcSWill Deacon 	queue_inc_cons(&q->llq);
2647417b99cSRobin Murphy 	queue_sync_cons_out(q);
2657417b99cSRobin Murphy 	return 0;
26648ec83bcSWill Deacon }
26787f42391SJean-Philippe Brucker 
26887f42391SJean-Philippe Brucker /* High-level queue accessors */
arm_smmu_cmdq_build_cmd(u64 * cmd,struct arm_smmu_cmdq_ent * ent)26987f42391SJean-Philippe Brucker static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
27048ec83bcSWill Deacon {
27148ec83bcSWill Deacon 	memset(cmd, 0, 1 << CMDQ_ENT_SZ_SHIFT);
2727417b99cSRobin Murphy 	cmd[0] |= FIELD_PREP(CMDQ_0_OP, ent->opcode);
27348ec83bcSWill Deacon 
27448ec83bcSWill Deacon 	switch (ent->opcode) {
2759111aebfSJean-Philippe Brucker 	case CMDQ_OP_TLBI_EL2_ALL:
2769111aebfSJean-Philippe Brucker 	case CMDQ_OP_TLBI_NSNH_ALL:
2779111aebfSJean-Philippe Brucker 		break;
2786a481a95SRob Herring 	case CMDQ_OP_PREFETCH_CFG:
2796a481a95SRob Herring 		cmd[0] |= FIELD_PREP(CMDQ_PREFETCH_0_SID, ent->prefetch.sid);
2807417b99cSRobin Murphy 		break;
2817417b99cSRobin Murphy 	case CMDQ_OP_CFGI_CD:
2826a481a95SRob Herring 		cmd[0] |= FIELD_PREP(CMDQ_CFGI_0_SSID, ent->cfgi.ssid);
2836a481a95SRob Herring 		fallthrough;
2841c27df1cSWill Deacon 	case CMDQ_OP_CFGI_STE:
2851c27df1cSWill Deacon 		cmd[0] |= FIELD_PREP(CMDQ_CFGI_0_SID, ent->cfgi.sid);
28648ec83bcSWill Deacon 		cmd[1] |= FIELD_PREP(CMDQ_CFGI_1_LEAF, ent->cfgi.leaf);
2876a481a95SRob Herring 		break;
2886a481a95SRob Herring 	case CMDQ_OP_CFGI_CD_ALL:
2897417b99cSRobin Murphy 		cmd[0] |= FIELD_PREP(CMDQ_CFGI_0_SID, ent->cfgi.sid);
2907417b99cSRobin Murphy 		break;
2916a481a95SRob Herring 	case CMDQ_OP_CFGI_ALL:
2926a481a95SRob Herring 		/* Cover the entire SID range */
2931c27df1cSWill Deacon 		cmd[1] |= FIELD_PREP(CMDQ_CFGI_1_RANGE, 31);
29448ec83bcSWill Deacon 		break;
29548ec83bcSWill Deacon 	case CMDQ_OP_TLBI_NH_VA:
2967417b99cSRobin Murphy 		cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid);
297df561f66SGustavo A. R. Silva 		fallthrough;
2981e8be08dSJason Gunthorpe 	case CMDQ_OP_TLBI_EL2_VA:
29948ec83bcSWill Deacon 		cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_NUM, ent->tlbi.num);
3007417b99cSRobin Murphy 		cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_SCALE, ent->tlbi.scale);
30148ec83bcSWill Deacon 		cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_ASID, ent->tlbi.asid);
3029111aebfSJean-Philippe Brucker 		cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_LEAF, ent->tlbi.leaf);
3039111aebfSJean-Philippe Brucker 		cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_TTL, ent->tlbi.ttl);
3049111aebfSJean-Philippe Brucker 		cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_TG, ent->tlbi.tg);
3059ce27afcSJean-Philippe Brucker 		cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_VA_MASK;
3069ce27afcSJean-Philippe Brucker 		break;
3079ce27afcSJean-Philippe Brucker 	case CMDQ_OP_TLBI_S2_IPA:
3089ce27afcSJean-Philippe Brucker 		cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_NUM, ent->tlbi.num);
3099ce27afcSJean-Philippe Brucker 		cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_SCALE, ent->tlbi.scale);
3109ce27afcSJean-Philippe Brucker 		cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid);
3119ce27afcSJean-Philippe Brucker 		cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_LEAF, ent->tlbi.leaf);
3129ce27afcSJean-Philippe Brucker 		cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_TTL, ent->tlbi.ttl);
31348ec83bcSWill Deacon 		cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_TG, ent->tlbi.tg);
3147417b99cSRobin Murphy 		cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_IPA_MASK;
3157417b99cSRobin Murphy 		break;
3167417b99cSRobin Murphy 	case CMDQ_OP_TLBI_NH_ASID:
3177417b99cSRobin Murphy 		cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_ASID, ent->tlbi.asid);
31848ec83bcSWill Deacon 		fallthrough;
31948ec83bcSWill Deacon 	case CMDQ_OP_TLBI_NH_ALL:
32048ec83bcSWill Deacon 	case CMDQ_OP_TLBI_S12_VMALL:
32148ec83bcSWill Deacon 		cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid);
32248ec83bcSWill Deacon 		break;
32348ec83bcSWill Deacon 	case CMDQ_OP_TLBI_EL2_ASID:
32448ec83bcSWill Deacon 		cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_ASID, ent->tlbi.asid);
32548ec83bcSWill Deacon 		break;
3267417b99cSRobin Murphy 	case CMDQ_OP_ATC_INV:
32748ec83bcSWill Deacon 		cmd[0] |= FIELD_PREP(CMDQ_0_SSV, ent->substream_valid);
328395ad89dSJean-Philippe Brucker 		cmd[0] |= FIELD_PREP(CMDQ_ATC_0_GLOBAL, ent->atc.global);
329395ad89dSJean-Philippe Brucker 		cmd[0] |= FIELD_PREP(CMDQ_ATC_0_SSID, ent->atc.ssid);
330395ad89dSJean-Philippe Brucker 		cmd[0] |= FIELD_PREP(CMDQ_ATC_0_SID, ent->atc.sid);
331395ad89dSJean-Philippe Brucker 		cmd[1] |= FIELD_PREP(CMDQ_ATC_1_SIZE, ent->atc.size);
332395ad89dSJean-Philippe Brucker 		cmd[1] |= ent->atc.addr & CMDQ_ATC_1_ADDR_MASK;
33348ec83bcSWill Deacon 		break;
334587e6c10SWill Deacon 	case CMDQ_OP_PRI_RESP:
3357417b99cSRobin Murphy 		cmd[0] |= FIELD_PREP(CMDQ_0_SSV, ent->substream_valid);
336587e6c10SWill Deacon 		cmd[0] |= FIELD_PREP(CMDQ_PRI_0_SSID, ent->pri.ssid);
337587e6c10SWill Deacon 		cmd[0] |= FIELD_PREP(CMDQ_PRI_0_SID, ent->pri.sid);
3387417b99cSRobin Murphy 		cmd[1] |= FIELD_PREP(CMDQ_PRI_1_GRPID, ent->pri.grpid);
339587e6c10SWill Deacon 		switch (ent->pri.resp) {
3407417b99cSRobin Murphy 		case PRI_RESP_DENY:
3417417b99cSRobin Murphy 		case PRI_RESP_FAIL:
34248ec83bcSWill Deacon 		case PRI_RESP_SUCC:
34348ec83bcSWill Deacon 			break;
34448ec83bcSWill Deacon 		default:
34548ec83bcSWill Deacon 			return -EINVAL;
34648ec83bcSWill Deacon 		}
34748ec83bcSWill Deacon 		cmd[1] |= FIELD_PREP(CMDQ_PRI_1_RESP, ent->pri.resp);
34848ec83bcSWill Deacon 		break;
34948ec83bcSWill Deacon 	case CMDQ_OP_RESUME:
350a9d40285SNicolin Chen 		cmd[0] |= FIELD_PREP(CMDQ_RESUME_0_SID, ent->resume.sid);
351a9d40285SNicolin Chen 		cmd[0] |= FIELD_PREP(CMDQ_RESUME_0_RESP, ent->resume.resp);
352587e6c10SWill Deacon 		cmd[1] |= FIELD_PREP(CMDQ_RESUME_1_STAG, ent->resume.stag);
3536de80d61SJason Gunthorpe 		break;
3546de80d61SJason Gunthorpe 	case CMDQ_OP_CMD_SYNC:
3556de80d61SJason Gunthorpe 		if (ent->sync.msiaddr) {
356a9d40285SNicolin Chen 			cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_IRQ);
3576de80d61SJason Gunthorpe 			cmd[1] |= ent->sync.msiaddr & CMDQ_SYNC_1_MSIADDR_MASK;
3586de80d61SJason Gunthorpe 		} else {
3598639cc83SZhen Lei 			cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_CS, CMDQ_SYNC_0_CS_SEV);
3608639cc83SZhen Lei 		}
361b935a5b1SNicolin Chen 		cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSH, ARM_SMMU_SH_ISH);
362b935a5b1SNicolin Chen 		cmd[0] |= FIELD_PREP(CMDQ_SYNC_0_MSIATTR, ARM_SMMU_MEMATTR_OIWB);
363b935a5b1SNicolin Chen 		break;
364b935a5b1SNicolin Chen 	default:
365b935a5b1SNicolin Chen 		return -ENOENT;
366b935a5b1SNicolin Chen 	}
367b935a5b1SNicolin Chen 
3688639cc83SZhen Lei 	return 0;
3698639cc83SZhen Lei }
3708639cc83SZhen Lei 
arm_smmu_get_cmdq(struct arm_smmu_device * smmu,struct arm_smmu_cmdq_ent * ent)3712ea1f012SNicolin Chen static struct arm_smmu_cmdq *arm_smmu_get_cmdq(struct arm_smmu_device *smmu,
3728639cc83SZhen Lei 					       struct arm_smmu_cmdq_ent *ent)
3732ea1f012SNicolin Chen {
374587e6c10SWill Deacon 	struct arm_smmu_cmdq *cmdq = NULL;
375587e6c10SWill Deacon 
376587e6c10SWill Deacon 	if (smmu->impl_ops && smmu->impl_ops->get_secondary_cmdq)
377587e6c10SWill Deacon 		cmdq = smmu->impl_ops->get_secondary_cmdq(smmu, ent);
378587e6c10SWill Deacon 
379587e6c10SWill Deacon 	return cmdq ?: &smmu->cmdq;
380587e6c10SWill Deacon }
381587e6c10SWill Deacon 
arm_smmu_cmdq_needs_busy_polling(struct arm_smmu_device * smmu,struct arm_smmu_cmdq * cmdq)382bd07a20aSBarry Song static bool arm_smmu_cmdq_needs_busy_polling(struct arm_smmu_device *smmu,
383587e6c10SWill Deacon 					     struct arm_smmu_cmdq *cmdq)
384587e6c10SWill Deacon {
385587e6c10SWill Deacon 	if (cmdq == &smmu->cmdq)
386587e6c10SWill Deacon 		return false;
387587e6c10SWill Deacon 
388b935a5b1SNicolin Chen 	return smmu->options & ARM_SMMU_OPT_TEGRA241_CMDQV;
389b935a5b1SNicolin Chen }
390587e6c10SWill Deacon 
arm_smmu_cmdq_build_sync_cmd(u64 * cmd,struct arm_smmu_device * smmu,struct arm_smmu_cmdq * cmdq,u32 prod)391587e6c10SWill Deacon static void arm_smmu_cmdq_build_sync_cmd(u64 *cmd, struct arm_smmu_device *smmu,
392a7a08b85SNicolin Chen 					 struct arm_smmu_cmdq *cmdq, u32 prod)
3932ea1f012SNicolin Chen {
39448ec83bcSWill Deacon 	struct arm_smmu_queue *q = &cmdq->q;
395d56d5162SBixuan Cui 	struct arm_smmu_cmdq_ent ent = {
39648ec83bcSWill Deacon 		.opcode = CMDQ_OP_CMD_SYNC,
39748ec83bcSWill Deacon 	};
39848ec83bcSWill Deacon 
3999ce27afcSJean-Philippe Brucker 	/*
40048ec83bcSWill Deacon 	 * Beware that Hi16xx adds an extra 32 bits of goodness to its MSI
4012ea1f012SNicolin Chen 	 * payload, so the write will zero the entire command on that platform.
40248ec83bcSWill Deacon 	 */
40348ec83bcSWill Deacon 	if (smmu->options & ARM_SMMU_OPT_MSIPOLL) {
40448ec83bcSWill Deacon 		ent.sync.msiaddr = q->base_dma + Q_IDX(&q->llq, prod) *
40548ec83bcSWill Deacon 				   q->ent_dwords * 8;
406cbcee19aSRobin Murphy 	}
40748ec83bcSWill Deacon 
40848ec83bcSWill Deacon 	arm_smmu_cmdq_build_cmd(cmd, &ent);
40948ec83bcSWill Deacon 	if (arm_smmu_cmdq_needs_busy_polling(smmu, cmdq))
41048ec83bcSWill Deacon 		u64p_replace_bits(cmd, CMDQ_SYNC_0_CS_NONE, CMDQ_SYNC_0_CS);
41148ec83bcSWill Deacon }
412a0d5c04cSWill Deacon 
__arm_smmu_cmdq_skip_err(struct arm_smmu_device * smmu,struct arm_smmu_cmdq * cmdq)41348ec83bcSWill Deacon void __arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu,
41448ec83bcSWill Deacon 			      struct arm_smmu_cmdq *cmdq)
41548ec83bcSWill Deacon {
41648ec83bcSWill Deacon 	static const char * const cerror_str[] = {
4175a1ab5c0SGustavo A. R. Silva 		[CMDQ_ERR_CERROR_NONE_IDX]	= "No error",
41848ec83bcSWill Deacon 		[CMDQ_ERR_CERROR_ILL_IDX]	= "Illegal command",
41948ec83bcSWill Deacon 		[CMDQ_ERR_CERROR_ABT_IDX]	= "Abort on command fetch",
4209ce27afcSJean-Philippe Brucker 		[CMDQ_ERR_CERROR_ATC_INV_IDX]	= "ATC invalidate timeout",
4219ce27afcSJean-Philippe Brucker 	};
4229ce27afcSJean-Philippe Brucker 	struct arm_smmu_queue *q = &cmdq->q;
4239ce27afcSJean-Philippe Brucker 
4249ce27afcSJean-Philippe Brucker 	int i;
4259ce27afcSJean-Philippe Brucker 	u64 cmd[CMDQ_ENT_DWORDS];
4269ce27afcSJean-Philippe Brucker 	u32 cons = readl_relaxed(q->cons_reg);
4279ce27afcSJean-Philippe Brucker 	u32 idx = FIELD_GET(CMDQ_CONS_ERR, cons);
428a0d5c04cSWill Deacon 	struct arm_smmu_cmdq_ent cmd_sync = {
429a0d5c04cSWill Deacon 		.opcode = CMDQ_OP_CMD_SYNC,
430a0d5c04cSWill Deacon 	};
43148ec83bcSWill Deacon 
43248ec83bcSWill Deacon 	dev_err(smmu->dev, "CMDQ error (cons 0x%08x): %s\n", cons,
43348ec83bcSWill Deacon 		idx < ARRAY_SIZE(cerror_str) ?  cerror_str[idx] : "Unknown");
43448ec83bcSWill Deacon 
43548ec83bcSWill Deacon 	switch (idx) {
43648ec83bcSWill Deacon 	case CMDQ_ERR_CERROR_ABT_IDX:
437aea2037eSWill Deacon 		dev_err(smmu->dev, "retrying command fetch\n");
43848ec83bcSWill Deacon 		return;
43948ec83bcSWill Deacon 	case CMDQ_ERR_CERROR_NONE_IDX:
44048ec83bcSWill Deacon 		return;
44148ec83bcSWill Deacon 	case CMDQ_ERR_CERROR_ATC_INV_IDX:
44248ec83bcSWill Deacon 		/*
44359d9bd72SZhen Lei 		 * ATC Invalidation Completion timeout. CONS is still pointing
444b935a5b1SNicolin Chen 		 * at the CMD_SYNC. Attempt to complete other pending commands
445b935a5b1SNicolin Chen 		 * by repeating the CMD_SYNC, though we might well end up back
44648ec83bcSWill Deacon 		 * here since the ATC invalidation may still be pending.
447aea2037eSWill Deacon 		 */
44848ec83bcSWill Deacon 		return;
44948ec83bcSWill Deacon 	case CMDQ_ERR_CERROR_ILL_IDX:
4502cbeaf3fSZhen Lei 	default:
4512cbeaf3fSZhen Lei 		break;
4522ea1f012SNicolin Chen 	}
4532cbeaf3fSZhen Lei 
4542cbeaf3fSZhen Lei 	/*
455587e6c10SWill Deacon 	 * We may have concurrent producers, so we need to be careful
456587e6c10SWill Deacon 	 * not to touch any of the shadow cmdq state.
457587e6c10SWill Deacon 	 */
458587e6c10SWill Deacon 	queue_read(cmd, Q_ENT(q, cons), q->ent_dwords);
459587e6c10SWill Deacon 	dev_err(smmu->dev, "skipping command in error state:\n");
460587e6c10SWill Deacon 	for (i = 0; i < ARRAY_SIZE(cmd); ++i)
461587e6c10SWill Deacon 		dev_err(smmu->dev, "\t0x%016llx\n", (unsigned long long)cmd[i]);
462587e6c10SWill Deacon 
463587e6c10SWill Deacon 	/* Convert the erroneous command into a CMD_SYNC */
464587e6c10SWill Deacon 	arm_smmu_cmdq_build_cmd(cmd, &cmd_sync);
465587e6c10SWill Deacon 	if (arm_smmu_cmdq_needs_busy_polling(smmu, cmdq))
466587e6c10SWill Deacon 		u64p_replace_bits(cmd, CMDQ_SYNC_0_CS_NONE, CMDQ_SYNC_0_CS);
467587e6c10SWill Deacon 
4682f657addSRobin Murphy 	queue_write(Q_ENT(q, cons), cmd, q->ent_dwords);
469587e6c10SWill Deacon }
4702f657addSRobin Murphy 
arm_smmu_cmdq_skip_err(struct arm_smmu_device * smmu)471587e6c10SWill Deacon static void arm_smmu_cmdq_skip_err(struct arm_smmu_device *smmu)
472587e6c10SWill Deacon {
473587e6c10SWill Deacon 	__arm_smmu_cmdq_skip_err(smmu, &smmu->cmdq);
474587e6c10SWill Deacon }
475587e6c10SWill Deacon 
476587e6c10SWill Deacon /*
477587e6c10SWill Deacon  * Command queue locking.
478587e6c10SWill Deacon  * This is a form of bastardised rwlock with the following major changes:
479901510eeSZhen Lei  *
480587e6c10SWill Deacon  * - The only LOCK routines are exclusive_trylock() and shared_lock().
481587e6c10SWill Deacon  *   Neither have barrier semantics, and instead provide only a control
482587e6c10SWill Deacon  *   dependency.
483587e6c10SWill Deacon  *
484587e6c10SWill Deacon  * - The UNLOCK routines are supplemented with shared_tryunlock(), which
485587e6c10SWill Deacon  *   fails if the caller appears to be the last lock holder (yes, this is
486587e6c10SWill Deacon  *   racy). All successful UNLOCK routines have RELEASE semantics.
487587e6c10SWill Deacon  */
arm_smmu_cmdq_shared_lock(struct arm_smmu_cmdq * cmdq)488587e6c10SWill Deacon static void arm_smmu_cmdq_shared_lock(struct arm_smmu_cmdq *cmdq)
489587e6c10SWill Deacon {
490587e6c10SWill Deacon 	int val;
491587e6c10SWill Deacon 
492587e6c10SWill Deacon 	/*
493587e6c10SWill Deacon 	 * We can try to avoid the cmpxchg() loop by simply incrementing the
494587e6c10SWill Deacon 	 * lock counter. When held in exclusive state, the lock counter is set
495587e6c10SWill Deacon 	 * to INT_MIN so these increments won't hurt as the value will remain
496587e6c10SWill Deacon 	 * negative.
497587e6c10SWill Deacon 	 */
498587e6c10SWill Deacon 	if (atomic_fetch_inc_relaxed(&cmdq->lock) >= 0)
499587e6c10SWill Deacon 		return;
500587e6c10SWill Deacon 
501587e6c10SWill Deacon 	do {
502587e6c10SWill Deacon 		val = atomic_cond_read_relaxed(&cmdq->lock, VAL >= 0);
503587e6c10SWill Deacon 	} while (atomic_cmpxchg_relaxed(&cmdq->lock, val, val + 1) != val);
504587e6c10SWill Deacon }
505587e6c10SWill Deacon 
arm_smmu_cmdq_shared_unlock(struct arm_smmu_cmdq * cmdq)506587e6c10SWill Deacon static void arm_smmu_cmdq_shared_unlock(struct arm_smmu_cmdq *cmdq)
507587e6c10SWill Deacon {
508587e6c10SWill Deacon 	(void)atomic_dec_return_release(&cmdq->lock);
509587e6c10SWill Deacon }
510587e6c10SWill Deacon 
arm_smmu_cmdq_shared_tryunlock(struct arm_smmu_cmdq * cmdq)511587e6c10SWill Deacon static bool arm_smmu_cmdq_shared_tryunlock(struct arm_smmu_cmdq *cmdq)
512587e6c10SWill Deacon {
513587e6c10SWill Deacon 	if (atomic_read(&cmdq->lock) == 1)
514587e6c10SWill Deacon 		return false;
515587e6c10SWill Deacon 
516587e6c10SWill Deacon 	arm_smmu_cmdq_shared_unlock(cmdq);
517587e6c10SWill Deacon 	return true;
518587e6c10SWill Deacon }
519587e6c10SWill Deacon 
520587e6c10SWill Deacon #define arm_smmu_cmdq_exclusive_trylock_irqsave(cmdq, flags)		\
521587e6c10SWill Deacon ({									\
522587e6c10SWill Deacon 	bool __ret;							\
523587e6c10SWill Deacon 	local_irq_save(flags);						\
524587e6c10SWill Deacon 	__ret = !atomic_cmpxchg_relaxed(&cmdq->lock, 0, INT_MIN);	\
525587e6c10SWill Deacon 	if (!__ret)							\
526587e6c10SWill Deacon 		local_irq_restore(flags);				\
527587e6c10SWill Deacon 	__ret;								\
528587e6c10SWill Deacon })
529587e6c10SWill Deacon 
530587e6c10SWill Deacon #define arm_smmu_cmdq_exclusive_unlock_irqrestore(cmdq, flags)		\
531587e6c10SWill Deacon ({									\
532587e6c10SWill Deacon 	atomic_set_release(&cmdq->lock, 0);				\
533587e6c10SWill Deacon 	local_irq_restore(flags);					\
534587e6c10SWill Deacon })
535587e6c10SWill Deacon 
536587e6c10SWill Deacon 
537587e6c10SWill Deacon /*
538587e6c10SWill Deacon  * Command queue insertion.
539587e6c10SWill Deacon  * This is made fiddly by our attempts to achieve some sort of scalability
540587e6c10SWill Deacon  * since there is one queue shared amongst all of the CPUs in the system.  If
541587e6c10SWill Deacon  * you like mixed-size concurrency, dependency ordering and relaxed atomics,
542587e6c10SWill Deacon  * then you'll *love* this monstrosity.
543587e6c10SWill Deacon  *
544587e6c10SWill Deacon  * The basic idea is to split the queue up into ranges of commands that are
545587e6c10SWill Deacon  * owned by a given CPU; the owner may not have written all of the commands
546587e6c10SWill Deacon  * itself, but is responsible for advancing the hardware prod pointer when
547587e6c10SWill Deacon  * the time comes. The algorithm is roughly:
548587e6c10SWill Deacon  *
549587e6c10SWill Deacon  * 	1. Allocate some space in the queue. At this point we also discover
550587e6c10SWill Deacon  *	   whether the head of the queue is currently owned by another CPU,
551587e6c10SWill Deacon  *	   or whether we are the owner.
552587e6c10SWill Deacon  *
553587e6c10SWill Deacon  *	2. Write our commands into our allocated slots in the queue.
554587e6c10SWill Deacon  *
555587e6c10SWill Deacon  *	3. Mark our slots as valid in arm_smmu_cmdq.valid_map.
556587e6c10SWill Deacon  *
557587e6c10SWill Deacon  *	4. If we are an owner:
558587e6c10SWill Deacon  *		a. Wait for the previous owner to finish.
559587e6c10SWill Deacon  *		b. Mark the queue head as unowned, which tells us the range
560587e6c10SWill Deacon  *		   that we are responsible for publishing.
561587e6c10SWill Deacon  *		c. Wait for all commands in our owned range to become valid.
562587e6c10SWill Deacon  *		d. Advance the hardware prod pointer.
563587e6c10SWill Deacon  *		e. Tell the next owner we've finished.
564587e6c10SWill Deacon  *
565587e6c10SWill Deacon  *	5. If we are inserting a CMD_SYNC (we may or may not have been an
566587e6c10SWill Deacon  *	   owner), then we need to stick around until it has completed:
567587e6c10SWill Deacon  *		a. If we have MSIs, the SMMU can write back into the CMD_SYNC
568587e6c10SWill Deacon  *		   to clear the first 4 bytes.
569587e6c10SWill Deacon  *		b. Otherwise, we spin waiting for the hardware cons pointer to
570587e6c10SWill Deacon  *		   advance past our command.
571587e6c10SWill Deacon  *
572587e6c10SWill Deacon  * The devil is in the details, particularly the use of locking for handling
573587e6c10SWill Deacon  * SYNC completion and freeing up space in the queue before we think that it is
574587e6c10SWill Deacon  * full.
575587e6c10SWill Deacon  */
__arm_smmu_cmdq_poll_set_valid_map(struct arm_smmu_cmdq * cmdq,u32 sprod,u32 eprod,bool set)576587e6c10SWill Deacon static void __arm_smmu_cmdq_poll_set_valid_map(struct arm_smmu_cmdq *cmdq,
577587e6c10SWill Deacon 					       u32 sprod, u32 eprod, bool set)
578587e6c10SWill Deacon {
579587e6c10SWill Deacon 	u32 swidx, sbidx, ewidx, ebidx;
580587e6c10SWill Deacon 	struct arm_smmu_ll_queue llq = {
581587e6c10SWill Deacon 		.max_n_shift	= cmdq->q.llq.max_n_shift,
582587e6c10SWill Deacon 		.prod		= sprod,
583587e6c10SWill Deacon 	};
584587e6c10SWill Deacon 
585587e6c10SWill Deacon 	ewidx = BIT_WORD(Q_IDX(&llq, eprod));
586587e6c10SWill Deacon 	ebidx = Q_IDX(&llq, eprod) % BITS_PER_LONG;
587587e6c10SWill Deacon 
588587e6c10SWill Deacon 	while (llq.prod != eprod) {
589587e6c10SWill Deacon 		unsigned long mask;
590587e6c10SWill Deacon 		atomic_long_t *ptr;
591587e6c10SWill Deacon 		u32 limit = BITS_PER_LONG;
592587e6c10SWill Deacon 
593587e6c10SWill Deacon 		swidx = BIT_WORD(Q_IDX(&llq, llq.prod));
594587e6c10SWill Deacon 		sbidx = Q_IDX(&llq, llq.prod) % BITS_PER_LONG;
595587e6c10SWill Deacon 
596587e6c10SWill Deacon 		ptr = &cmdq->valid_map[swidx];
597587e6c10SWill Deacon 
598587e6c10SWill Deacon 		if ((swidx == ewidx) && (sbidx < ebidx))
599587e6c10SWill Deacon 			limit = ebidx;
600587e6c10SWill Deacon 
601587e6c10SWill Deacon 		mask = GENMASK(limit - 1, sbidx);
602587e6c10SWill Deacon 
603587e6c10SWill Deacon 		/*
604587e6c10SWill Deacon 		 * The valid bit is the inverse of the wrap bit. This means
605587e6c10SWill Deacon 		 * that a zero-initialised queue is invalid and, after marking
606587e6c10SWill Deacon 		 * all entries as valid, they become invalid again when we
607587e6c10SWill Deacon 		 * wrap.
608587e6c10SWill Deacon 		 */
609587e6c10SWill Deacon 		if (set) {
610587e6c10SWill Deacon 			atomic_long_xor(mask, ptr);
611587e6c10SWill Deacon 		} else { /* Poll */
612587e6c10SWill Deacon 			unsigned long valid;
613587e6c10SWill Deacon 
614587e6c10SWill Deacon 			valid = (ULONG_MAX + !!Q_WRP(&llq, llq.prod)) & mask;
615587e6c10SWill Deacon 			atomic_long_cond_read_relaxed(ptr, (VAL & mask) == valid);
616587e6c10SWill Deacon 		}
61756ae8866SNicolin Chen 
618587e6c10SWill Deacon 		llq.prod = queue_inc_prod_n(&llq, limit - sbidx);
619587e6c10SWill Deacon 	}
620587e6c10SWill Deacon }
621587e6c10SWill Deacon 
622587e6c10SWill Deacon /* Mark all entries in the range [sprod, eprod) as valid */
arm_smmu_cmdq_set_valid_map(struct arm_smmu_cmdq * cmdq,u32 sprod,u32 eprod)623587e6c10SWill Deacon static void arm_smmu_cmdq_set_valid_map(struct arm_smmu_cmdq *cmdq,
624587e6c10SWill Deacon 					u32 sprod, u32 eprod)
625587e6c10SWill Deacon {
626587e6c10SWill Deacon 	__arm_smmu_cmdq_poll_set_valid_map(cmdq, sprod, eprod, true);
627587e6c10SWill Deacon }
628587e6c10SWill Deacon 
629587e6c10SWill Deacon /* Wait for all entries in the range [sprod, eprod) to become valid */
arm_smmu_cmdq_poll_valid_map(struct arm_smmu_cmdq * cmdq,u32 sprod,u32 eprod)630587e6c10SWill Deacon static void arm_smmu_cmdq_poll_valid_map(struct arm_smmu_cmdq *cmdq,
631587e6c10SWill Deacon 					 u32 sprod, u32 eprod)
632587e6c10SWill Deacon {
633587e6c10SWill Deacon 	__arm_smmu_cmdq_poll_set_valid_map(cmdq, sprod, eprod, false);
634587e6c10SWill Deacon }
635587e6c10SWill Deacon 
636587e6c10SWill Deacon /* Wait for the command queue to become non-full */
arm_smmu_cmdq_poll_until_not_full(struct arm_smmu_device * smmu,struct arm_smmu_cmdq * cmdq,struct arm_smmu_ll_queue * llq)6378639cc83SZhen Lei static int arm_smmu_cmdq_poll_until_not_full(struct arm_smmu_device *smmu,
638587e6c10SWill Deacon 					     struct arm_smmu_cmdq *cmdq,
639587e6c10SWill Deacon 					     struct arm_smmu_ll_queue *llq)
640587e6c10SWill Deacon {
641587e6c10SWill Deacon 	unsigned long flags;
642587e6c10SWill Deacon 	struct arm_smmu_queue_poll qp;
643587e6c10SWill Deacon 	int ret = 0;
644587e6c10SWill Deacon 
645587e6c10SWill Deacon 	/*
646587e6c10SWill Deacon 	 * Try to update our copy of cons by grabbing exclusive cmdq access. If
647587e6c10SWill Deacon 	 * that fails, spin until somebody else updates it for us.
648587e6c10SWill Deacon 	 */
649587e6c10SWill Deacon 	if (arm_smmu_cmdq_exclusive_trylock_irqsave(cmdq, flags)) {
650587e6c10SWill Deacon 		WRITE_ONCE(cmdq->q.llq.cons, readl_relaxed(cmdq->q.cons_reg));
651587e6c10SWill Deacon 		arm_smmu_cmdq_exclusive_unlock_irqrestore(cmdq, flags);
65256ae8866SNicolin Chen 		llq->val = READ_ONCE(cmdq->q.llq.val);
653587e6c10SWill Deacon 		return 0;
654587e6c10SWill Deacon 	}
655587e6c10SWill Deacon 
656587e6c10SWill Deacon 	queue_poll_init(smmu, &qp);
657587e6c10SWill Deacon 	do {
658587e6c10SWill Deacon 		llq->val = READ_ONCE(cmdq->q.llq.val);
659587e6c10SWill Deacon 		if (!queue_full(llq))
660587e6c10SWill Deacon 			break;
661587e6c10SWill Deacon 
662587e6c10SWill Deacon 		ret = queue_poll(&qp);
663587e6c10SWill Deacon 	} while (!ret);
664587e6c10SWill Deacon 
665587e6c10SWill Deacon 	return ret;
666587e6c10SWill Deacon }
667587e6c10SWill Deacon 
668587e6c10SWill Deacon /*
669587e6c10SWill Deacon  * Wait until the SMMU signals a CMD_SYNC completion MSI.
670587e6c10SWill Deacon  * Must be called with the cmdq lock held in some capacity.
671587e6c10SWill Deacon  */
__arm_smmu_cmdq_poll_until_msi(struct arm_smmu_device * smmu,struct arm_smmu_cmdq * cmdq,struct arm_smmu_ll_queue * llq)672587e6c10SWill Deacon static int __arm_smmu_cmdq_poll_until_msi(struct arm_smmu_device *smmu,
673587e6c10SWill Deacon 					  struct arm_smmu_cmdq *cmdq,
674587e6c10SWill Deacon 					  struct arm_smmu_ll_queue *llq)
675587e6c10SWill Deacon {
67656ae8866SNicolin Chen 	int ret = 0;
677587e6c10SWill Deacon 	struct arm_smmu_queue_poll qp;
678587e6c10SWill Deacon 	u32 *cmd = (u32 *)(Q_ENT(&cmdq->q, llq->prod));
679587e6c10SWill Deacon 
680587e6c10SWill Deacon 	queue_poll_init(smmu, &qp);
681587e6c10SWill Deacon 
682587e6c10SWill Deacon 	/*
683587e6c10SWill Deacon 	 * The MSI won't generate an event, since it's being written back
6848639cc83SZhen Lei 	 * into the command queue.
685587e6c10SWill Deacon 	 */
686587e6c10SWill Deacon 	qp.wfe = false;
687587e6c10SWill Deacon 	smp_cond_load_relaxed(cmd, !VAL || (ret = queue_poll(&qp)));
688587e6c10SWill Deacon 	llq->cons = ret ? llq->prod : queue_inc_prod_n(llq, 1);
689587e6c10SWill Deacon 	return ret;
690587e6c10SWill Deacon }
691587e6c10SWill Deacon 
692587e6c10SWill Deacon /*
693587e6c10SWill Deacon  * Wait until the SMMU cons index passes llq->prod.
694587e6c10SWill Deacon  * Must be called with the cmdq lock held in some capacity.
695587e6c10SWill Deacon  */
__arm_smmu_cmdq_poll_until_consumed(struct arm_smmu_device * smmu,struct arm_smmu_cmdq * cmdq,struct arm_smmu_ll_queue * llq)696587e6c10SWill Deacon static int __arm_smmu_cmdq_poll_until_consumed(struct arm_smmu_device *smmu,
697587e6c10SWill Deacon 					       struct arm_smmu_cmdq *cmdq,
698587e6c10SWill Deacon 					       struct arm_smmu_ll_queue *llq)
699587e6c10SWill Deacon {
700587e6c10SWill Deacon 	struct arm_smmu_queue_poll qp;
701587e6c10SWill Deacon 	u32 prod = llq->prod;
702587e6c10SWill Deacon 	int ret = 0;
703587e6c10SWill Deacon 
704587e6c10SWill Deacon 	queue_poll_init(smmu, &qp);
705587e6c10SWill Deacon 	llq->val = READ_ONCE(cmdq->q.llq.val);
706587e6c10SWill Deacon 	do {
707587e6c10SWill Deacon 		if (queue_consumed(llq, prod))
708587e6c10SWill Deacon 			break;
709587e6c10SWill Deacon 
710587e6c10SWill Deacon 		ret = queue_poll(&qp);
711587e6c10SWill Deacon 
712587e6c10SWill Deacon 		/*
713587e6c10SWill Deacon 		 * This needs to be a readl() so that our subsequent call
714587e6c10SWill Deacon 		 * to arm_smmu_cmdq_shared_tryunlock() can fail accurately.
715587e6c10SWill Deacon 		 *
716587e6c10SWill Deacon 		 * Specifically, we need to ensure that we observe all
717587e6c10SWill Deacon 		 * shared_lock()s by other CMD_SYNCs that share our owner,
718587e6c10SWill Deacon 		 * so that a failing call to tryunlock() means that we're
719587e6c10SWill Deacon 		 * the last one out and therefore we can safely advance
720587e6c10SWill Deacon 		 * cmdq->q.llq.cons. Roughly speaking:
721587e6c10SWill Deacon 		 *
722587e6c10SWill Deacon 		 * CPU 0		CPU1			CPU2 (us)
723587e6c10SWill Deacon 		 *
724587e6c10SWill Deacon 		 * if (sync)
725587e6c10SWill Deacon 		 * 	shared_lock();
72656ae8866SNicolin Chen 		 *
727587e6c10SWill Deacon 		 * dma_wmb();
728587e6c10SWill Deacon 		 * set_valid_map();
729b935a5b1SNicolin Chen 		 *
730b935a5b1SNicolin Chen 		 * 			if (owner) {
73156ae8866SNicolin Chen 		 *				poll_valid_map();
732587e6c10SWill Deacon 		 *				<control dependency>
73356ae8866SNicolin Chen 		 *				writel(prod_reg);
734587e6c10SWill Deacon 		 *
735587e6c10SWill Deacon 		 *						readl(cons_reg);
736587e6c10SWill Deacon 		 *						tryunlock();
737587e6c10SWill Deacon 		 *
738587e6c10SWill Deacon 		 * Requires us to see CPU 0's shared_lock() acquisition.
739587e6c10SWill Deacon 		 */
740587e6c10SWill Deacon 		llq->cons = readl(cmdq->q.cons_reg);
741587e6c10SWill Deacon 	} while (!ret);
742587e6c10SWill Deacon 
743587e6c10SWill Deacon 	return ret;
744587e6c10SWill Deacon }
745587e6c10SWill Deacon 
arm_smmu_cmdq_poll_until_sync(struct arm_smmu_device * smmu,struct arm_smmu_cmdq * cmdq,struct arm_smmu_ll_queue * llq)746587e6c10SWill Deacon static int arm_smmu_cmdq_poll_until_sync(struct arm_smmu_device *smmu,
747587e6c10SWill Deacon 					 struct arm_smmu_cmdq *cmdq,
748587e6c10SWill Deacon 					 struct arm_smmu_ll_queue *llq)
749587e6c10SWill Deacon {
750587e6c10SWill Deacon 	if (smmu->options & ARM_SMMU_OPT_MSIPOLL &&
751587e6c10SWill Deacon 	    !arm_smmu_cmdq_needs_busy_polling(smmu, cmdq))
752587e6c10SWill Deacon 		return __arm_smmu_cmdq_poll_until_msi(smmu, cmdq, llq);
75305cbaf4dSWill Deacon 
75405cbaf4dSWill Deacon 	return __arm_smmu_cmdq_poll_until_consumed(smmu, cmdq, llq);
75505cbaf4dSWill Deacon }
75605cbaf4dSWill Deacon 
arm_smmu_cmdq_write_entries(struct arm_smmu_cmdq * cmdq,u64 * cmds,u32 prod,int n)75705cbaf4dSWill Deacon static void arm_smmu_cmdq_write_entries(struct arm_smmu_cmdq *cmdq, u64 *cmds,
75805cbaf4dSWill Deacon 					u32 prod, int n)
75905cbaf4dSWill Deacon {
76005cbaf4dSWill Deacon 	int i;
76105cbaf4dSWill Deacon 	struct arm_smmu_ll_queue llq = {
76205cbaf4dSWill Deacon 		.max_n_shift	= cmdq->q.llq.max_n_shift,
76305cbaf4dSWill Deacon 		.prod		= prod,
76405cbaf4dSWill Deacon 	};
76505cbaf4dSWill Deacon 
76605cbaf4dSWill Deacon 	for (i = 0; i < n; ++i) {
76705cbaf4dSWill Deacon 		u64 *cmd = &cmds[i * CMDQ_ENT_DWORDS];
76805cbaf4dSWill Deacon 
769d68beb27SNicolin Chen 		prod = queue_inc_prod_n(&llq, i);
770d68beb27SNicolin Chen 		queue_write(Q_ENT(&cmdq->q, prod), cmd, CMDQ_ENT_DWORDS);
771d68beb27SNicolin Chen 	}
772587e6c10SWill Deacon }
773587e6c10SWill Deacon 
774587e6c10SWill Deacon /*
775587e6c10SWill Deacon  * This is the actual insertion function, and provides the following
776587e6c10SWill Deacon  * ordering guarantees to callers:
7775c08c5acSJohn Garry  *
778587e6c10SWill Deacon  * - There is a dma_wmb() before publishing any commands to the queue.
779587e6c10SWill Deacon  *   This can be relied upon to order prior writes to data structures
7805c08c5acSJohn Garry  *   in memory (such as a CD or an STE) before the command.
7815c08c5acSJohn Garry  *
782587e6c10SWill Deacon  * - On completion of a CMD_SYNC, there is a control dependency.
783587e6c10SWill Deacon  *   This can be relied upon to order subsequent writes to memory (e.g.
784587e6c10SWill Deacon  *   freeing an IOVA) after completion of the CMD_SYNC.
785587e6c10SWill Deacon  *
786587e6c10SWill Deacon  * - Command insertion is totally ordered, so if two CPUs each race to
787587e6c10SWill Deacon  *   insert their own list of commands then all of the commands from one
788587e6c10SWill Deacon  *   CPU will appear before any of the commands from the other CPU.
789587e6c10SWill Deacon  */
arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device * smmu,struct arm_smmu_cmdq * cmdq,u64 * cmds,int n,bool sync)79056ae8866SNicolin Chen int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu,
7912f657addSRobin Murphy 				struct arm_smmu_cmdq *cmdq, u64 *cmds, int n,
792587e6c10SWill Deacon 				bool sync)
793587e6c10SWill Deacon {
794587e6c10SWill Deacon 	u64 cmd_sync[CMDQ_ENT_DWORDS];
795587e6c10SWill Deacon 	u32 prod;
796587e6c10SWill Deacon 	unsigned long flags;
797587e6c10SWill Deacon 	bool owner;
798587e6c10SWill Deacon 	struct arm_smmu_ll_queue llq, head;
799587e6c10SWill Deacon 	int ret = 0;
800587e6c10SWill Deacon 
801587e6c10SWill Deacon 	llq.max_n_shift = cmdq->q.llq.max_n_shift;
802587e6c10SWill Deacon 
803587e6c10SWill Deacon 	/* 1. Allocate some space in the queue */
804587e6c10SWill Deacon 	local_irq_save(flags);
805587e6c10SWill Deacon 	llq.val = READ_ONCE(cmdq->q.llq.val);
806587e6c10SWill Deacon 	do {
807587e6c10SWill Deacon 		u64 old;
808587e6c10SWill Deacon 
809587e6c10SWill Deacon 		while (!queue_has_space(&llq, n + sync)) {
810587e6c10SWill Deacon 			local_irq_restore(flags);
811587e6c10SWill Deacon 			if (arm_smmu_cmdq_poll_until_not_full(smmu, cmdq, &llq))
812587e6c10SWill Deacon 				dev_err_ratelimited(smmu->dev, "CMDQ timeout\n");
813587e6c10SWill Deacon 			local_irq_save(flags);
814587e6c10SWill Deacon 		}
815587e6c10SWill Deacon 
8162ea1f012SNicolin Chen 		head.cons = llq.cons;
817587e6c10SWill Deacon 		head.prod = queue_inc_prod_n(&llq, n + sync) |
818587e6c10SWill Deacon 					     CMDQ_PROD_OWNED_FLAG;
819587e6c10SWill Deacon 
820587e6c10SWill Deacon 		old = cmpxchg_relaxed(&cmdq->q.llq.val, llq.val, head.val);
821587e6c10SWill Deacon 		if (old == llq.val)
822587e6c10SWill Deacon 			break;
823587e6c10SWill Deacon 
824587e6c10SWill Deacon 		llq.val = old;
825587e6c10SWill Deacon 	} while (1);
826587e6c10SWill Deacon 	owner = !(llq.prod & CMDQ_PROD_OWNED_FLAG);
827587e6c10SWill Deacon 	head.prod &= ~CMDQ_PROD_OWNED_FLAG;
828587e6c10SWill Deacon 	llq.prod &= ~CMDQ_PROD_OWNED_FLAG;
829587e6c10SWill Deacon 
830587e6c10SWill Deacon 	/*
831587e6c10SWill Deacon 	 * 2. Write our commands into the queue
832587e6c10SWill Deacon 	 * Dependency ordering from the cmpxchg() loop above.
833587e6c10SWill Deacon 	 */
834587e6c10SWill Deacon 	arm_smmu_cmdq_write_entries(cmdq, cmds, llq.prod, n);
835587e6c10SWill Deacon 	if (sync) {
836587e6c10SWill Deacon 		prod = queue_inc_prod_n(&llq, n);
837587e6c10SWill Deacon 		arm_smmu_cmdq_build_sync_cmd(cmd_sync, smmu, cmdq, prod);
838587e6c10SWill Deacon 		queue_write(Q_ENT(&cmdq->q, prod), cmd_sync, CMDQ_ENT_DWORDS);
839587e6c10SWill Deacon 
840587e6c10SWill Deacon 		/*
841587e6c10SWill Deacon 		 * In order to determine completion of our CMD_SYNC, we must
842587e6c10SWill Deacon 		 * ensure that the queue can't wrap twice without us noticing.
843587e6c10SWill Deacon 		 * We achieve that by taking the cmdq lock as shared before
844587e6c10SWill Deacon 		 * marking our slot as valid.
845587e6c10SWill Deacon 		 */
846587e6c10SWill Deacon 		arm_smmu_cmdq_shared_lock(cmdq);
847587e6c10SWill Deacon 	}
848587e6c10SWill Deacon 
849587e6c10SWill Deacon 	/* 3. Mark our slots as valid, ensuring commands are visible first */
850587e6c10SWill Deacon 	dma_wmb();
851587e6c10SWill Deacon 	arm_smmu_cmdq_set_valid_map(cmdq, llq.prod, head.prod);
852587e6c10SWill Deacon 
853587e6c10SWill Deacon 	/* 4. If we are the owner, take control of the SMMU hardware */
854587e6c10SWill Deacon 	if (owner) {
855587e6c10SWill Deacon 		/* a. Wait for previous owner to finish */
856587e6c10SWill Deacon 		atomic_cond_read_relaxed(&cmdq->owner_prod, VAL == llq.prod);
857587e6c10SWill Deacon 
858587e6c10SWill Deacon 		/* b. Stop gathering work by clearing the owned flag */
859587e6c10SWill Deacon 		prod = atomic_fetch_andnot_relaxed(CMDQ_PROD_OWNED_FLAG,
860587e6c10SWill Deacon 						   &cmdq->q.llq.atomic.prod);
861587e6c10SWill Deacon 		prod &= ~CMDQ_PROD_OWNED_FLAG;
862587e6c10SWill Deacon 
863587e6c10SWill Deacon 		/*
864587e6c10SWill Deacon 		 * c. Wait for any gathered work to be written to the queue.
865587e6c10SWill Deacon 		 * Note that we read our own entries so that we have the control
86656ae8866SNicolin Chen 		 * dependency required by (d).
867587e6c10SWill Deacon 		 */
868587e6c10SWill Deacon 		arm_smmu_cmdq_poll_valid_map(cmdq, llq.prod, prod);
869587e6c10SWill Deacon 
870587e6c10SWill Deacon 		/*
871587e6c10SWill Deacon 		 * d. Advance the hardware prod pointer
872587e6c10SWill Deacon 		 * Control dependency ordering from the entries becoming valid.
873587e6c10SWill Deacon 		 */
874587e6c10SWill Deacon 		writel_relaxed(prod, cmdq->q.prod_reg);
875587e6c10SWill Deacon 
87649fbb250SJohn Garry 		/*
877587e6c10SWill Deacon 		 * e. Tell the next owner we're done
878587e6c10SWill Deacon 		 * Make sure we've updated the hardware first, so that we don't
879587e6c10SWill Deacon 		 * race to update prod and potentially move it backwards.
880587e6c10SWill Deacon 		 */
881587e6c10SWill Deacon 		atomic_set_release(&cmdq->owner_prod, prod);
8822f657addSRobin Murphy 	}
8832f657addSRobin Murphy 
8842f657addSRobin Murphy 	/* 5. If we are inserting a CMD_SYNC, we must wait for it to complete */
885587e6c10SWill Deacon 	if (sync) {
886587e6c10SWill Deacon 		llq.prod = queue_inc_prod_n(&llq, n);
887587e6c10SWill Deacon 		ret = arm_smmu_cmdq_poll_until_sync(smmu, cmdq, &llq);
888587e6c10SWill Deacon 		if (ret) {
8894537f6f1SZhen Lei 			dev_err_ratelimited(smmu->dev,
8904537f6f1SZhen Lei 					    "CMD_SYNC timeout at 0x%08x [hwprod 0x%08x, hwcons 0x%08x]\n",
8914537f6f1SZhen Lei 					    llq.prod,
89248ec83bcSWill Deacon 					    readl_relaxed(cmdq->q.prod_reg),
89348ec83bcSWill Deacon 					    readl_relaxed(cmdq->q.cons_reg));
89448ec83bcSWill Deacon 		}
89559d9bd72SZhen Lei 
89648ec83bcSWill Deacon 		/*
89748ec83bcSWill Deacon 		 * Try to unlock the cmdq lock. This will fail if we're the last
898587e6c10SWill Deacon 		 * reader, in which case we can safely update cmdq->q.llq.cons
89948ec83bcSWill Deacon 		 */
90048ec83bcSWill Deacon 		if (!arm_smmu_cmdq_shared_tryunlock(cmdq)) {
90156ae8866SNicolin Chen 			WRITE_ONCE(cmdq->q.llq.cons, llq.cons);
902a9d40285SNicolin Chen 			arm_smmu_cmdq_shared_unlock(cmdq);
90349806599SWill Deacon 		}
90449806599SWill Deacon 	}
9054537f6f1SZhen Lei 
9064537f6f1SZhen Lei 	local_irq_restore(flags);
90749806599SWill Deacon 	return ret;
9084537f6f1SZhen Lei }
9094537f6f1SZhen Lei 
__arm_smmu_cmdq_issue_cmd(struct arm_smmu_device * smmu,struct arm_smmu_cmdq_ent * ent,bool sync)9104537f6f1SZhen Lei static int __arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
9114537f6f1SZhen Lei 				     struct arm_smmu_cmdq_ent *ent,
9124537f6f1SZhen Lei 				     bool sync)
9134537f6f1SZhen Lei {
9144537f6f1SZhen Lei 	u64 cmd[CMDQ_ENT_DWORDS];
91548ec83bcSWill Deacon 
91648ec83bcSWill Deacon 	if (unlikely(arm_smmu_cmdq_build_cmd(cmd, ent))) {
91756ae8866SNicolin Chen 		dev_warn(smmu->dev, "ignoring unknown CMDQ opcode 0x%x\n",
918a9d40285SNicolin Chen 			 ent->opcode);
919a9d40285SNicolin Chen 		return -EINVAL;
92056ae8866SNicolin Chen 	}
92156ae8866SNicolin Chen 
922a9d40285SNicolin Chen 	return arm_smmu_cmdq_issue_cmdlist(
92356ae8866SNicolin Chen 		smmu, arm_smmu_get_cmdq(smmu, ent), cmd, 1, sync);
92456ae8866SNicolin Chen }
9254ce8da45SJean-Philippe Brucker 
arm_smmu_cmdq_issue_cmd(struct arm_smmu_device * smmu,struct arm_smmu_cmdq_ent * ent)9264ce8da45SJean-Philippe Brucker static int arm_smmu_cmdq_issue_cmd(struct arm_smmu_device *smmu,
9274ce8da45SJean-Philippe Brucker 				   struct arm_smmu_cmdq_ent *ent)
9284ce8da45SJean-Philippe Brucker {
929f59e8549SNicolin Chen 	return __arm_smmu_cmdq_issue_cmd(smmu, ent, false);
930f59e8549SNicolin Chen }
931f59e8549SNicolin Chen 
arm_smmu_cmdq_issue_cmd_with_sync(struct arm_smmu_device * smmu,struct arm_smmu_cmdq_ent * ent)93259d9bd72SZhen Lei static int arm_smmu_cmdq_issue_cmd_with_sync(struct arm_smmu_device *smmu,
93359d9bd72SZhen Lei 					     struct arm_smmu_cmdq_ent *ent)
934f59e8549SNicolin Chen {
93556ae8866SNicolin Chen 	return __arm_smmu_cmdq_issue_cmd(smmu, ent, true);
93656ae8866SNicolin Chen }
937a9d40285SNicolin Chen 
arm_smmu_cmdq_batch_init(struct arm_smmu_device * smmu,struct arm_smmu_cmdq_batch * cmds,struct arm_smmu_cmdq_ent * ent)938309a15cbSRobin Murphy static void arm_smmu_cmdq_batch_init(struct arm_smmu_device *smmu,
939309a15cbSRobin Murphy 				     struct arm_smmu_cmdq_batch *cmds,
9404ce8da45SJean-Philippe Brucker 				     struct arm_smmu_cmdq_ent *ent)
94156ae8866SNicolin Chen {
94256ae8866SNicolin Chen 	cmds->num = 0;
943a9d40285SNicolin Chen 	cmds->cmdq = arm_smmu_get_cmdq(smmu, ent);
9444ce8da45SJean-Philippe Brucker }
94559d9bd72SZhen Lei 
arm_smmu_cmdq_batch_add(struct arm_smmu_device * smmu,struct arm_smmu_cmdq_batch * cmds,struct arm_smmu_cmdq_ent * cmd)94659d9bd72SZhen Lei static void arm_smmu_cmdq_batch_add(struct arm_smmu_device *smmu,
94759d9bd72SZhen Lei 				    struct arm_smmu_cmdq_batch *cmds,
94859d9bd72SZhen Lei 				    struct arm_smmu_cmdq_ent *cmd)
94959d9bd72SZhen Lei {
95059d9bd72SZhen Lei 	bool unsupported_cmd = !arm_smmu_cmdq_supports_cmd(cmds->cmdq, cmd);
95159d9bd72SZhen Lei 	bool force_sync = (cmds->num == CMDQ_BATCH_ENTRIES - 1) &&
95259d9bd72SZhen Lei 			  (smmu->options & ARM_SMMU_OPT_CMDQ_FORCE_SYNC);
9534ce8da45SJean-Philippe Brucker 	int index;
9544ce8da45SJean-Philippe Brucker 
9554ce8da45SJean-Philippe Brucker 	if (force_sync || unsupported_cmd) {
9564ce8da45SJean-Philippe Brucker 		arm_smmu_cmdq_issue_cmdlist(smmu, cmds->cmdq, cmds->cmds,
9574ce8da45SJean-Philippe Brucker 					    cmds->num, true);
9584ce8da45SJean-Philippe Brucker 		arm_smmu_cmdq_batch_init(smmu, cmds, cmd);
95956ae8866SNicolin Chen 	}
96056ae8866SNicolin Chen 
9614ce8da45SJean-Philippe Brucker 	if (cmds->num == CMDQ_BATCH_ENTRIES) {
9624ce8da45SJean-Philippe Brucker 		arm_smmu_cmdq_issue_cmdlist(smmu, cmds->cmdq, cmds->cmds,
963b554e396SLu Baolu 					    cmds->num, false);
964395ad89dSJean-Philippe Brucker 		arm_smmu_cmdq_batch_init(smmu, cmds, cmd);
965395ad89dSJean-Philippe Brucker 	}
966395ad89dSJean-Philippe Brucker 
967395ad89dSJean-Philippe Brucker 	index = cmds->num * CMDQ_ENT_DWORDS;
968395ad89dSJean-Philippe Brucker 	if (unlikely(arm_smmu_cmdq_build_cmd(&cmds->cmds[index], cmd))) {
969395ad89dSJean-Philippe Brucker 		dev_warn(smmu->dev, "ignoring unknown CMDQ opcode 0x%x\n",
970b554e396SLu Baolu 			 cmd->opcode);
971b554e396SLu Baolu 		return;
972b554e396SLu Baolu 	}
973395ad89dSJean-Philippe Brucker 
974395ad89dSJean-Philippe Brucker 	cmds->num++;
975395ad89dSJean-Philippe Brucker }
976395ad89dSJean-Philippe Brucker 
arm_smmu_cmdq_batch_submit(struct arm_smmu_device * smmu,struct arm_smmu_cmdq_batch * cmds)977395ad89dSJean-Philippe Brucker static int arm_smmu_cmdq_batch_submit(struct arm_smmu_device *smmu,
978395ad89dSJean-Philippe Brucker 				      struct arm_smmu_cmdq_batch *cmds)
979395ad89dSJean-Philippe Brucker {
980395ad89dSJean-Philippe Brucker 	return arm_smmu_cmdq_issue_cmdlist(smmu, cmds->cmdq, cmds->cmds,
981395ad89dSJean-Philippe Brucker 					   cmds->num, true);
982395ad89dSJean-Philippe Brucker }
983395ad89dSJean-Philippe Brucker 
arm_smmu_page_response(struct device * dev,struct iopf_fault * unused,struct iommu_page_response * resp)984395ad89dSJean-Philippe Brucker static void arm_smmu_page_response(struct device *dev, struct iopf_fault *unused,
985b554e396SLu Baolu 				   struct iommu_page_response *resp)
986395ad89dSJean-Philippe Brucker {
987395ad89dSJean-Philippe Brucker 	struct arm_smmu_cmdq_ent cmd = {0};
988395ad89dSJean-Philippe Brucker 	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
989395ad89dSJean-Philippe Brucker 	int sid = master->streams[0].id;
990395ad89dSJean-Philippe Brucker 
991395ad89dSJean-Philippe Brucker 	if (WARN_ON(!master->stall_enabled))
992395ad89dSJean-Philippe Brucker 		return;
993395ad89dSJean-Philippe Brucker 
994395ad89dSJean-Philippe Brucker 	cmd.opcode		= CMDQ_OP_RESUME;
995395ad89dSJean-Philippe Brucker 	cmd.resume.sid		= sid;
996395ad89dSJean-Philippe Brucker 	cmd.resume.stag		= resp->grpid;
99748ec83bcSWill Deacon 	switch (resp->code) {
9983e630336SJean-Philippe Brucker 	case IOMMU_PAGE_RESP_INVALID:
9993e630336SJean-Philippe Brucker 	case IOMMU_PAGE_RESP_FAILURE:
10003e630336SJean-Philippe Brucker 		cmd.resume.resp = CMDQ_RESUME_0_RESP_ABORT;
10019111aebfSJean-Philippe Brucker 		break;
10029111aebfSJean-Philippe Brucker 	case IOMMU_PAGE_RESP_SUCCESS:
10033e630336SJean-Philippe Brucker 		cmd.resume.resp = CMDQ_RESUME_0_RESP_RETRY;
10043e630336SJean-Philippe Brucker 		break;
10053e630336SJean-Philippe Brucker 	default:
10064537f6f1SZhen Lei 		break;
10073e630336SJean-Philippe Brucker 	}
10083e630336SJean-Philippe Brucker 
10097da51af9SJason Gunthorpe 	arm_smmu_cmdq_issue_cmd(master->smmu, &cmd);
10107da51af9SJason Gunthorpe 	/*
10117da51af9SJason Gunthorpe 	 * Don't send a SYNC, it doesn't do anything for RESUME or PRI_RESP.
10127da51af9SJason Gunthorpe 	 * RESUME consumption guarantees that the stalled transaction will be
10137da51af9SJason Gunthorpe 	 * terminated... at some point in the future. PRI_RESP is fire and
101456e1a4ccSJason Gunthorpe 	 * forget.
101556e1a4ccSJason Gunthorpe 	 */
10167da51af9SJason Gunthorpe }
1017de31c355SJason Gunthorpe 
10187da51af9SJason Gunthorpe /* Context descriptor manipulation functions */
arm_smmu_tlb_inv_asid(struct arm_smmu_device * smmu,u16 asid)1019de31c355SJason Gunthorpe void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid)
1020de31c355SJason Gunthorpe {
10217da51af9SJason Gunthorpe 	struct arm_smmu_cmdq_ent cmd = {
10227da51af9SJason Gunthorpe 		.opcode	= smmu->features & ARM_SMMU_FEAT_E2H ?
1023de31c355SJason Gunthorpe 			CMDQ_OP_TLBI_EL2_ASID : CMDQ_OP_TLBI_NH_ASID,
10247da51af9SJason Gunthorpe 		.tlbi.asid = asid,
10257da51af9SJason Gunthorpe 	};
10267da51af9SJason Gunthorpe 
1027de31c355SJason Gunthorpe 	arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
10287da51af9SJason Gunthorpe }
10297da51af9SJason Gunthorpe 
1030de31c355SJason Gunthorpe /*
10317da51af9SJason Gunthorpe  * Based on the value of ent report which bits of the STE the HW will access. It
10327da51af9SJason Gunthorpe  * would be nice if this was complete according to the spec, but minimally it
10337da51af9SJason Gunthorpe  * has to capture the bits this driver uses.
10347da51af9SJason Gunthorpe  */
1035de31c355SJason Gunthorpe VISIBLE_IF_KUNIT
arm_smmu_get_ste_used(const __le64 * ent,__le64 * used_bits)1036ce26ea9eSJason Gunthorpe void arm_smmu_get_ste_used(const __le64 *ent, __le64 *used_bits)
1037ce26ea9eSJason Gunthorpe {
1038ce26ea9eSJason Gunthorpe 	unsigned int cfg = FIELD_GET(STRTAB_STE_0_CFG, le64_to_cpu(ent[0]));
1039ce26ea9eSJason Gunthorpe 
1040ce26ea9eSJason Gunthorpe 	used_bits[0] = cpu_to_le64(STRTAB_STE_0_V);
1041ce26ea9eSJason Gunthorpe 	if (!(ent[0] & cpu_to_le64(STRTAB_STE_0_V)))
1042ce26ea9eSJason Gunthorpe 		return;
1043ce26ea9eSJason Gunthorpe 
10447da51af9SJason Gunthorpe 	used_bits[0] |= cpu_to_le64(STRTAB_STE_0_CFG);
10457da51af9SJason Gunthorpe 
10467da51af9SJason Gunthorpe 	/* S1 translates */
10477da51af9SJason Gunthorpe 	if (cfg & BIT(0)) {
1048de31c355SJason Gunthorpe 		used_bits[0] |= cpu_to_le64(STRTAB_STE_0_S1FMT |
104967e4fe39SJason Gunthorpe 					    STRTAB_STE_0_S1CTXPTR_MASK |
105067e4fe39SJason Gunthorpe 					    STRTAB_STE_0_S1CDMAX);
1051de31c355SJason Gunthorpe 		used_bits[1] |=
10527da51af9SJason Gunthorpe 			cpu_to_le64(STRTAB_STE_1_S1DSS | STRTAB_STE_1_S1CIR |
10537da51af9SJason Gunthorpe 				    STRTAB_STE_1_S1COR | STRTAB_STE_1_S1CSH |
1054ce7cb08eSMostafa Saleh 				    STRTAB_STE_1_S1STALLD | STRTAB_STE_1_STRW |
1055ce7cb08eSMostafa Saleh 				    STRTAB_STE_1_EATS | STRTAB_STE_1_MEV);
1056de31c355SJason Gunthorpe 		used_bits[2] |= cpu_to_le64(STRTAB_STE_2_S2VMID);
10577da51af9SJason Gunthorpe 
10587da51af9SJason Gunthorpe 		/*
10597da51af9SJason Gunthorpe 		 * See 13.5 Summary of attribute/permission configuration fields
1060de31c355SJason Gunthorpe 		 * for the SHCFG behavior.
10617da51af9SJason Gunthorpe 		 */
1062da55da5aSJason Gunthorpe 		if (FIELD_GET(STRTAB_STE_1_S1DSS, le64_to_cpu(ent[1])) ==
10637da51af9SJason Gunthorpe 		    STRTAB_STE_1_S1DSS_BYPASS)
10647da51af9SJason Gunthorpe 			used_bits[1] |= cpu_to_le64(STRTAB_STE_1_SHCFG);
10657da51af9SJason Gunthorpe 	}
10667da51af9SJason Gunthorpe 
10677da51af9SJason Gunthorpe 	/* S2 translates */
10687da51af9SJason Gunthorpe 	if (cfg & BIT(1)) {
10697da51af9SJason Gunthorpe 		used_bits[1] |=
1070de31c355SJason Gunthorpe 			cpu_to_le64(STRTAB_STE_1_S2FWB | STRTAB_STE_1_EATS |
1071de31c355SJason Gunthorpe 				    STRTAB_STE_1_SHCFG | STRTAB_STE_1_MEV);
1072de31c355SJason Gunthorpe 		used_bits[2] |=
10737da51af9SJason Gunthorpe 			cpu_to_le64(STRTAB_STE_2_S2VMID | STRTAB_STE_2_VTCR |
1074de31c355SJason Gunthorpe 				    STRTAB_STE_2_S2AA64 | STRTAB_STE_2_S2ENDI |
1075de31c355SJason Gunthorpe 				    STRTAB_STE_2_S2PTW | STRTAB_STE_2_S2S |
10767da51af9SJason Gunthorpe 				    STRTAB_STE_2_S2R);
10777da51af9SJason Gunthorpe 		used_bits[3] |= cpu_to_le64(STRTAB_STE_3_S2TTB_MASK);
10787da51af9SJason Gunthorpe 	}
1079de31c355SJason Gunthorpe 
1080de31c355SJason Gunthorpe 	if (cfg == STRTAB_STE_0_CFG_BYPASS)
10817da51af9SJason Gunthorpe 		used_bits[1] |= cpu_to_le64(STRTAB_STE_1_SHCFG);
1082de31c355SJason Gunthorpe }
10837da51af9SJason Gunthorpe EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_ste_used);
10847da51af9SJason Gunthorpe 
10857da51af9SJason Gunthorpe /*
10867da51af9SJason Gunthorpe  * Figure out if we can do a hitless update of entry to become target. Returns a
10877da51af9SJason Gunthorpe  * bit mask where 1 indicates that qword needs to be set disruptively.
1088de31c355SJason Gunthorpe  * unused_update is an intermediate value of entry that has unused bits set to
10897da51af9SJason Gunthorpe  * their new values.
10907da51af9SJason Gunthorpe  */
arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer * writer,const __le64 * entry,const __le64 * target,__le64 * unused_update)1091de31c355SJason Gunthorpe static u8 arm_smmu_entry_qword_diff(struct arm_smmu_entry_writer *writer,
1092de31c355SJason Gunthorpe 				    const __le64 *entry, const __le64 *target,
10937da51af9SJason Gunthorpe 				    __le64 *unused_update)
10947da51af9SJason Gunthorpe {
10957da51af9SJason Gunthorpe 	__le64 target_used[NUM_ENTRY_QWORDS] = {};
10967da51af9SJason Gunthorpe 	__le64 cur_used[NUM_ENTRY_QWORDS] = {};
1097de31c355SJason Gunthorpe 	u8 used_qword_diff = 0;
10987da51af9SJason Gunthorpe 	unsigned int i;
10997da51af9SJason Gunthorpe 
11007da51af9SJason Gunthorpe 	writer->ops->get_used(entry, cur_used);
11017da51af9SJason Gunthorpe 	writer->ops->get_used(target, target_used);
11027da51af9SJason Gunthorpe 
1103de31c355SJason Gunthorpe 	for (i = 0; i != NUM_ENTRY_QWORDS; i++) {
1104de31c355SJason Gunthorpe 		/*
11057da51af9SJason Gunthorpe 		 * Check that masks are up to date, the make functions are not
11067da51af9SJason Gunthorpe 		 * allowed to set a bit to 1 if the used function doesn't say it
11077da51af9SJason Gunthorpe 		 * is used.
11087da51af9SJason Gunthorpe 		 */
11097da51af9SJason Gunthorpe 		WARN_ON_ONCE(target[i] & ~target_used[i]);
11107da51af9SJason Gunthorpe 
1111de31c355SJason Gunthorpe 		/* Bits can change because they are not currently being used */
1112de31c355SJason Gunthorpe 		unused_update[i] = (entry[i] & cur_used[i]) |
11137da51af9SJason Gunthorpe 				   (target[i] & ~cur_used[i]);
11147da51af9SJason Gunthorpe 		/*
11157da51af9SJason Gunthorpe 		 * Each bit indicates that a used bit in a qword needs to be
11167da51af9SJason Gunthorpe 		 * changed after unused_update is applied.
11177da51af9SJason Gunthorpe 		 */
1118de31c355SJason Gunthorpe 		if ((unused_update[i] & target_used[i]) != target[i])
11197da51af9SJason Gunthorpe 			used_qword_diff |= 1 << i;
11207da51af9SJason Gunthorpe 	}
11217da51af9SJason Gunthorpe 	return used_qword_diff;
11227da51af9SJason Gunthorpe }
11237da51af9SJason Gunthorpe 
entry_set(struct arm_smmu_entry_writer * writer,__le64 * entry,const __le64 * target,unsigned int start,unsigned int len)11247da51af9SJason Gunthorpe static bool entry_set(struct arm_smmu_entry_writer *writer, __le64 *entry,
11257da51af9SJason Gunthorpe 		      const __le64 *target, unsigned int start,
11267da51af9SJason Gunthorpe 		      unsigned int len)
11277da51af9SJason Gunthorpe {
11287da51af9SJason Gunthorpe 	bool changed = false;
11297da51af9SJason Gunthorpe 	unsigned int i;
11307da51af9SJason Gunthorpe 
11317da51af9SJason Gunthorpe 	for (i = start; len != 0; len--, i++) {
11327da51af9SJason Gunthorpe 		if (entry[i] != target[i]) {
11337da51af9SJason Gunthorpe 			WRITE_ONCE(entry[i], target[i]);
11347da51af9SJason Gunthorpe 			changed = true;
11357da51af9SJason Gunthorpe 		}
11367da51af9SJason Gunthorpe 	}
11377da51af9SJason Gunthorpe 
11387da51af9SJason Gunthorpe 	if (changed)
11397da51af9SJason Gunthorpe 		writer->ops->sync(writer);
11407da51af9SJason Gunthorpe 	return changed;
11417da51af9SJason Gunthorpe }
11427da51af9SJason Gunthorpe 
11437da51af9SJason Gunthorpe /*
11447da51af9SJason Gunthorpe  * Update the STE/CD to the target configuration. The transition from the
11457da51af9SJason Gunthorpe  * current entry to the target entry takes place over multiple steps that
11467da51af9SJason Gunthorpe  * attempts to make the transition hitless if possible. This function takes care
11477da51af9SJason Gunthorpe  * not to create a situation where the HW can perceive a corrupted entry. HW is
114856e1a4ccSJason Gunthorpe  * only required to have a 64 bit atomicity with stores from the CPU, while
114956e1a4ccSJason Gunthorpe  * entries are many 64 bit values big.
115056e1a4ccSJason Gunthorpe  *
11517da51af9SJason Gunthorpe  * The difference between the current value and the target value is analyzed to
1152de31c355SJason Gunthorpe  * determine which of three updates are required - disruptive, hitless or no
11537da51af9SJason Gunthorpe  * change.
11547da51af9SJason Gunthorpe  *
11557da51af9SJason Gunthorpe  * In the most general disruptive case we can make any update in three steps:
1156de31c355SJason Gunthorpe  *  - Disrupting the entry (V=0)
11577da51af9SJason Gunthorpe  *  - Fill now unused qwords, execpt qword 0 which contains V
11587da51af9SJason Gunthorpe  *  - Make qword 0 have the final value and valid (V=1) with a single 64
11597da51af9SJason Gunthorpe  *    bit store
1160de31c355SJason Gunthorpe  *
1161de31c355SJason Gunthorpe  * However this disrupts the HW while it is happening. There are several
1162de31c355SJason Gunthorpe  * interesting cases where a STE/CD can be updated without disturbing the HW
1163de31c355SJason Gunthorpe  * because only a small number of bits are changing (S1DSS, CONFIG, etc) or
11647da51af9SJason Gunthorpe  * because the used bits don't intersect. We can detect this by calculating how
11657da51af9SJason Gunthorpe  * many 64 bit values need update after adjusting the unused bits and skip the
11667da51af9SJason Gunthorpe  * V=0 process. This relies on the IGNORED behavior described in the
11677da51af9SJason Gunthorpe  * specification.
11687da51af9SJason Gunthorpe  */
11697da51af9SJason Gunthorpe VISIBLE_IF_KUNIT
arm_smmu_write_entry(struct arm_smmu_entry_writer * writer,__le64 * entry,const __le64 * target)11707da51af9SJason Gunthorpe void arm_smmu_write_entry(struct arm_smmu_entry_writer *writer, __le64 *entry,
11717da51af9SJason Gunthorpe 			  const __le64 *target)
1172de31c355SJason Gunthorpe {
1173de31c355SJason Gunthorpe 	__le64 unused_update[NUM_ENTRY_QWORDS];
1174de31c355SJason Gunthorpe 	u8 used_qword_diff;
1175de31c355SJason Gunthorpe 
1176de31c355SJason Gunthorpe 	used_qword_diff =
11777da51af9SJason Gunthorpe 		arm_smmu_entry_qword_diff(writer, entry, target, unused_update);
11787da51af9SJason Gunthorpe 	if (hweight8(used_qword_diff) == 1) {
11797da51af9SJason Gunthorpe 		/*
11807da51af9SJason Gunthorpe 		 * Only one qword needs its used bits to be changed. This is a
11817da51af9SJason Gunthorpe 		 * hitless update, update all bits the current STE/CD is
11827da51af9SJason Gunthorpe 		 * ignoring to their new values, then update a single "critical
1183de31c355SJason Gunthorpe 		 * qword" to change the STE/CD and finally 0 out any bits that
1184de31c355SJason Gunthorpe 		 * are now unused in the target configuration.
1185de31c355SJason Gunthorpe 		 */
1186de31c355SJason Gunthorpe 		unsigned int critical_qword_index = ffs(used_qword_diff) - 1;
11877da51af9SJason Gunthorpe 
11887da51af9SJason Gunthorpe 		/*
11897da51af9SJason Gunthorpe 		 * Skip writing unused bits in the critical qword since we'll be
11907da51af9SJason Gunthorpe 		 * writing it in the next step anyways. This can save a sync
11917da51af9SJason Gunthorpe 		 * when the only change is in that qword.
11927da51af9SJason Gunthorpe 		 */
11937da51af9SJason Gunthorpe 		unused_update[critical_qword_index] =
1194de31c355SJason Gunthorpe 			entry[critical_qword_index];
11957da51af9SJason Gunthorpe 		entry_set(writer, entry, unused_update, 0, NUM_ENTRY_QWORDS);
11967da51af9SJason Gunthorpe 		entry_set(writer, entry, target, critical_qword_index, 1);
1197da55da5aSJason Gunthorpe 		entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS);
11987da51af9SJason Gunthorpe 	} else if (used_qword_diff) {
119924503148SMichael Shavit 		/*
120087f42391SJean-Philippe Brucker 		 * At least two qwords need their inuse bits to be changed. This
120148ec83bcSWill Deacon 		 * requires a breaking update, zero the V bit, write all qwords
120287f42391SJean-Philippe Brucker 		 * but 0, then set qword 0
1203fac95671SJohn Garry 		 */
120424503148SMichael Shavit 		unused_update[0] = 0;
120587f42391SJean-Philippe Brucker 		entry_set(writer, entry, unused_update, 0, 1);
120687f42391SJean-Philippe Brucker 		entry_set(writer, entry, target, 1, NUM_ENTRY_QWORDS - 1);
120787f42391SJean-Philippe Brucker 		entry_set(writer, entry, target, 0, 1);
120887f42391SJean-Philippe Brucker 	} else {
120987f42391SJean-Philippe Brucker 		/*
121087f42391SJean-Philippe Brucker 		 * No inuse bit changed. Sanity check that all unused bits are 0
121187f42391SJean-Philippe Brucker 		 * in the entry. The target was already sanity checked by
121248ec83bcSWill Deacon 		 * compute_qword_diff().
1213a9d40285SNicolin Chen 		 */
1214cdf315f9SJean-Philippe Brucker 		WARN_ON_ONCE(
1215cdf315f9SJean-Philippe Brucker 			entry_set(writer, entry, target, 0, NUM_ENTRY_QWORDS));
1216edd0351eSJean-Philippe Brucker 	}
121787f42391SJean-Philippe Brucker }
121848ec83bcSWill Deacon EXPORT_SYMBOL_IF_KUNIT(arm_smmu_write_entry);
1219edd0351eSJean-Philippe Brucker 
arm_smmu_sync_cd(struct arm_smmu_master * master,int ssid,bool leaf)122048ec83bcSWill Deacon static void arm_smmu_sync_cd(struct arm_smmu_master *master,
122148ec83bcSWill Deacon 			     int ssid, bool leaf)
12227c567eb1SJason Gunthorpe {
12237c567eb1SJason Gunthorpe 	size_t i;
122448ec83bcSWill Deacon 	struct arm_smmu_cmdq_batch cmds;
1225c0a25a96SJason Gunthorpe 	struct arm_smmu_device *smmu = master->smmu;
122673af06f5SJean-Philippe Brucker 	struct arm_smmu_cmdq_ent cmd = {
12277b87c93cSJason Gunthorpe 		.opcode	= CMDQ_OP_CFGI_CD,
12287c567eb1SJason Gunthorpe 		.cfgi	= {
122973af06f5SJean-Philippe Brucker 			.ssid	= ssid,
123073af06f5SJean-Philippe Brucker 			.leaf	= leaf,
12317c567eb1SJason Gunthorpe 		},
1232c0a25a96SJason Gunthorpe 	};
12337c567eb1SJason Gunthorpe 
123473af06f5SJean-Philippe Brucker 	arm_smmu_cmdq_batch_init(smmu, &cmds, &cmd);
123573af06f5SJean-Philippe Brucker 	for (i = 0; i < master->num_streams; i++) {
1236e9d1e4ffSJason Gunthorpe 		cmd.cfgi.sid = master->streams[i].id;
1237e8e4398dSJason Gunthorpe 		arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
123873af06f5SJean-Philippe Brucker 	}
1239e3b1be2eSJason Gunthorpe 
1240475918e9SMichael Shavit 	arm_smmu_cmdq_batch_submit(smmu, &cmds);
124173af06f5SJean-Philippe Brucker }
1242e3b1be2eSJason Gunthorpe 
arm_smmu_write_cd_l1_desc(struct arm_smmu_cdtab_l1 * dst,dma_addr_t l2ptr_dma)1243b2f4c0fcSJason Gunthorpe static void arm_smmu_write_cd_l1_desc(struct arm_smmu_cdtab_l1 *dst,
124473af06f5SJean-Philippe Brucker 				      dma_addr_t l2ptr_dma)
124573af06f5SJean-Philippe Brucker {
1246e3b1be2eSJason Gunthorpe 	u64 val = (l2ptr_dma & CTXDESC_L1_DESC_L2PTR_MASK) | CTXDESC_L1_DESC_V;
124773af06f5SJean-Philippe Brucker 
1248e3b1be2eSJason Gunthorpe 	/* The HW has 64 bit atomicity with stores to the L2 CD table */
1249e3b1be2eSJason Gunthorpe 	WRITE_ONCE(dst->l2ptr, cpu_to_le64(val));
1250b2f4c0fcSJason Gunthorpe }
1251e3b1be2eSJason Gunthorpe 
arm_smmu_cd_l1_get_desc(const struct arm_smmu_cdtab_l1 * src)1252b2f4c0fcSJason Gunthorpe static dma_addr_t arm_smmu_cd_l1_get_desc(const struct arm_smmu_cdtab_l1 *src)
1253b2f4c0fcSJason Gunthorpe {
125485f2fb6eSJason Gunthorpe 	return le64_to_cpu(src->l2ptr) & CTXDESC_L1_DESC_L2PTR_MASK;
1255b2f4c0fcSJason Gunthorpe }
1256b2f4c0fcSJason Gunthorpe 
arm_smmu_get_cd_ptr(struct arm_smmu_master * master,u32 ssid)1257b2f4c0fcSJason Gunthorpe struct arm_smmu_cd *arm_smmu_get_cd_ptr(struct arm_smmu_master *master,
1258b2f4c0fcSJason Gunthorpe 					u32 ssid)
1259b2f4c0fcSJason Gunthorpe {
12607b87c93cSJason Gunthorpe 	struct arm_smmu_cdtab_l2 *l2;
12617b87c93cSJason Gunthorpe 	struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
12627b87c93cSJason Gunthorpe 
1263e3b1be2eSJason Gunthorpe 	if (!arm_smmu_cdtab_allocated(cd_table))
1264b2f4c0fcSJason Gunthorpe 		return NULL;
1265b2f4c0fcSJason Gunthorpe 
1266b2f4c0fcSJason Gunthorpe 	if (cd_table->s1fmt == STRTAB_STE_0_S1FMT_LINEAR)
1267b2f4c0fcSJason Gunthorpe 		return &cd_table->linear.table[ssid];
1268b2f4c0fcSJason Gunthorpe 
12697c567eb1SJason Gunthorpe 	l2 = cd_table->l2.l2ptrs[arm_smmu_cdtab_l1_idx(ssid)];
1270e3b1be2eSJason Gunthorpe 	if (!l2)
1271b2f4c0fcSJason Gunthorpe 		return NULL;
1272e3b1be2eSJason Gunthorpe 	return &l2->cds[arm_smmu_cdtab_l2_idx(ssid)];
1273c0a25a96SJason Gunthorpe }
1274b2f4c0fcSJason Gunthorpe 
arm_smmu_alloc_cd_ptr(struct arm_smmu_master * master,u32 ssid)1275e3b1be2eSJason Gunthorpe static struct arm_smmu_cd *arm_smmu_alloc_cd_ptr(struct arm_smmu_master *master,
1276e3b1be2eSJason Gunthorpe 						 u32 ssid)
1277e3b1be2eSJason Gunthorpe {
127873af06f5SJean-Philippe Brucker 	struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
127973af06f5SJean-Philippe Brucker 	struct arm_smmu_device *smmu = master->smmu;
1280e3b1be2eSJason Gunthorpe 
1281e3b1be2eSJason Gunthorpe 	might_sleep();
128273af06f5SJean-Philippe Brucker 	iommu_group_mutex_assert(master->dev);
128324503148SMichael Shavit 
128473af06f5SJean-Philippe Brucker 	if (!arm_smmu_cdtab_allocated(cd_table)) {
1285b2f4c0fcSJason Gunthorpe 		if (arm_smmu_alloc_cd_tables(master))
1286b2f4c0fcSJason Gunthorpe 			return NULL;
128773af06f5SJean-Philippe Brucker 	}
128873af06f5SJean-Philippe Brucker 
128978a5fbe8SJason Gunthorpe 	if (cd_table->s1fmt == STRTAB_STE_0_S1FMT_64K_L2) {
129078a5fbe8SJason Gunthorpe 		unsigned int idx = arm_smmu_cdtab_l1_idx(ssid);
129178a5fbe8SJason Gunthorpe 		struct arm_smmu_cdtab_l2 **l2ptr = &cd_table->l2.l2ptrs[idx];
129278a5fbe8SJason Gunthorpe 
129378a5fbe8SJason Gunthorpe 		if (!*l2ptr) {
129456e1a4ccSJason Gunthorpe 			dma_addr_t l2ptr_dma;
129556e1a4ccSJason Gunthorpe 
129687f42391SJean-Philippe Brucker 			*l2ptr = dma_alloc_coherent(smmu->dev, sizeof(**l2ptr),
129778a5fbe8SJason Gunthorpe 						    &l2ptr_dma, GFP_KERNEL);
129878a5fbe8SJason Gunthorpe 			if (!*l2ptr)
129978a5fbe8SJason Gunthorpe 				return NULL;
130078a5fbe8SJason Gunthorpe 
130148ec83bcSWill Deacon 			arm_smmu_write_cd_l1_desc(&cd_table->l2.l1tab[idx],
130248ec83bcSWill Deacon 						  l2ptr_dma);
130378a5fbe8SJason Gunthorpe 			/* An invalid L1CD can be cached */
130478a5fbe8SJason Gunthorpe 			arm_smmu_sync_cd(master, ssid, false);
130548ec83bcSWill Deacon 		}
130678a5fbe8SJason Gunthorpe 	}
130778a5fbe8SJason Gunthorpe 	return arm_smmu_get_cd_ptr(master, ssid);
130878a5fbe8SJason Gunthorpe }
130978a5fbe8SJason Gunthorpe 
131078a5fbe8SJason Gunthorpe struct arm_smmu_cd_writer {
131178a5fbe8SJason Gunthorpe 	struct arm_smmu_entry_writer writer;
131278a5fbe8SJason Gunthorpe 	unsigned int ssid;
131378a5fbe8SJason Gunthorpe };
1314da55da5aSJason Gunthorpe 
131587f42391SJean-Philippe Brucker VISIBLE_IF_KUNIT
arm_smmu_get_cd_used(const __le64 * ent,__le64 * used_bits)131678a5fbe8SJason Gunthorpe void arm_smmu_get_cd_used(const __le64 *ent, __le64 *used_bits)
131778a5fbe8SJason Gunthorpe {
131878a5fbe8SJason Gunthorpe 	used_bits[0] = cpu_to_le64(CTXDESC_CD_0_V);
131978a5fbe8SJason Gunthorpe 	if (!(ent[0] & cpu_to_le64(CTXDESC_CD_0_V)))
132078a5fbe8SJason Gunthorpe 		return;
132178a5fbe8SJason Gunthorpe 	memset(used_bits, 0xFF, sizeof(struct arm_smmu_cd));
132278a5fbe8SJason Gunthorpe 
132378a5fbe8SJason Gunthorpe 	/*
132478a5fbe8SJason Gunthorpe 	 * If EPD0 is set by the make function it means
132578a5fbe8SJason Gunthorpe 	 * T0SZ/TG0/IR0/OR0/SH0/TTB0 are IGNORED
132678a5fbe8SJason Gunthorpe 	 */
132778a5fbe8SJason Gunthorpe 	if (ent[0] & cpu_to_le64(CTXDESC_CD_0_TCR_EPD0)) {
132878a5fbe8SJason Gunthorpe 		used_bits[0] &= ~cpu_to_le64(
1329e9d1e4ffSJason Gunthorpe 			CTXDESC_CD_0_TCR_T0SZ | CTXDESC_CD_0_TCR_TG0 |
133078a5fbe8SJason Gunthorpe 			CTXDESC_CD_0_TCR_IRGN0 | CTXDESC_CD_0_TCR_ORGN0 |
133178a5fbe8SJason Gunthorpe 			CTXDESC_CD_0_TCR_SH0);
133278a5fbe8SJason Gunthorpe 		used_bits[1] &= ~cpu_to_le64(CTXDESC_CD_1_TTB0_MASK);
1333be7c90deSJason Gunthorpe 	}
1334be7c90deSJason Gunthorpe }
133578a5fbe8SJason Gunthorpe EXPORT_SYMBOL_IF_KUNIT(arm_smmu_get_cd_used);
133678a5fbe8SJason Gunthorpe 
arm_smmu_cd_writer_sync_entry(struct arm_smmu_entry_writer * writer)133778a5fbe8SJason Gunthorpe static void arm_smmu_cd_writer_sync_entry(struct arm_smmu_entry_writer *writer)
133878a5fbe8SJason Gunthorpe {
133978a5fbe8SJason Gunthorpe 	struct arm_smmu_cd_writer *cd_writer =
134078a5fbe8SJason Gunthorpe 		container_of(writer, struct arm_smmu_cd_writer, writer);
134178a5fbe8SJason Gunthorpe 
134278a5fbe8SJason Gunthorpe 	arm_smmu_sync_cd(writer->master, cd_writer->ssid, true);
1343be7c90deSJason Gunthorpe }
1344be7c90deSJason Gunthorpe 
1345be7c90deSJason Gunthorpe static const struct arm_smmu_entry_writer_ops arm_smmu_cd_writer_ops = {
1346be7c90deSJason Gunthorpe 	.sync = arm_smmu_cd_writer_sync_entry,
1347be7c90deSJason Gunthorpe 	.get_used = arm_smmu_get_cd_used,
1348be7c90deSJason Gunthorpe };
1349be7c90deSJason Gunthorpe 
arm_smmu_write_cd_entry(struct arm_smmu_master * master,int ssid,struct arm_smmu_cd * cdptr,const struct arm_smmu_cd * target)135078a5fbe8SJason Gunthorpe void arm_smmu_write_cd_entry(struct arm_smmu_master *master, int ssid,
135178a5fbe8SJason Gunthorpe 			     struct arm_smmu_cd *cdptr,
135278a5fbe8SJason Gunthorpe 			     const struct arm_smmu_cd *target)
1353e9d1e4ffSJason Gunthorpe {
1354e9d1e4ffSJason Gunthorpe 	bool target_valid = target->data[0] & cpu_to_le64(CTXDESC_CD_0_V);
1355e9d1e4ffSJason Gunthorpe 	bool cur_valid = cdptr->data[0] & cpu_to_le64(CTXDESC_CD_0_V);
1356e9d1e4ffSJason Gunthorpe 	struct arm_smmu_cd_writer cd_writer = {
1357e9d1e4ffSJason Gunthorpe 		.writer = {
135804905c17SJason Gunthorpe 			.ops = &arm_smmu_cd_writer_ops,
135904905c17SJason Gunthorpe 			.master = master,
136004905c17SJason Gunthorpe 		},
136104905c17SJason Gunthorpe 		.ssid = ssid,
1362e9d1e4ffSJason Gunthorpe 	};
1363e9d1e4ffSJason Gunthorpe 
1364e9d1e4ffSJason Gunthorpe 	if (ssid != IOMMU_NO_PASID && cur_valid != target_valid) {
1365e9d1e4ffSJason Gunthorpe 		if (cur_valid)
136604905c17SJason Gunthorpe 			master->cd_table.used_ssids--;
136704905c17SJason Gunthorpe 		else
136804905c17SJason Gunthorpe 			master->cd_table.used_ssids++;
136904905c17SJason Gunthorpe 	}
137004905c17SJason Gunthorpe 
137148ec83bcSWill Deacon 	arm_smmu_write_entry(&cd_writer.writer, cdptr->data, target->data);
137248ec83bcSWill Deacon }
137348ec83bcSWill Deacon 
arm_smmu_make_s1_cd(struct arm_smmu_cd * target,struct arm_smmu_master * master,struct arm_smmu_domain * smmu_domain)137404905c17SJason Gunthorpe void arm_smmu_make_s1_cd(struct arm_smmu_cd *target,
1375e9d1e4ffSJason Gunthorpe 			 struct arm_smmu_master *master,
137604905c17SJason Gunthorpe 			 struct arm_smmu_domain *smmu_domain)
137787f42391SJean-Philippe Brucker {
1378e9d1e4ffSJason Gunthorpe 	struct arm_smmu_ctx_desc *cd = &smmu_domain->cd;
1379e9d1e4ffSJason Gunthorpe 	const struct io_pgtable_cfg *pgtbl_cfg =
1380e9d1e4ffSJason Gunthorpe 		&io_pgtable_ops_to_pgtable(smmu_domain->pgtbl_ops)->cfg;
1381e9d1e4ffSJason Gunthorpe 	typeof(&pgtbl_cfg->arm_lpae_s1_cfg.tcr) tcr =
1382e9d1e4ffSJason Gunthorpe 		&pgtbl_cfg->arm_lpae_s1_cfg.tcr;
1383e9d1e4ffSJason Gunthorpe 
138425c776ddSKunkun Jiang 	memset(target, 0, sizeof(*target));
138525c776ddSKunkun Jiang 
138625c776ddSKunkun Jiang 	target->data[0] = cpu_to_le64(
138725c776ddSKunkun Jiang 		FIELD_PREP(CTXDESC_CD_0_TCR_T0SZ, tcr->tsz) |
138825c776ddSKunkun Jiang 		FIELD_PREP(CTXDESC_CD_0_TCR_TG0, tcr->tg) |
138925c776ddSKunkun Jiang 		FIELD_PREP(CTXDESC_CD_0_TCR_IRGN0, tcr->irgn) |
139004905c17SJason Gunthorpe 		FIELD_PREP(CTXDESC_CD_0_TCR_ORGN0, tcr->orgn) |
139104905c17SJason Gunthorpe 		FIELD_PREP(CTXDESC_CD_0_TCR_SH0, tcr->sh) |
139204905c17SJason Gunthorpe #ifdef __BIG_ENDIAN
139387f42391SJean-Philippe Brucker 		CTXDESC_CD_0_ENDI |
1394da55da5aSJason Gunthorpe #endif
13959cff86fdSYisheng Xie 		CTXDESC_CD_0_TCR_EPD1 |
1396af8f0b83SJason Gunthorpe 		CTXDESC_CD_0_V |
1397af8f0b83SJason Gunthorpe 		FIELD_PREP(CTXDESC_CD_0_TCR_IPS, tcr->ips) |
1398af8f0b83SJason Gunthorpe 		CTXDESC_CD_0_AA64 |
1399af8f0b83SJason Gunthorpe 		(master->stall_enabled ? CTXDESC_CD_0_S : 0) |
1400af8f0b83SJason Gunthorpe 		CTXDESC_CD_0_R |
1401e3b1be2eSJason Gunthorpe 		CTXDESC_CD_0_A |
1402af8f0b83SJason Gunthorpe 		CTXDESC_CD_0_ASET |
1403af8f0b83SJason Gunthorpe 		FIELD_PREP(CTXDESC_CD_0_ASID, cd->asid)
1404af8f0b83SJason Gunthorpe 		);
1405af8f0b83SJason Gunthorpe 
1406af8f0b83SJason Gunthorpe 	/* To enable dirty flag update, set both Access flag and dirty state update */
140748ec83bcSWill Deacon 	if (pgtbl_cfg->quirks & IO_PGTABLE_QUIRK_ARM_HD)
140848ec83bcSWill Deacon 		target->data[0] |= cpu_to_le64(CTXDESC_CD_0_TCR_HA |
140910e4968cSMichael Shavit 					       CTXDESC_CD_0_TCR_HD);
1410a557aff0SJean-Philippe Brucker 
141173af06f5SJean-Philippe Brucker 	target->data[1] = cpu_to_le64(pgtbl_cfg->arm_lpae_s1_cfg.ttbr &
1412a557aff0SJean-Philippe Brucker 				      CTXDESC_CD_1_TTB0_MASK);
141373af06f5SJean-Philippe Brucker 	target->data[3] = cpu_to_le64(pgtbl_cfg->arm_lpae_s1_cfg.mair);
141424503148SMichael Shavit }
1415475918e9SMichael Shavit EXPORT_SYMBOL_IF_KUNIT(arm_smmu_make_s1_cd);
141648ec83bcSWill Deacon 
arm_smmu_clear_cd(struct arm_smmu_master * master,ioasid_t ssid)1417475918e9SMichael Shavit void arm_smmu_clear_cd(struct arm_smmu_master *master, ioasid_t ssid)
1418475918e9SMichael Shavit {
141987f42391SJean-Philippe Brucker 	struct arm_smmu_cd target = {};
142073af06f5SJean-Philippe Brucker 	struct arm_smmu_cd *cdptr;
142173af06f5SJean-Philippe Brucker 
1422475918e9SMichael Shavit 	if (!arm_smmu_cdtab_allocated(&master->cd_table))
1423e3b1be2eSJason Gunthorpe 		return;
142473af06f5SJean-Philippe Brucker 	cdptr = arm_smmu_get_cd_ptr(master, ssid);
14257de7d354SChen Ni 	if (WARN_ON(!cdptr))
1426e3b1be2eSJason Gunthorpe 		return;
1427e3b1be2eSJason Gunthorpe 	arm_smmu_write_cd_entry(master, ssid, cdptr, &target);
1428e3b1be2eSJason Gunthorpe }
1429e3b1be2eSJason Gunthorpe 
arm_smmu_alloc_cd_tables(struct arm_smmu_master * master)1430e3b1be2eSJason Gunthorpe static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master)
143173af06f5SJean-Philippe Brucker {
1432475918e9SMichael Shavit 	int ret;
1433e3b1be2eSJason Gunthorpe 	size_t l1size;
1434e3b1be2eSJason Gunthorpe 	size_t max_contexts;
143573af06f5SJean-Philippe Brucker 	struct arm_smmu_device *smmu = master->smmu;
1436e3b1be2eSJason Gunthorpe 	struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
1437e3b1be2eSJason Gunthorpe 
143873af06f5SJean-Philippe Brucker 	cd_table->s1cdmax = master->ssid_bits;
1439e3b1be2eSJason Gunthorpe 	max_contexts = 1 << cd_table->s1cdmax;
144073af06f5SJean-Philippe Brucker 
144173af06f5SJean-Philippe Brucker 	if (!(smmu->features & ARM_SMMU_FEAT_2_LVL_CDTAB) ||
1442e3b1be2eSJason Gunthorpe 	    max_contexts <= CTXDESC_L2_ENTRIES) {
1443e3b1be2eSJason Gunthorpe 		cd_table->s1fmt = STRTAB_STE_0_S1FMT_LINEAR;
1444e3b1be2eSJason Gunthorpe 		cd_table->linear.num_ents = max_contexts;
1445a557aff0SJean-Philippe Brucker 
1446e3b1be2eSJason Gunthorpe 		l1size = max_contexts * sizeof(struct arm_smmu_cd);
144773af06f5SJean-Philippe Brucker 		cd_table->linear.table = dma_alloc_coherent(smmu->dev, l1size,
1448e3b1be2eSJason Gunthorpe 							    &cd_table->cdtab_dma,
1449a557aff0SJean-Philippe Brucker 							    GFP_KERNEL);
1450e3b1be2eSJason Gunthorpe 		if (!cd_table->linear.table)
1451a557aff0SJean-Philippe Brucker 			return -ENOMEM;
145273af06f5SJean-Philippe Brucker 	} else {
1453e3b1be2eSJason Gunthorpe 		cd_table->s1fmt = STRTAB_STE_0_S1FMT_64K_L2;
1454e3b1be2eSJason Gunthorpe 		cd_table->l2.num_l1_ents =
1455e3b1be2eSJason Gunthorpe 			DIV_ROUND_UP(max_contexts, CTXDESC_L2_ENTRIES);
145673af06f5SJean-Philippe Brucker 
1457a557aff0SJean-Philippe Brucker 		cd_table->l2.l2ptrs = kcalloc(cd_table->l2.num_l1_ents,
1458a557aff0SJean-Philippe Brucker 					     sizeof(*cd_table->l2.l2ptrs),
145910e4968cSMichael Shavit 					     GFP_KERNEL);
1460a557aff0SJean-Philippe Brucker 		if (!cd_table->l2.l2ptrs)
146173af06f5SJean-Philippe Brucker 			return -ENOMEM;
146210e4968cSMichael Shavit 
1463475918e9SMichael Shavit 		l1size = cd_table->l2.num_l1_ents * sizeof(struct arm_smmu_cdtab_l1);
146473af06f5SJean-Philippe Brucker 		cd_table->l2.l1tab = dma_alloc_coherent(smmu->dev, l1size,
1465e3b1be2eSJason Gunthorpe 							&cd_table->cdtab_dma,
1466e3b1be2eSJason Gunthorpe 							GFP_KERNEL);
1467e3b1be2eSJason Gunthorpe 		if (!cd_table->l2.l2ptrs) {
146873af06f5SJean-Philippe Brucker 			ret = -ENOMEM;
146973af06f5SJean-Philippe Brucker 			goto err_free_l2ptrs;
14707c567eb1SJason Gunthorpe 		}
1471e3b1be2eSJason Gunthorpe 	}
1472e3b1be2eSJason Gunthorpe 	return 0;
1473e3b1be2eSJason Gunthorpe 
147473af06f5SJean-Philippe Brucker err_free_l2ptrs:
1475e3b1be2eSJason Gunthorpe 	kfree(cd_table->l2.l2ptrs);
147673af06f5SJean-Philippe Brucker 	cd_table->l2.l2ptrs = NULL;
1477e3b1be2eSJason Gunthorpe 	return ret;
1478e3b1be2eSJason Gunthorpe }
1479e3b1be2eSJason Gunthorpe 
arm_smmu_free_cd_tables(struct arm_smmu_master * master)1480e3b1be2eSJason Gunthorpe static void arm_smmu_free_cd_tables(struct arm_smmu_master *master)
148173af06f5SJean-Philippe Brucker {
1482e3b1be2eSJason Gunthorpe 	int i;
1483e3b1be2eSJason Gunthorpe 	struct arm_smmu_device *smmu = master->smmu;
1484e3b1be2eSJason Gunthorpe 	struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
1485e3b1be2eSJason Gunthorpe 
148673af06f5SJean-Philippe Brucker 	if (cd_table->s1fmt != STRTAB_STE_0_S1FMT_LINEAR) {
148748ec83bcSWill Deacon 		for (i = 0; i < cd_table->l2.num_l1_ents; i++) {
148848ec83bcSWill Deacon 			if (!cd_table->l2.l2ptrs[i])
148948ec83bcSWill Deacon 				continue;
1490abb4f9d3SJason Gunthorpe 
1491abb4f9d3SJason Gunthorpe 			dma_free_coherent(smmu->dev,
149248ec83bcSWill Deacon 					  sizeof(*cd_table->l2.l2ptrs[i]),
149348ec83bcSWill Deacon 					  cd_table->l2.l2ptrs[i],
149448ec83bcSWill Deacon 					  arm_smmu_cd_l1_get_desc(&cd_table->l2.l1tab[i]));
1495a4d75360SJason Gunthorpe 		}
1496a4d75360SJason Gunthorpe 		kfree(cd_table->l2.l2ptrs);
149748ec83bcSWill Deacon 
14987b87c93cSJason Gunthorpe 		dma_free_coherent(smmu->dev,
1499abb4f9d3SJason Gunthorpe 				  cd_table->l2.num_l1_ents *
150048ec83bcSWill Deacon 					  sizeof(struct arm_smmu_cdtab_l1),
150148ec83bcSWill Deacon 				  cd_table->l2.l1tab, cd_table->cdtab_dma);
1502de31c355SJason Gunthorpe 	} else {
1503de31c355SJason Gunthorpe 		dma_free_coherent(smmu->dev,
1504de31c355SJason Gunthorpe 				  cd_table->linear.num_ents *
1505de31c355SJason Gunthorpe 					  sizeof(struct arm_smmu_cd),
1506de31c355SJason Gunthorpe 				  cd_table->linear.table, cd_table->cdtab_dma);
1507de31c355SJason Gunthorpe 	}
150848ec83bcSWill Deacon }
1509de31c355SJason Gunthorpe 
1510de31c355SJason Gunthorpe /* Stream table manipulation functions */
arm_smmu_write_strtab_l1_desc(struct arm_smmu_strtab_l1 * dst,dma_addr_t l2ptr_dma)151148ec83bcSWill Deacon static void arm_smmu_write_strtab_l1_desc(struct arm_smmu_strtab_l1 *dst,
151248ec83bcSWill Deacon 					  dma_addr_t l2ptr_dma)
151348ec83bcSWill Deacon {
1514de31c355SJason Gunthorpe 	u64 val = 0;
151548ec83bcSWill Deacon 
151648ec83bcSWill Deacon 	val |= FIELD_PREP(STRTAB_L1_DESC_SPAN, STRTAB_SPLIT + 1);
151748ec83bcSWill Deacon 	val |= l2ptr_dma & STRTAB_L1_DESC_L2PTR_MASK;
151848ec83bcSWill Deacon 
1519de31c355SJason Gunthorpe 	/* The HW has 64 bit atomicity with stores to the L2 STE table */
152048ec83bcSWill Deacon 	WRITE_ONCE(dst->l2ptr, cpu_to_le64(val));
152148ec83bcSWill Deacon }
1522de31c355SJason Gunthorpe 
1523de31c355SJason Gunthorpe struct arm_smmu_ste_writer {
1524de31c355SJason Gunthorpe 	struct arm_smmu_entry_writer writer;
1525de31c355SJason Gunthorpe 	u32 sid;
1526de31c355SJason Gunthorpe };
1527de31c355SJason Gunthorpe 
arm_smmu_ste_writer_sync_entry(struct arm_smmu_entry_writer * writer)1528de31c355SJason Gunthorpe static void arm_smmu_ste_writer_sync_entry(struct arm_smmu_entry_writer *writer)
1529de31c355SJason Gunthorpe {
1530de31c355SJason Gunthorpe 	struct arm_smmu_ste_writer *ste_writer =
1531de31c355SJason Gunthorpe 		container_of(writer, struct arm_smmu_ste_writer, writer);
1532de31c355SJason Gunthorpe 	struct arm_smmu_cmdq_ent cmd = {
1533de31c355SJason Gunthorpe 		.opcode	= CMDQ_OP_CFGI_STE,
1534de31c355SJason Gunthorpe 		.cfgi	= {
1535de31c355SJason Gunthorpe 			.sid	= ste_writer->sid,
1536de31c355SJason Gunthorpe 			.leaf	= true,
1537de31c355SJason Gunthorpe 		},
1538de31c355SJason Gunthorpe 	};
1539de31c355SJason Gunthorpe 
1540de31c355SJason Gunthorpe 	arm_smmu_cmdq_issue_cmd_with_sync(writer->master->smmu, &cmd);
1541de31c355SJason Gunthorpe }
1542de31c355SJason Gunthorpe 
1543de31c355SJason Gunthorpe static const struct arm_smmu_entry_writer_ops arm_smmu_ste_writer_ops = {
1544de31c355SJason Gunthorpe 	.sync = arm_smmu_ste_writer_sync_entry,
1545de31c355SJason Gunthorpe 	.get_used = arm_smmu_get_ste_used,
1546de31c355SJason Gunthorpe };
1547de31c355SJason Gunthorpe 
arm_smmu_write_ste(struct arm_smmu_master * master,u32 sid,struct arm_smmu_ste * ste,const struct arm_smmu_ste * target)1548de31c355SJason Gunthorpe static void arm_smmu_write_ste(struct arm_smmu_master *master, u32 sid,
1549de31c355SJason Gunthorpe 			       struct arm_smmu_ste *ste,
1550de31c355SJason Gunthorpe 			       const struct arm_smmu_ste *target)
1551de31c355SJason Gunthorpe {
155248ec83bcSWill Deacon 	struct arm_smmu_device *smmu = master->smmu;
155348ec83bcSWill Deacon 	struct arm_smmu_ste_writer ste_writer = {
155456e1a4ccSJason Gunthorpe 		.writer = {
155548ec83bcSWill Deacon 			.ops = &arm_smmu_ste_writer_ops,
15567686aa5fSJason Gunthorpe 			.master = master,
15577686aa5fSJason Gunthorpe 		},
15587686aa5fSJason Gunthorpe 		.sid = sid,
15597686aa5fSJason Gunthorpe 	};
15607686aa5fSJason Gunthorpe 
1561da55da5aSJason Gunthorpe 	arm_smmu_write_entry(&ste_writer.writer, ste->data, target->data);
15627686aa5fSJason Gunthorpe 
156356e1a4ccSJason Gunthorpe 	/* It's likely that we'll want to use the new STE soon */
156456e1a4ccSJason Gunthorpe 	if (!(smmu->options & ARM_SMMU_OPT_SKIP_PREFETCH)) {
1565ec9098d6SMostafa Saleh 		struct arm_smmu_cmdq_ent
15667686aa5fSJason Gunthorpe 			prefetch_cmd = { .opcode = CMDQ_OP_PREFETCH_CFG,
15677686aa5fSJason Gunthorpe 					 .prefetch = {
15687686aa5fSJason Gunthorpe 						 .sid = sid,
15697686aa5fSJason Gunthorpe 					 } };
15707686aa5fSJason Gunthorpe 
1571ec9098d6SMostafa Saleh 		arm_smmu_cmdq_issue_cmd(smmu, &prefetch_cmd);
1572ec9098d6SMostafa Saleh 	}
1573ec9098d6SMostafa Saleh }
1574ec9098d6SMostafa Saleh 
arm_smmu_make_abort_ste(struct arm_smmu_ste * target)15757686aa5fSJason Gunthorpe void arm_smmu_make_abort_ste(struct arm_smmu_ste *target)
1576da55da5aSJason Gunthorpe {
15777686aa5fSJason Gunthorpe 	memset(target, 0, sizeof(*target));
157856e1a4ccSJason Gunthorpe 	target->data[0] = cpu_to_le64(
157956e1a4ccSJason Gunthorpe 		STRTAB_STE_0_V |
1580ce26ea9eSJason Gunthorpe 		FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_ABORT));
1581ce26ea9eSJason Gunthorpe }
1582efe15df0SJason Gunthorpe EXPORT_SYMBOL_IF_KUNIT(arm_smmu_make_abort_ste);
1583efe15df0SJason Gunthorpe 
158412a48fe9SJason Gunthorpe VISIBLE_IF_KUNIT
arm_smmu_make_bypass_ste(struct arm_smmu_device * smmu,struct arm_smmu_ste * target)158548ec83bcSWill Deacon void arm_smmu_make_bypass_ste(struct arm_smmu_device *smmu,
1586efe15df0SJason Gunthorpe 			      struct arm_smmu_ste *target)
1587efe15df0SJason Gunthorpe {
1588efe15df0SJason Gunthorpe 	memset(target, 0, sizeof(*target));
1589efe15df0SJason Gunthorpe 	target->data[0] = cpu_to_le64(
1590efe15df0SJason Gunthorpe 		STRTAB_STE_0_V |
1591efe15df0SJason Gunthorpe 		FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_BYPASS));
1592efe15df0SJason Gunthorpe 
15938be39a1aSJean-Philippe Brucker 	if (smmu->features & ARM_SMMU_FEAT_ATTR_TYPES_OVR)
1594efe15df0SJason Gunthorpe 		target->data[1] = cpu_to_le64(FIELD_PREP(STRTAB_STE_1_SHCFG,
1595ce26ea9eSJason Gunthorpe 							 STRTAB_STE_1_SHCFG_INCOMING));
1596ba08bdcbSRobin Murphy }
1597ba08bdcbSRobin Murphy EXPORT_SYMBOL_IF_KUNIT(arm_smmu_make_bypass_ste);
1598ba08bdcbSRobin Murphy 
1599efe15df0SJason Gunthorpe VISIBLE_IF_KUNIT
arm_smmu_make_cdtable_ste(struct arm_smmu_ste * target,struct arm_smmu_master * master,bool ats_enabled,unsigned int s1dss)1600efe15df0SJason Gunthorpe void arm_smmu_make_cdtable_ste(struct arm_smmu_ste *target,
1601efe15df0SJason Gunthorpe 			       struct arm_smmu_master *master, bool ats_enabled,
1602efe15df0SJason Gunthorpe 			       unsigned int s1dss)
1603efe15df0SJason Gunthorpe {
16047497f421SJason Gunthorpe 	struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
160548ec83bcSWill Deacon 	struct arm_smmu_device *smmu = master->smmu;
1606ce26ea9eSJason Gunthorpe 
1607ce26ea9eSJason Gunthorpe 	memset(target, 0, sizeof(*target));
1608ce26ea9eSJason Gunthorpe 	target->data[0] = cpu_to_le64(
1609ce26ea9eSJason Gunthorpe 		STRTAB_STE_0_V |
1610ce26ea9eSJason Gunthorpe 		FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_S1_TRANS) |
1611efe15df0SJason Gunthorpe 		FIELD_PREP(STRTAB_STE_0_S1FMT, cd_table->s1fmt) |
1612efe15df0SJason Gunthorpe 		(cd_table->cdtab_dma & STRTAB_STE_0_S1CTXPTR_MASK) |
1613efe15df0SJason Gunthorpe 		FIELD_PREP(STRTAB_STE_0_S1CDMAX, cd_table->s1cdmax));
1614efe15df0SJason Gunthorpe 
1615efe15df0SJason Gunthorpe 	target->data[1] = cpu_to_le64(
1616efe15df0SJason Gunthorpe 		FIELD_PREP(STRTAB_STE_1_S1DSS, s1dss) |
1617efe15df0SJason Gunthorpe 		FIELD_PREP(STRTAB_STE_1_S1CIR, STRTAB_STE_1_S1C_CACHE_WBRA) |
1618efe15df0SJason Gunthorpe 		FIELD_PREP(STRTAB_STE_1_S1COR, STRTAB_STE_1_S1C_CACHE_WBRA) |
1619efe15df0SJason Gunthorpe 		FIELD_PREP(STRTAB_STE_1_S1CSH, ARM_SMMU_SH_ISH) |
1620efe15df0SJason Gunthorpe 		((smmu->features & ARM_SMMU_FEAT_STALLS &&
1621efe15df0SJason Gunthorpe 		  !master->stall_enabled) ?
1622efe15df0SJason Gunthorpe 			 STRTAB_STE_1_S1STALLD :
1623efe15df0SJason Gunthorpe 			 0) |
1624efe15df0SJason Gunthorpe 		FIELD_PREP(STRTAB_STE_1_EATS,
16256380be05SPrem Mallappa 			   ats_enabled ? STRTAB_STE_1_EATS_TRANS : 0));
1626efe15df0SJason Gunthorpe 
1627efe15df0SJason Gunthorpe 	if ((smmu->features & ARM_SMMU_FEAT_ATTR_TYPES_OVR) &&
1628efe15df0SJason Gunthorpe 	    s1dss == STRTAB_STE_1_S1DSS_BYPASS)
1629efe15df0SJason Gunthorpe 		target->data[1] |= cpu_to_le64(FIELD_PREP(
1630efe15df0SJason Gunthorpe 			STRTAB_STE_1_SHCFG, STRTAB_STE_1_SHCFG_INCOMING));
1631efe15df0SJason Gunthorpe 
1632efe15df0SJason Gunthorpe 	if (smmu->features & ARM_SMMU_FEAT_E2H) {
163348ec83bcSWill Deacon 		/*
1634da55da5aSJason Gunthorpe 		 * To support BTM the streamworld needs to match the
163548ec83bcSWill Deacon 		 * configuration of the CPU so that the ASID broadcasts are
163656e1a4ccSJason Gunthorpe 		 * properly matched. This means either S/NS-EL2-E2H (hypervisor)
1637efe15df0SJason Gunthorpe 		 * or NS-EL1 (guest). Since an SVA domain can be installed in a
16387497f421SJason Gunthorpe 		 * PASID this should always use a BTM compatible configuration
16397497f421SJason Gunthorpe 		 * if the HW supports it.
1640efe15df0SJason Gunthorpe 		 */
1641efe15df0SJason Gunthorpe 		target->data[1] |= cpu_to_le64(
164271b0aa10SJason Gunthorpe 			FIELD_PREP(STRTAB_STE_1_STRW, STRTAB_STE_1_STRW_EL2));
164371b0aa10SJason Gunthorpe 	} else {
164471b0aa10SJason Gunthorpe 		target->data[1] |= cpu_to_le64(
164571b0aa10SJason Gunthorpe 			FIELD_PREP(STRTAB_STE_1_STRW, STRTAB_STE_1_STRW_NSEL1));
164671b0aa10SJason Gunthorpe 
1647ec9098d6SMostafa Saleh 		/*
1648efe15df0SJason Gunthorpe 		 * VMID 0 is reserved for stage-2 bypass EL1 STEs, see
1649efe15df0SJason Gunthorpe 		 * arm_smmu_domain_alloc_id()
1650efe15df0SJason Gunthorpe 		 */
1651efe15df0SJason Gunthorpe 		target->data[2] =
1652efe15df0SJason Gunthorpe 			cpu_to_le64(FIELD_PREP(STRTAB_STE_2_S2VMID, 0));
1653efe15df0SJason Gunthorpe 	}
1654efe15df0SJason Gunthorpe }
1655efe15df0SJason Gunthorpe EXPORT_SYMBOL_IF_KUNIT(arm_smmu_make_cdtable_ste);
16567497f421SJason Gunthorpe 
arm_smmu_make_s2_domain_ste(struct arm_smmu_ste * target,struct arm_smmu_master * master,struct arm_smmu_domain * smmu_domain,bool ats_enabled)1657ec9098d6SMostafa Saleh void arm_smmu_make_s2_domain_ste(struct arm_smmu_ste *target,
165867e4fe39SJason Gunthorpe 				 struct arm_smmu_master *master,
165967e4fe39SJason Gunthorpe 				 struct arm_smmu_domain *smmu_domain,
1660ec9098d6SMostafa Saleh 				 bool ats_enabled)
1661ec9098d6SMostafa Saleh {
1662efe15df0SJason Gunthorpe 	struct arm_smmu_s2_cfg *s2_cfg = &smmu_domain->s2_cfg;
1663efe15df0SJason Gunthorpe 	const struct io_pgtable_cfg *pgtbl_cfg =
166471b0aa10SJason Gunthorpe 		&io_pgtable_ops_to_pgtable(smmu_domain->pgtbl_ops)->cfg;
166571b0aa10SJason Gunthorpe 	typeof(&pgtbl_cfg->arm_lpae_s2_cfg.vtcr) vtcr =
166671b0aa10SJason Gunthorpe 		&pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
166771b0aa10SJason Gunthorpe 	u64 vtcr_val;
166871b0aa10SJason Gunthorpe 	struct arm_smmu_device *smmu = master->smmu;
166971b0aa10SJason Gunthorpe 
167071b0aa10SJason Gunthorpe 	memset(target, 0, sizeof(*target));
1671efe15df0SJason Gunthorpe 	target->data[0] = cpu_to_le64(
16728be39a1aSJean-Philippe Brucker 		STRTAB_STE_0_V |
167371b0aa10SJason Gunthorpe 		FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_S2_TRANS));
1674efe15df0SJason Gunthorpe 
167548ec83bcSWill Deacon 	target->data[1] = cpu_to_le64(
167648ec83bcSWill Deacon 		FIELD_PREP(STRTAB_STE_1_EATS,
167748ec83bcSWill Deacon 			   ats_enabled ? STRTAB_STE_1_EATS_TRANS : 0));
1678efe15df0SJason Gunthorpe 
1679ce7cb08eSMostafa Saleh 	if (pgtbl_cfg->quirks & IO_PGTABLE_QUIRK_ARM_S2FWB)
168048ec83bcSWill Deacon 		target->data[1] |= cpu_to_le64(STRTAB_STE_1_S2FWB);
168148ec83bcSWill Deacon 	if (smmu->features & ARM_SMMU_FEAT_ATTR_TYPES_OVR)
168271b0aa10SJason Gunthorpe 		target->data[1] |= cpu_to_le64(FIELD_PREP(STRTAB_STE_1_SHCFG,
168371b0aa10SJason Gunthorpe 							  STRTAB_STE_1_SHCFG_INCOMING));
168448ec83bcSWill Deacon 
1685da55da5aSJason Gunthorpe 	vtcr_val = FIELD_PREP(STRTAB_STE_2_VTCR_S2T0SZ, vtcr->tsz) |
168648ec83bcSWill Deacon 		   FIELD_PREP(STRTAB_STE_2_VTCR_S2SL0, vtcr->sl) |
16877686aa5fSJason Gunthorpe 		   FIELD_PREP(STRTAB_STE_2_VTCR_S2IR0, vtcr->irgn) |
16887686aa5fSJason Gunthorpe 		   FIELD_PREP(STRTAB_STE_2_VTCR_S2OR0, vtcr->orgn) |
16897686aa5fSJason Gunthorpe 		   FIELD_PREP(STRTAB_STE_2_VTCR_S2SH0, vtcr->sh) |
16907686aa5fSJason Gunthorpe 		   FIELD_PREP(STRTAB_STE_2_VTCR_S2TG, vtcr->tg) |
1691734554fdSRobin Murphy 		   FIELD_PREP(STRTAB_STE_2_VTCR_S2PS, vtcr->ps);
16927686aa5fSJason Gunthorpe 	target->data[2] = cpu_to_le64(
169348ec83bcSWill Deacon 		FIELD_PREP(STRTAB_STE_2_S2VMID, s2_cfg->vmid) |
169448ec83bcSWill Deacon 		FIELD_PREP(STRTAB_STE_2_VTCR, vtcr_val) |
169548ec83bcSWill Deacon 		STRTAB_STE_2_S2AA64 |
169648ec83bcSWill Deacon #ifdef __BIG_ENDIAN
16977686aa5fSJason Gunthorpe 		STRTAB_STE_2_S2ENDI |
169857b89048SJason Gunthorpe #endif
169948ec83bcSWill Deacon 		STRTAB_STE_2_S2PTW |
170048ec83bcSWill Deacon 		(master->stall_enabled ? STRTAB_STE_2_S2S : 0) |
170148ec83bcSWill Deacon 		STRTAB_STE_2_S2R);
170248ec83bcSWill Deacon 
170348ec83bcSWill Deacon 	target->data[3] = cpu_to_le64(pgtbl_cfg->arm_lpae_s2_cfg.vttbr &
1704a4d75360SJason Gunthorpe 				      STRTAB_STE_3_S2TTB_MASK);
170548ec83bcSWill Deacon }
170685196f54SJason Gunthorpe EXPORT_SYMBOL_IF_KUNIT(arm_smmu_make_s2_domain_ste);
170748ec83bcSWill Deacon 
170885196f54SJason Gunthorpe /*
170985196f54SJason Gunthorpe  * This can safely directly manipulate the STE memory without a sync sequence
171048ec83bcSWill Deacon  * because the STE table has not been installed in the SMMU yet.
171148ec83bcSWill Deacon  */
arm_smmu_init_initial_stes(struct arm_smmu_ste * strtab,unsigned int nent)171285196f54SJason Gunthorpe static void arm_smmu_init_initial_stes(struct arm_smmu_ste *strtab,
1713abb4f9d3SJason Gunthorpe 				       unsigned int nent)
171485196f54SJason Gunthorpe {
171548ec83bcSWill Deacon 	unsigned int i;
171648ec83bcSWill Deacon 
171748ec83bcSWill Deacon 	for (i = 0; i < nent; ++i) {
171848ec83bcSWill Deacon 		arm_smmu_make_abort_ste(strtab);
171948ec83bcSWill Deacon 		strtab++;
172048ec83bcSWill Deacon 	}
172185196f54SJason Gunthorpe }
172285196f54SJason Gunthorpe 
arm_smmu_init_l2_strtab(struct arm_smmu_device * smmu,u32 sid)172385196f54SJason Gunthorpe static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
1724ce410410SJason Gunthorpe {
172548ec83bcSWill Deacon 	dma_addr_t l2ptr_dma;
172648ec83bcSWill Deacon 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
172748ec83bcSWill Deacon 	struct arm_smmu_strtab_l2 **l2table;
1728a2bb820eSJason Gunthorpe 
1729a2bb820eSJason Gunthorpe 	l2table = &cfg->l2.l2ptrs[arm_smmu_strtab_l1_idx(sid)];
1730a2bb820eSJason Gunthorpe 	if (*l2table)
1731a2bb820eSJason Gunthorpe 		return 0;
1732a2bb820eSJason Gunthorpe 
1733a2bb820eSJason Gunthorpe 	*l2table = dmam_alloc_coherent(smmu->dev, sizeof(**l2table),
1734a2bb820eSJason Gunthorpe 				       &l2ptr_dma, GFP_KERNEL);
1735a2bb820eSJason Gunthorpe 	if (!*l2table) {
1736a2bb820eSJason Gunthorpe 		dev_err(smmu->dev,
1737a2bb820eSJason Gunthorpe 			"failed to allocate l2 stream table for SID %u\n",
1738a2bb820eSJason Gunthorpe 			sid);
1739a2bb820eSJason Gunthorpe 		return -ENOMEM;
1740a2bb820eSJason Gunthorpe 	}
1741a2bb820eSJason Gunthorpe 
1742a2bb820eSJason Gunthorpe 	arm_smmu_init_initial_stes((*l2table)->stes,
1743a2bb820eSJason Gunthorpe 				   ARRAY_SIZE((*l2table)->stes));
1744a2bb820eSJason Gunthorpe 	arm_smmu_write_strtab_l1_desc(&cfg->l2.l1tab[arm_smmu_strtab_l1_idx(sid)],
1745a2bb820eSJason Gunthorpe 				      l2ptr_dma);
1746a2bb820eSJason Gunthorpe 	return 0;
1747a2bb820eSJason Gunthorpe }
1748cdf315f9SJean-Philippe Brucker 
arm_smmu_streams_cmp_key(const void * lhs,const struct rb_node * rhs)1749cdf315f9SJean-Philippe Brucker static int arm_smmu_streams_cmp_key(const void *lhs, const struct rb_node *rhs)
1750cdf315f9SJean-Philippe Brucker {
1751cdf315f9SJean-Philippe Brucker 	struct arm_smmu_stream *stream_rhs =
1752cdf315f9SJean-Philippe Brucker 		rb_entry(rhs, struct arm_smmu_stream, node);
1753cdf315f9SJean-Philippe Brucker 	const u32 *sid_lhs = lhs;
1754cdf315f9SJean-Philippe Brucker 
1755a2bb820eSJason Gunthorpe 	if (*sid_lhs < stream_rhs->id)
1756a2bb820eSJason Gunthorpe 		return -1;
1757cdf315f9SJean-Philippe Brucker 	if (*sid_lhs > stream_rhs->id)
1758a2bb820eSJason Gunthorpe 		return 1;
1759cdf315f9SJean-Philippe Brucker 	return 0;
1760cdf315f9SJean-Philippe Brucker }
176148ec83bcSWill Deacon 
arm_smmu_streams_cmp_node(struct rb_node * lhs,const struct rb_node * rhs)1762395ad89dSJean-Philippe Brucker static int arm_smmu_streams_cmp_node(struct rb_node *lhs,
1763395ad89dSJean-Philippe Brucker 				     const struct rb_node *rhs)
17643dfa64aeSLu Baolu {
1765395ad89dSJean-Philippe Brucker 	return arm_smmu_streams_cmp_key(
1766395ad89dSJean-Philippe Brucker 		&rb_entry(lhs, struct arm_smmu_stream, node)->id, rhs);
1767395ad89dSJean-Philippe Brucker }
1768395ad89dSJean-Philippe Brucker 
17693f02a9dcSLu Baolu static struct arm_smmu_master *
arm_smmu_find_master(struct arm_smmu_device * smmu,u32 sid)1770395ad89dSJean-Philippe Brucker arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid)
1771395ad89dSJean-Philippe Brucker {
1772395ad89dSJean-Philippe Brucker 	struct rb_node *node;
1773395ad89dSJean-Philippe Brucker 
1774395ad89dSJean-Philippe Brucker 	lockdep_assert_held(&smmu->streams_mutex);
1775395ad89dSJean-Philippe Brucker 
1776395ad89dSJean-Philippe Brucker 	node = rb_find(&sid, &smmu->streams, arm_smmu_streams_cmp_key);
1777395ad89dSJean-Philippe Brucker 	if (!node)
1778395ad89dSJean-Philippe Brucker 		return NULL;
1779395ad89dSJean-Philippe Brucker 	return rb_entry(node, struct arm_smmu_stream, node)->master;
1780395ad89dSJean-Philippe Brucker }
1781395ad89dSJean-Philippe Brucker 
178266014df7SLu Baolu /* IRQ and event handlers */
arm_smmu_decode_event(struct arm_smmu_device * smmu,u64 * raw,struct arm_smmu_event * event)178366014df7SLu Baolu static void arm_smmu_decode_event(struct arm_smmu_device *smmu, u64 *raw,
178466014df7SLu Baolu 				  struct arm_smmu_event *event)
1785395ad89dSJean-Philippe Brucker {
1786395ad89dSJean-Philippe Brucker 	struct arm_smmu_master *master;
1787395ad89dSJean-Philippe Brucker 
1788395ad89dSJean-Philippe Brucker 	event->id = FIELD_GET(EVTQ_0_ID, raw[0]);
1789395ad89dSJean-Philippe Brucker 	event->sid = FIELD_GET(EVTQ_0_SID, raw[0]);
1790395ad89dSJean-Philippe Brucker 	event->ssv = FIELD_GET(EVTQ_0_SSV, raw[0]);
1791395ad89dSJean-Philippe Brucker 	event->ssid = event->ssv ? FIELD_GET(EVTQ_0_SSID, raw[0]) : IOMMU_NO_PASID;
1792395ad89dSJean-Philippe Brucker 	event->privileged = FIELD_GET(EVTQ_1_PnU, raw[1]);
1793395ad89dSJean-Philippe Brucker 	event->instruction = FIELD_GET(EVTQ_1_InD, raw[1]);
1794395ad89dSJean-Philippe Brucker 	event->s2 = FIELD_GET(EVTQ_1_S2, raw[1]);
1795395ad89dSJean-Philippe Brucker 	event->read = FIELD_GET(EVTQ_1_RnW, raw[1]);
1796395ad89dSJean-Philippe Brucker 	event->stag = FIELD_GET(EVTQ_1_STAG, raw[1]);
1797395ad89dSJean-Philippe Brucker 	event->stall = FIELD_GET(EVTQ_1_STALL, raw[1]);
1798395ad89dSJean-Philippe Brucker 	event->class = FIELD_GET(EVTQ_1_CLASS, raw[1]);
1799395ad89dSJean-Philippe Brucker 	event->iova = FIELD_GET(EVTQ_2_ADDR, raw[2]);
1800395ad89dSJean-Philippe Brucker 	event->ipa = raw[3] & EVTQ_3_IPA;
1801395ad89dSJean-Philippe Brucker 	event->fetch_addr = raw[3] & EVTQ_3_FETCH_ADDR;
1802395ad89dSJean-Philippe Brucker 	event->ttrnw = FIELD_GET(EVTQ_1_TT_READ, raw[1]);
1803395ad89dSJean-Philippe Brucker 	event->class_tt = false;
1804395ad89dSJean-Philippe Brucker 	event->dev = NULL;
1805395ad89dSJean-Philippe Brucker 
1806395ad89dSJean-Philippe Brucker 	if (event->id == EVT_ID_PERMISSION_FAULT)
1807395ad89dSJean-Philippe Brucker 		event->class_tt = (event->class == EVTQ_1_CLASS_TT);
1808395ad89dSJean-Philippe Brucker 
1809395ad89dSJean-Philippe Brucker 	mutex_lock(&smmu->streams_mutex);
1810395ad89dSJean-Philippe Brucker 	master = arm_smmu_find_master(smmu, event->sid);
1811395ad89dSJean-Philippe Brucker 	if (master)
1812395ad89dSJean-Philippe Brucker 		event->dev = get_device(master->dev);
1813395ad89dSJean-Philippe Brucker 	mutex_unlock(&smmu->streams_mutex);
1814395ad89dSJean-Philippe Brucker }
1815395ad89dSJean-Philippe Brucker 
arm_smmu_handle_event(struct arm_smmu_device * smmu,u64 * evt,struct arm_smmu_event * event)1816b58b133eSPranjal Shrivastava static int arm_smmu_handle_event(struct arm_smmu_device *smmu, u64 *evt,
1817395ad89dSJean-Philippe Brucker 				 struct arm_smmu_event *event)
1818395ad89dSJean-Philippe Brucker {
1819395ad89dSJean-Philippe Brucker 	int ret = 0;
1820395ad89dSJean-Philippe Brucker 	u32 perm = 0;
1821395ad89dSJean-Philippe Brucker 	struct arm_smmu_master *master;
182248ec83bcSWill Deacon 	struct iopf_fault fault_evt = { };
182348ec83bcSWill Deacon 	struct iommu_fault *flt = &fault_evt.fault;
1824395ad89dSJean-Philippe Brucker 
182548ec83bcSWill Deacon 	switch (event->id) {
182648ec83bcSWill Deacon 	case EVT_ID_BAD_STE_CONFIG:
18277c288a5bSWill Deacon 	case EVT_ID_STREAM_DISABLED_FAULT:
18289cff922bSJean-Philippe Brucker 	case EVT_ID_BAD_SUBSTREAMID_CONFIG:
18299cff922bSJean-Philippe Brucker 	case EVT_ID_BAD_CD_CONFIG:
183048ec83bcSWill Deacon 	case EVT_ID_TRANSLATION_FAULT:
183148ec83bcSWill Deacon 	case EVT_ID_ADDR_SIZE_FAULT:
1832b4163fb3SJean-Philippe Brucker 	case EVT_ID_ACCESS_FAULT:
183348ec83bcSWill Deacon 	case EVT_ID_PERMISSION_FAULT:
18347417b99cSRobin Murphy 		break;
183548ec83bcSWill Deacon 	default:
1836395ad89dSJean-Philippe Brucker 		return -EOPNOTSUPP;
18379cff922bSJean-Philippe Brucker 	}
1838395ad89dSJean-Philippe Brucker 
1839395ad89dSJean-Philippe Brucker 	if (event->stall) {
184048ec83bcSWill Deacon 		if (event->read)
184148ec83bcSWill Deacon 			perm |= IOMMU_FAULT_PERM_READ;
184248ec83bcSWill Deacon 		else
184348ec83bcSWill Deacon 			perm |= IOMMU_FAULT_PERM_WRITE;
184448ec83bcSWill Deacon 
184530de2b54SZhou Guanghui 		if (event->instruction)
184648ec83bcSWill Deacon 			perm |= IOMMU_FAULT_PERM_EXEC;
184748ec83bcSWill Deacon 
184848ec83bcSWill Deacon 		if (event->privileged)
184948ec83bcSWill Deacon 			perm |= IOMMU_FAULT_PERM_PRIV;
185048ec83bcSWill Deacon 
185148ec83bcSWill Deacon 		flt->type = IOMMU_FAULT_PAGE_REQ;
18522a8868f1SWill Deacon 		flt->prm = (struct iommu_fault_page_request){
185348ec83bcSWill Deacon 			.flags = IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE,
18547c288a5bSWill Deacon 			.grpid = event->stag,
185548ec83bcSWill Deacon 			.perm = perm,
1856b4163fb3SJean-Philippe Brucker 			.addr = event->iova,
185767ea0b7cSTomas Krcka 		};
1858b4163fb3SJean-Philippe Brucker 
185948ec83bcSWill Deacon 		if (event->ssv) {
186048ec83bcSWill Deacon 			flt->prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
1861b4163fb3SJean-Philippe Brucker 			flt->prm.pasid = event->ssid;
186248ec83bcSWill Deacon 		}
186348ec83bcSWill Deacon 	}
186448ec83bcSWill Deacon 
186548ec83bcSWill Deacon 	mutex_lock(&smmu->streams_mutex);
186648ec83bcSWill Deacon 	master = arm_smmu_find_master(smmu, event->sid);
18677417b99cSRobin Murphy 	if (!master) {
18687417b99cSRobin Murphy 		ret = -EINVAL;
186942987801SJacob Pan 		goto out_unlock;
18707417b99cSRobin Murphy 	}
18717417b99cSRobin Murphy 
187248ec83bcSWill Deacon 	if (event->stall)
187348ec83bcSWill Deacon 		ret = iommu_report_device_fault(master->dev, &fault_evt);
187448ec83bcSWill Deacon 	else if (master->vmaster && !event->s2)
187548ec83bcSWill Deacon 		ret = arm_vmaster_report_event(master->vmaster, evt);
187648ec83bcSWill Deacon 	else
187748ec83bcSWill Deacon 		ret = -EOPNOTSUPP; /* Unhandled events should be pinned */
187848ec83bcSWill Deacon out_unlock:
187948ec83bcSWill Deacon 	mutex_unlock(&smmu->streams_mutex);
188048ec83bcSWill Deacon 	return ret;
18811cf9e54eSRobin Murphy }
188248ec83bcSWill Deacon 
arm_smmu_dump_raw_event(struct arm_smmu_device * smmu,u64 * raw,struct arm_smmu_event * event)188348ec83bcSWill Deacon static void arm_smmu_dump_raw_event(struct arm_smmu_device *smmu, u64 *raw,
188448ec83bcSWill Deacon 				    struct arm_smmu_event *event)
188548ec83bcSWill Deacon {
188648ec83bcSWill Deacon 	int i;
188748ec83bcSWill Deacon 
188848ec83bcSWill Deacon 	dev_err(smmu->dev, "event 0x%02x received:\n", event->id);
188948ec83bcSWill Deacon 
189048ec83bcSWill Deacon 	for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
189148ec83bcSWill Deacon 		dev_err(smmu->dev, "\t0x%016llx\n", raw[i]);
189248ec83bcSWill Deacon }
189348ec83bcSWill Deacon 
189448ec83bcSWill Deacon #define ARM_SMMU_EVT_KNOWN(e)	((e)->id < ARRAY_SIZE(event_str) && event_str[(e)->id])
189548ec83bcSWill Deacon #define ARM_SMMU_LOG_EVT_STR(e) ARM_SMMU_EVT_KNOWN(e) ? event_str[(e)->id] : "UNKNOWN"
189648ec83bcSWill Deacon #define ARM_SMMU_LOG_CLIENT(e)	(e)->dev ? dev_name((e)->dev) : "(unassigned sid)"
189748ec83bcSWill Deacon 
arm_smmu_dump_event(struct arm_smmu_device * smmu,u64 * raw,struct arm_smmu_event * evt,struct ratelimit_state * rs)189848ec83bcSWill Deacon static void arm_smmu_dump_event(struct arm_smmu_device *smmu, u64 *raw,
1899b4163fb3SJean-Philippe Brucker 				struct arm_smmu_event *evt,
1900b4163fb3SJean-Philippe Brucker 				struct ratelimit_state *rs)
1901b4163fb3SJean-Philippe Brucker {
1902b4163fb3SJean-Philippe Brucker 	if (!__ratelimit(rs))
19037c288a5bSWill Deacon 		return;
1904b4163fb3SJean-Philippe Brucker 
1905b4163fb3SJean-Philippe Brucker 	arm_smmu_dump_raw_event(smmu, raw, evt);
1906b4163fb3SJean-Philippe Brucker 
1907b4163fb3SJean-Philippe Brucker 	switch (evt->id) {
1908b4163fb3SJean-Philippe Brucker 	case EVT_ID_TRANSLATION_FAULT:
1909b4163fb3SJean-Philippe Brucker 	case EVT_ID_ADDR_SIZE_FAULT:
19102a8868f1SWill Deacon 	case EVT_ID_ACCESS_FAULT:
1911b4163fb3SJean-Philippe Brucker 	case EVT_ID_PERMISSION_FAULT:
19127c288a5bSWill Deacon 		dev_err(smmu->dev, "event: %s client: %s sid: %#x ssid: %#x iova: %#llx ipa: %#llx",
1913b4163fb3SJean-Philippe Brucker 			ARM_SMMU_LOG_EVT_STR(evt), ARM_SMMU_LOG_CLIENT(evt),
191448ec83bcSWill Deacon 			evt->sid, evt->ssid, evt->iova, evt->ipa);
191567ea0b7cSTomas Krcka 
191648ec83bcSWill Deacon 		dev_err(smmu->dev, "%s %s %s %s \"%s\"%s%s stag: %#x",
191748ec83bcSWill Deacon 			evt->privileged ? "priv" : "unpriv",
191848ec83bcSWill Deacon 			evt->instruction ? "inst" : "data",
191948ec83bcSWill Deacon 			str_read_write(evt->read),
192048ec83bcSWill Deacon 			evt->s2 ? "s2" : "s1", event_class_str[evt->class],
192148ec83bcSWill Deacon 			evt->class_tt ? (evt->ttrnw ? " ttd_read" : " ttd_write") : "",
192248ec83bcSWill Deacon 			evt->stall ? " stall" : "", evt->stag);
1923324ba108SPrem Mallappa 
192448ec83bcSWill Deacon 		break;
192548ec83bcSWill Deacon 
192648ec83bcSWill Deacon 	case EVT_ID_STE_FETCH_FAULT:
192748ec83bcSWill Deacon 	case EVT_ID_CD_FETCH_FAULT:
192848ec83bcSWill Deacon 	case EVT_ID_VMS_FETCH_FAULT:
1929324ba108SPrem Mallappa 		dev_err(smmu->dev, "event: %s client: %s sid: %#x ssid: %#x fetch_addr: %#llx",
1930324ba108SPrem Mallappa 			ARM_SMMU_LOG_EVT_STR(evt), ARM_SMMU_LOG_CLIENT(evt),
193148ec83bcSWill Deacon 			evt->sid, evt->ssid, evt->fetch_addr);
193248ec83bcSWill Deacon 
193348ec83bcSWill Deacon 		break;
193448ec83bcSWill Deacon 
1935324ba108SPrem Mallappa 	default:
193648ec83bcSWill Deacon 		dev_err(smmu->dev, "event: %s client: %s sid: %#x ssid: %#x",
1937324ba108SPrem Mallappa 			ARM_SMMU_LOG_EVT_STR(evt), ARM_SMMU_LOG_CLIENT(evt),
193848ec83bcSWill Deacon 			evt->sid, evt->ssid);
193948ec83bcSWill Deacon 	}
194048ec83bcSWill Deacon }
194148ec83bcSWill Deacon 
arm_smmu_evtq_thread(int irq,void * dev)1942324ba108SPrem Mallappa static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
194348ec83bcSWill Deacon {
194448ec83bcSWill Deacon 	u64 evt[EVTQ_ENT_DWORDS];
1945b4163fb3SJean-Philippe Brucker 	struct arm_smmu_event event = {0};
194648ec83bcSWill Deacon 	struct arm_smmu_device *smmu = dev;
194748ec83bcSWill Deacon 	struct arm_smmu_queue *q = &smmu->evtq.q;
1948b4163fb3SJean-Philippe Brucker 	struct arm_smmu_ll_queue *llq = &q->llq;
194948ec83bcSWill Deacon 	static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
195048ec83bcSWill Deacon 				      DEFAULT_RATELIMIT_BURST);
1951dce032a1SRobin Murphy 
195248ec83bcSWill Deacon 	do {
195348ec83bcSWill Deacon 		while (!queue_remove_raw(q, evt)) {
1954324ba108SPrem Mallappa 			arm_smmu_decode_event(smmu, evt, &event);
195548ec83bcSWill Deacon 			if (arm_smmu_handle_event(smmu, evt, &event))
195648ec83bcSWill Deacon 				arm_smmu_dump_event(smmu, evt, &event, &rs);
1957324ba108SPrem Mallappa 
195848ec83bcSWill Deacon 			put_device(event.dev);
195948ec83bcSWill Deacon 			cond_resched();
1960324ba108SPrem Mallappa 		}
196148ec83bcSWill Deacon 
196248ec83bcSWill Deacon 		/*
196348ec83bcSWill Deacon 		 * Not much we can do on overflow, so scream and pretend we're
196448ec83bcSWill Deacon 		 * trying harder.
196548ec83bcSWill Deacon 		 */
196648ec83bcSWill Deacon 		if (queue_sync_prod_in(q) == -EOVERFLOW)
1967f935448aSGeetha Sowjanya 			dev_err(smmu->dev, "EVTQ overflow detected -- events lost\n");
1968f935448aSGeetha Sowjanya 	} while (!queue_empty(llq));
1969f935448aSGeetha Sowjanya 
1970f935448aSGeetha Sowjanya 	/* Sync our overflow flag, as we believe we're up to speed */
1971f935448aSGeetha Sowjanya 	queue_sync_cons_ovf(q);
1972f935448aSGeetha Sowjanya 	return IRQ_HANDLED;
1973f935448aSGeetha Sowjanya }
1974f935448aSGeetha Sowjanya 
arm_smmu_handle_ppr(struct arm_smmu_device * smmu,u64 * evt)1975f935448aSGeetha Sowjanya static void arm_smmu_handle_ppr(struct arm_smmu_device *smmu, u64 *evt)
1976f935448aSGeetha Sowjanya {
1977f935448aSGeetha Sowjanya 	u32 sid, ssid;
1978f935448aSGeetha Sowjanya 	u16 grpid;
1979f935448aSGeetha Sowjanya 	bool ssv, last;
1980f935448aSGeetha Sowjanya 
1981f935448aSGeetha Sowjanya 	sid = FIELD_GET(PRIQ_0_SID, evt[0]);
1982f935448aSGeetha Sowjanya 	ssv = FIELD_GET(PRIQ_0_SSID_V, evt[0]);
1983f935448aSGeetha Sowjanya 	ssid = ssv ? FIELD_GET(PRIQ_0_SSID, evt[0]) : IOMMU_NO_PASID;
19849ce27afcSJean-Philippe Brucker 	last = FIELD_GET(PRIQ_0_PRG_LAST, evt[0]);
19859ce27afcSJean-Philippe Brucker 	grpid = FIELD_GET(PRIQ_1_PRG_IDX, evt[1]);
19869ce27afcSJean-Philippe Brucker 
19879ce27afcSJean-Philippe Brucker 	dev_info(smmu->dev, "unexpected PRI request received:\n");
19889ce27afcSJean-Philippe Brucker 	dev_info(smmu->dev,
19899ce27afcSJean-Philippe Brucker 		 "\tsid 0x%08x.0x%05x: [%u%s] %sprivileged %s%s%s access at iova 0x%016llx\n",
19909ce27afcSJean-Philippe Brucker 		 sid, ssid, grpid, last ? "L" : "",
19919ce27afcSJean-Philippe Brucker 		 evt[0] & PRIQ_0_PERM_PRIV ? "" : "un",
19929ce27afcSJean-Philippe Brucker 		 evt[0] & PRIQ_0_PERM_READ ? "R" : "",
19939ce27afcSJean-Philippe Brucker 		 evt[0] & PRIQ_0_PERM_WRITE ? "W" : "",
19942f7e8c55SJean-Philippe Brucker 		 evt[0] & PRIQ_0_PERM_EXEC ? "X" : "",
19952f7e8c55SJean-Philippe Brucker 		 evt[1] & PRIQ_1_ADDR_MASK);
19962f7e8c55SJean-Philippe Brucker 
19972f7e8c55SJean-Philippe Brucker 	if (last) {
19982f7e8c55SJean-Philippe Brucker 		struct arm_smmu_cmdq_ent cmd = {
19992f7e8c55SJean-Philippe Brucker 			.opcode			= CMDQ_OP_PRI_RESP,
20002f7e8c55SJean-Philippe Brucker 			.substream_valid	= ssv,
20012f7e8c55SJean-Philippe Brucker 			.pri			= {
20022f7e8c55SJean-Philippe Brucker 				.sid	= sid,
20032f7e8c55SJean-Philippe Brucker 				.ssid	= ssid,
20042f7e8c55SJean-Philippe Brucker 				.grpid	= grpid,
20052f7e8c55SJean-Philippe Brucker 				.resp	= PRI_RESP_DENY,
20062f7e8c55SJean-Philippe Brucker 			},
20072f7e8c55SJean-Philippe Brucker 		};
20089ce27afcSJean-Philippe Brucker 
20099ce27afcSJean-Philippe Brucker 		arm_smmu_cmdq_issue_cmd(smmu, &cmd);
201042987801SJacob Pan 	}
20119ce27afcSJean-Philippe Brucker }
20129ce27afcSJean-Philippe Brucker 
arm_smmu_priq_thread(int irq,void * dev)20139ce27afcSJean-Philippe Brucker static irqreturn_t arm_smmu_priq_thread(int irq, void *dev)
20149ce27afcSJean-Philippe Brucker {
20159ce27afcSJean-Philippe Brucker 	struct arm_smmu_device *smmu = dev;
20169ce27afcSJean-Philippe Brucker 	struct arm_smmu_queue *q = &smmu->priq.q;
20179ce27afcSJean-Philippe Brucker 	struct arm_smmu_ll_queue *llq = &q->llq;
20189ce27afcSJean-Philippe Brucker 	u64 evt[PRIQ_ENT_DWORDS];
20199ce27afcSJean-Philippe Brucker 
20209ce27afcSJean-Philippe Brucker 	do {
20219ce27afcSJean-Philippe Brucker 		while (!queue_remove_raw(q, evt))
20229ce27afcSJean-Philippe Brucker 			arm_smmu_handle_ppr(smmu, evt);
20239ce27afcSJean-Philippe Brucker 
20249ce27afcSJean-Philippe Brucker 		if (queue_sync_prod_in(q) == -EOVERFLOW)
20259ce27afcSJean-Philippe Brucker 			dev_err(smmu->dev, "PRIQ overflow detected -- requests lost\n");
20269ce27afcSJean-Philippe Brucker 	} while (!queue_empty(llq));
20279ce27afcSJean-Philippe Brucker 
20289ce27afcSJean-Philippe Brucker 	/* Sync our overflow flag, as we believe we're up to speed */
20299ce27afcSJean-Philippe Brucker 	queue_sync_cons_ovf(q);
20309ce27afcSJean-Philippe Brucker 	return IRQ_HANDLED;
20319ce27afcSJean-Philippe Brucker }
20329ce27afcSJean-Philippe Brucker 
20339ce27afcSJean-Philippe Brucker static int arm_smmu_device_disable(struct arm_smmu_device *smmu);
20349ce27afcSJean-Philippe Brucker 
arm_smmu_gerror_handler(int irq,void * dev)20359ce27afcSJean-Philippe Brucker static irqreturn_t arm_smmu_gerror_handler(int irq, void *dev)
20369ce27afcSJean-Philippe Brucker {
20379ce27afcSJean-Philippe Brucker 	u32 gerror, gerrorn, active;
20389ce27afcSJean-Philippe Brucker 	struct arm_smmu_device *smmu = dev;
20399ce27afcSJean-Philippe Brucker 
20409ce27afcSJean-Philippe Brucker 	gerror = readl_relaxed(smmu->base + ARM_SMMU_GERROR);
20419ce27afcSJean-Philippe Brucker 	gerrorn = readl_relaxed(smmu->base + ARM_SMMU_GERRORN);
20429ce27afcSJean-Philippe Brucker 
20439ce27afcSJean-Philippe Brucker 	active = gerror ^ gerrorn;
20449ce27afcSJean-Philippe Brucker 	if (!(active & GERROR_ERR_MASK))
20459ce27afcSJean-Philippe Brucker 		return IRQ_NONE; /* No errors pending */
20469ce27afcSJean-Philippe Brucker 
20479ce27afcSJean-Philippe Brucker 	dev_warn(smmu->dev,
20489ce27afcSJean-Philippe Brucker 		 "unexpected global error reported (0x%08x), this could be serious\n",
20499ce27afcSJean-Philippe Brucker 		 active);
20509ce27afcSJean-Philippe Brucker 
20511d5f34f0SJason Gunthorpe 	if (active & GERROR_SFM_ERR) {
20521d5f34f0SJason Gunthorpe 		dev_err(smmu->dev, "device has entered Service Failure Mode!\n");
20539ce27afcSJean-Philippe Brucker 		arm_smmu_device_disable(smmu);
20549ce27afcSJean-Philippe Brucker 	}
20559e773aeeSRob Herring 
205693f9f795SZhen Lei 	if (active & GERROR_MSI_GERROR_ABT_ERR)
20579ce27afcSJean-Philippe Brucker 		dev_warn(smmu->dev, "GERROR MSI write aborted\n");
20581d5f34f0SJason Gunthorpe 
20599ce27afcSJean-Philippe Brucker 	if (active & GERROR_MSI_PRIQ_ABT_ERR)
2060a9d40285SNicolin Chen 		dev_warn(smmu->dev, "PRIQ MSI write aborted\n");
2061cdf315f9SJean-Philippe Brucker 
2062cdf315f9SJean-Philippe Brucker 	if (active & GERROR_MSI_EVTQ_ABT_ERR)
2063eff19474SZhen Lei 		dev_warn(smmu->dev, "EVTQ MSI write aborted\n");
20649ce27afcSJean-Philippe Brucker 
20659ce27afcSJean-Philippe Brucker 	if (active & GERROR_MSI_CMDQ_ABT_ERR)
2066eff19474SZhen Lei 		dev_warn(smmu->dev, "CMDQ MSI write aborted\n");
20679ce27afcSJean-Philippe Brucker 
20689ce27afcSJean-Philippe Brucker 	if (active & GERROR_PRIQ_ABT_ERR)
2069d38c28dbSJason Gunthorpe 		dev_err(smmu->dev, "PRIQ write aborted -- events may have been lost\n");
2070d38c28dbSJason Gunthorpe 
20719ce27afcSJean-Philippe Brucker 	if (active & GERROR_EVTQ_ABT_ERR)
2072ad10dce6SJason Gunthorpe 		dev_err(smmu->dev, "EVTQ write aborted -- events may have been lost\n");
20739e773aeeSRob Herring 
20749ce27afcSJean-Philippe Brucker 	if (active & GERROR_CMDQ_ERR)
2075a9d40285SNicolin Chen 		arm_smmu_cmdq_skip_err(smmu);
2076a9d40285SNicolin Chen 
2077a9d40285SNicolin Chen 	writel(gerror, smmu->base + ARM_SMMU_GERRORN);
2078fac95671SJohn Garry 	return IRQ_HANDLED;
20799ce27afcSJean-Philippe Brucker }
20809ce27afcSJean-Philippe Brucker 
arm_smmu_combined_irq_thread(int irq,void * dev)20819ce27afcSJean-Philippe Brucker static irqreturn_t arm_smmu_combined_irq_thread(int irq, void *dev)
20829ce27afcSJean-Philippe Brucker {
2083cdb8a3c3SWill Deacon 	struct arm_smmu_device *smmu = dev;
2084cdb8a3c3SWill Deacon 
2085cdb8a3c3SWill Deacon 	arm_smmu_evtq_thread(irq, dev);
2086cdb8a3c3SWill Deacon 	if (smmu->features & ARM_SMMU_FEAT_PRI)
2087cdb8a3c3SWill Deacon 		arm_smmu_priq_thread(irq, dev);
2088cdb8a3c3SWill Deacon 
2089cdb8a3c3SWill Deacon 	return IRQ_HANDLED;
2090cdb8a3c3SWill Deacon }
2091cdb8a3c3SWill Deacon 
arm_smmu_combined_irq_handler(int irq,void * dev)2092cdb8a3c3SWill Deacon static irqreturn_t arm_smmu_combined_irq_handler(int irq, void *dev)
2093cdb8a3c3SWill Deacon {
2094cdb8a3c3SWill Deacon 	arm_smmu_gerror_handler(irq, dev);
2095cdb8a3c3SWill Deacon 	return IRQ_WAKE_THREAD;
2096cdb8a3c3SWill Deacon }
2097cdb8a3c3SWill Deacon 
2098cdb8a3c3SWill Deacon static void
arm_smmu_atc_inv_to_cmd(int ssid,unsigned long iova,size_t size,struct arm_smmu_cmdq_ent * cmd)2099cdb8a3c3SWill Deacon arm_smmu_atc_inv_to_cmd(int ssid, unsigned long iova, size_t size,
2100a9d40285SNicolin Chen 			struct arm_smmu_cmdq_ent *cmd)
2101fac95671SJohn Garry {
21029ce27afcSJean-Philippe Brucker 	size_t log2_span;
2103ad10dce6SJason Gunthorpe 	size_t span_mask;
2104ad10dce6SJason Gunthorpe 	/* ATC invalidates are always on 4096-bytes pages */
2105ad10dce6SJason Gunthorpe 	size_t inval_grain_shift = 12;
2106ad10dce6SJason Gunthorpe 	unsigned long page_start, page_end;
21079e773aeeSRob Herring 
21089e773aeeSRob Herring 	/*
21099e773aeeSRob Herring 	 * ATS and PASID:
2110f27298a8SJason Gunthorpe 	 *
2111f27298a8SJason Gunthorpe 	 * If substream_valid is clear, the PCIe TLP is sent without a PASID
2112f27298a8SJason Gunthorpe 	 * prefix. In that case all ATC entries within the address range are
2113f27298a8SJason Gunthorpe 	 * invalidated, including those that were requested with a PASID! There
2114f27298a8SJason Gunthorpe 	 * is no way to invalidate only entries without PASID.
2115f27298a8SJason Gunthorpe 	 *
2116f27298a8SJason Gunthorpe 	 * When using STRTAB_STE_1_S1DSS_SSID0 (reserving CD 0 for non-PASID
2117f27298a8SJason Gunthorpe 	 * traffic), translation requests without PASID create ATC entries
2118f27298a8SJason Gunthorpe 	 * without PASID, which must be invalidated with substream_valid clear.
2119f27298a8SJason Gunthorpe 	 * This has the unpleasant side-effect of invalidating all PASID-tagged
212064efb3deSJason Gunthorpe 	 * ATC entries within the address range.
2121cdf315f9SJean-Philippe Brucker 	 */
2122cdf315f9SJean-Philippe Brucker 	*cmd = (struct arm_smmu_cmdq_ent) {
21239e773aeeSRob Herring 		.opcode			= CMDQ_OP_ATC_INV,
21249e773aeeSRob Herring 		.substream_valid	= (ssid != IOMMU_NO_PASID),
21259e773aeeSRob Herring 		.atc.ssid		= ssid,
21269ce27afcSJean-Philippe Brucker 	};
21279ce27afcSJean-Philippe Brucker 
21289e773aeeSRob Herring 	if (!size) {
21299ce27afcSJean-Philippe Brucker 		cmd->atc.size = ATC_INV_SIZE_ALL;
21309ce27afcSJean-Philippe Brucker 		return;
213148ec83bcSWill Deacon 	}
213248ec83bcSWill Deacon 
213348ec83bcSWill Deacon 	page_start	= iova >> inval_grain_shift;
213448ec83bcSWill Deacon 	page_end	= (iova + size - 1) >> inval_grain_shift;
213548ec83bcSWill Deacon 
213648ec83bcSWill Deacon 	/*
213748ec83bcSWill Deacon 	 * In an ATS Invalidate Request, the address must be aligned on the
21389662b99aSZhen Lei 	 * range size, which must be a power of two number of page sizes. We
21399662b99aSZhen Lei 	 * thus have to choose between grossly over-invalidating the region, or
21409662b99aSZhen Lei 	 * splitting the invalidation into multiple commands. For simplicity
2141587e6c10SWill Deacon 	 * we'll go with the first solution, but should refine it in the future
2142587e6c10SWill Deacon 	 * if multiple commands are shown to be more efficient.
2143587e6c10SWill Deacon 	 *
21449662b99aSZhen Lei 	 * Find the smallest power of two that covers the range. The most
21453e630336SJean-Philippe Brucker 	 * significant differing bit between the start and end addresses,
2146987a878eSMichael Shavit 	 * fls(start ^ end), indicates the required span. For example:
21473e630336SJean-Philippe Brucker 	 *
21483e630336SJean-Philippe Brucker 	 * We want to invalidate pages [8; 11]. This is already the ideal range:
21493e630336SJean-Philippe Brucker 	 *		x = 0b1000 ^ 0b1011 = 0b11
21504537f6f1SZhen Lei 	 *		span = 1 << fls(x) = 4
21513e630336SJean-Philippe Brucker 	 *
215264efb3deSJason Gunthorpe 	 * To invalidate pages [7; 10], we need to invalidate [0; 15]:
215348ec83bcSWill Deacon 	 *		x = 0b0111 ^ 0b1010 = 0b1101
215448ec83bcSWill Deacon 	 *		span = 1 << fls(x) = 16
2155eba8d2f8SJean-Philippe Brucker 	 */
2156eba8d2f8SJean-Philippe Brucker 	log2_span	= fls_long(page_start ^ page_end);
2157eba8d2f8SJean-Philippe Brucker 	span_mask	= (1ULL << log2_span) - 1;
21582af2e72bSWill Deacon 
215948ec83bcSWill Deacon 	page_start	&= ~span_mask;
216048ec83bcSWill Deacon 
2161eba8d2f8SJean-Philippe Brucker 	cmd->atc.addr	= page_start << inval_grain_shift;
21626a481a95SRob Herring 	cmd->atc.size	= log2_span;
2163fac95671SJohn Garry }
216448ec83bcSWill Deacon 
arm_smmu_atc_inv_master(struct arm_smmu_master * master,ioasid_t ssid)21657314ca86SWill Deacon static int arm_smmu_atc_inv_master(struct arm_smmu_master *master,
21667314ca86SWill Deacon 				   ioasid_t ssid)
21677314ca86SWill Deacon {
21686a481a95SRob Herring 	int i;
21696a481a95SRob Herring 	struct arm_smmu_cmdq_ent cmd;
21706a481a95SRob Herring 	struct arm_smmu_cmdq_batch cmds;
21716a481a95SRob Herring 
2172eb6c9764SRobin Murphy 	arm_smmu_atc_inv_to_cmd(ssid, 0, 0, &cmd);
2173eb6c9764SRobin Murphy 
21746a481a95SRob Herring 	arm_smmu_cmdq_batch_init(master->smmu, &cmds, &cmd);
2175eba8d2f8SJean-Philippe Brucker 	for (i = 0; i < master->num_streams; i++) {
21766a481a95SRob Herring 		cmd.atc.sid = master->streams[i].id;
21776833b8f2SRobin Murphy 		arm_smmu_cmdq_batch_add(master->smmu, &cmds, &cmd);
2178eb6c9764SRobin Murphy 	}
2179eb6c9764SRobin Murphy 
2180eb6c9764SRobin Murphy 	return arm_smmu_cmdq_batch_submit(master->smmu, &cmds);
2181eb6c9764SRobin Murphy }
2182eb6c9764SRobin Murphy 
arm_smmu_atc_inv_domain(struct arm_smmu_domain * smmu_domain,unsigned long iova,size_t size)2183eb6c9764SRobin Murphy int arm_smmu_atc_inv_domain(struct arm_smmu_domain *smmu_domain,
21846833b8f2SRobin Murphy 			    unsigned long iova, size_t size)
21856833b8f2SRobin Murphy {
2186eba8d2f8SJean-Philippe Brucker 	struct arm_smmu_master_domain *master_domain;
2187eb6c9764SRobin Murphy 	int i;
2188eb6c9764SRobin Murphy 	unsigned long flags;
21896a481a95SRob Herring 	struct arm_smmu_cmdq_ent cmd = {
21906a481a95SRob Herring 		.opcode = CMDQ_OP_ATC_INV,
2191a9d40285SNicolin Chen 	};
2192fac95671SJohn Garry 	struct arm_smmu_cmdq_batch cmds;
21932af2e72bSWill Deacon 
21946a481a95SRob Herring 	if (!(smmu_domain->smmu->features & ARM_SMMU_FEAT_ATS))
21956a481a95SRob Herring 		return 0;
21966a481a95SRob Herring 
21976a481a95SRob Herring 	/*
21986a481a95SRob Herring 	 * Ensure that we've completed prior invalidation of the main TLBs
21996a481a95SRob Herring 	 * before we read 'nr_ats_masters' in case of a concurrent call to
22006a481a95SRob Herring 	 * arm_smmu_enable_ats():
22016a481a95SRob Herring 	 *
22026a481a95SRob Herring 	 *	// unmap()			// arm_smmu_enable_ats()
22036a481a95SRob Herring 	 *	TLBI+SYNC			atomic_inc(&nr_ats_masters);
22046a481a95SRob Herring 	 *	smp_mb();			[...]
22056a481a95SRob Herring 	 *	atomic_read(&nr_ats_masters);	pci_enable_ats() // writel()
2206eba8d2f8SJean-Philippe Brucker 	 *
22076a481a95SRob Herring 	 * Ensures that we always see the incremented 'nr_ats_masters' count if
22086a481a95SRob Herring 	 * ATS was enabled at the PCI device before completion of the TLBI.
22096a481a95SRob Herring 	 */
2210eba8d2f8SJean-Philippe Brucker 	smp_mb();
22116a481a95SRob Herring 	if (!atomic_read(&smmu_domain->nr_ats_masters))
22126a481a95SRob Herring 		return 0;
22136a481a95SRob Herring 
22146a481a95SRob Herring 	arm_smmu_cmdq_batch_init(smmu_domain->smmu, &cmds, &cmd);
22156a481a95SRob Herring 
22166a481a95SRob Herring 	spin_lock_irqsave(&smmu_domain->devices_lock, flags);
221748ec83bcSWill Deacon 	list_for_each_entry(master_domain, &smmu_domain->devices,
221848ec83bcSWill Deacon 			    devices_elm) {
2219eba8d2f8SJean-Philippe Brucker 		struct arm_smmu_master *master = master_domain->master;
2220eba8d2f8SJean-Philippe Brucker 
22216a481a95SRob Herring 		if (!master->ats_enabled)
22222af2e72bSWill Deacon 			continue;
22234ce8da45SJean-Philippe Brucker 
2224eba8d2f8SJean-Philippe Brucker 		if (master_domain->nested_ats_flush) {
2225eba8d2f8SJean-Philippe Brucker 			/*
2226eba8d2f8SJean-Philippe Brucker 			 * If a S2 used as a nesting parent is changed we have
2227eba8d2f8SJean-Philippe Brucker 			 * no option but to completely flush the ATC.
2228eba8d2f8SJean-Philippe Brucker 			 */
2229eba8d2f8SJean-Philippe Brucker 			arm_smmu_atc_inv_to_cmd(IOMMU_NO_PASID, 0, 0, &cmd);
2230eba8d2f8SJean-Philippe Brucker 		} else {
2231eba8d2f8SJean-Philippe Brucker 			arm_smmu_atc_inv_to_cmd(master_domain->ssid, iova, size,
2232eba8d2f8SJean-Philippe Brucker 						&cmd);
2233eba8d2f8SJean-Philippe Brucker 		}
2234eba8d2f8SJean-Philippe Brucker 
2235eba8d2f8SJean-Philippe Brucker 		for (i = 0; i < master->num_streams; i++) {
2236eba8d2f8SJean-Philippe Brucker 			cmd.atc.sid = master->streams[i].id;
22379111aebfSJean-Philippe Brucker 			arm_smmu_cmdq_batch_add(smmu_domain->smmu, &cmds, &cmd);
22389111aebfSJean-Philippe Brucker 		}
2239987a878eSMichael Shavit 	}
2240eba8d2f8SJean-Philippe Brucker 	spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
2241eba8d2f8SJean-Philippe Brucker 
2242eba8d2f8SJean-Philippe Brucker 	return arm_smmu_cmdq_batch_submit(smmu_domain->smmu, &cmds);
2243eba8d2f8SJean-Philippe Brucker }
2244eba8d2f8SJean-Philippe Brucker 
2245353e3cf8SWill Deacon /* IO_PGTABLE API */
arm_smmu_tlb_inv_context(void * cookie)22461e8be08dSJason Gunthorpe static void arm_smmu_tlb_inv_context(void *cookie)
22471e8be08dSJason Gunthorpe {
22481e8be08dSJason Gunthorpe 	struct arm_smmu_domain *smmu_domain = cookie;
22491e8be08dSJason Gunthorpe 	struct arm_smmu_device *smmu = smmu_domain->smmu;
22501e8be08dSJason Gunthorpe 	struct arm_smmu_cmdq_ent cmd;
22511e8be08dSJason Gunthorpe 
22521e8be08dSJason Gunthorpe 	/*
22531e8be08dSJason Gunthorpe 	 * NOTE: when io-pgtable is in non-strict mode, we may get here with
22541e8be08dSJason Gunthorpe 	 * PTEs previously cleared by unmaps on the current CPU not yet visible
2255353e3cf8SWill Deacon 	 * to the SMMU. We are relying on the dma_wmb() implicit during cmd
2256353e3cf8SWill Deacon 	 * insertion to guarantee those are observed before the TLBI. Do be
2257353e3cf8SWill Deacon 	 * careful, 007.
2258353e3cf8SWill Deacon 	 */
225964efb3deSJason Gunthorpe 	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
226048ec83bcSWill Deacon 		arm_smmu_tlb_inv_asid(smmu, smmu_domain->cd.asid);
226148ec83bcSWill Deacon 	} else {
226251d113c3SJean-Philippe Brucker 		cmd.opcode	= CMDQ_OP_TLBI_S12_VMALL;
226351d113c3SJean-Philippe Brucker 		cmd.tlbi.vmid	= smmu_domain->s2_cfg.vmid;
226451d113c3SJean-Philippe Brucker 		arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
226551d113c3SJean-Philippe Brucker 	}
226651d113c3SJean-Philippe Brucker 	arm_smmu_atc_inv_domain(smmu_domain, 0, 0);
22679111aebfSJean-Philippe Brucker }
22689111aebfSJean-Philippe Brucker 
__arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent * cmd,unsigned long iova,size_t size,size_t granule,struct arm_smmu_domain * smmu_domain)226951d113c3SJean-Philippe Brucker static void __arm_smmu_tlb_inv_range(struct arm_smmu_cmdq_ent *cmd,
227051d113c3SJean-Philippe Brucker 				     unsigned long iova, size_t size,
227151d113c3SJean-Philippe Brucker 				     size_t granule,
227251d113c3SJean-Philippe Brucker 				     struct arm_smmu_domain *smmu_domain)
227351d113c3SJean-Philippe Brucker {
227451d113c3SJean-Philippe Brucker 	struct arm_smmu_device *smmu = smmu_domain->smmu;
227551d113c3SJean-Philippe Brucker 	unsigned long end = iova + size, num_pages = 0, tg = 0;
227651d113c3SJean-Philippe Brucker 	size_t inv_range = granule;
227751d113c3SJean-Philippe Brucker 	struct arm_smmu_cmdq_batch cmds;
22783951c41aSWill Deacon 
22793951c41aSWill Deacon 	if (!size)
2280abfd6fe0SWill Deacon 		return;
2281abfd6fe0SWill Deacon 
22822af2e72bSWill Deacon 	if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
22832af2e72bSWill Deacon 		/* Get the leaf page size */
22842af2e72bSWill Deacon 		tg = __ffs(smmu_domain->domain.pgsize_bitmap);
22852af2e72bSWill Deacon 
2286abfd6fe0SWill Deacon 		num_pages = size >> tg;
2287abfd6fe0SWill Deacon 
228805aed941SWill Deacon 		/* Convert page size of 12,14,16 (log2) to 1,2,3 */
228905aed941SWill Deacon 		cmd->tlbi.tg = (tg - 10) / 2;
229005aed941SWill Deacon 
2291eba8d2f8SJean-Philippe Brucker 		/*
229205aed941SWill Deacon 		 * Determine what level the granule is at. For non-leaf, both
229305aed941SWill Deacon 		 * io-pgtable and SVA pass a nominal last-level granule because
2294298f7889SWill Deacon 		 * they don't know what level(s) actually apply, so ignore that
229548ec83bcSWill Deacon 		 * and leave TTL=0. However for various errata reasons we still
229605aed941SWill Deacon 		 * want to use a range command, so avoid the SVA corner case
2297abfd6fe0SWill Deacon 		 * where both scale and num could be 0 as well.
229848ec83bcSWill Deacon 		 */
229948ec83bcSWill Deacon 		if (cmd->tlbi.leaf)
230025c776ddSKunkun Jiang 			cmd->tlbi.ttl = 4 - ((ilog2(granule) - 3) / (tg - 3));
230125c776ddSKunkun Jiang 		else if ((num_pages & CMDQ_TLBI_RANGE_NUM_MAX) == 1)
230225c776ddSKunkun Jiang 			num_pages++;
230325c776ddSKunkun Jiang 	}
230425c776ddSKunkun Jiang 
230525c776ddSKunkun Jiang 	arm_smmu_cmdq_batch_init(smmu, &cmds, cmd);
230625c776ddSKunkun Jiang 
230748ec83bcSWill Deacon 	while (iova < end) {
2308359ad157SRobin Murphy 		if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
230948ec83bcSWill Deacon 			/*
2310df198b37SRobin Murphy 			 * On each iteration of the loop, the range is 5 bits
2311df198b37SRobin Murphy 			 * worth of the aligned size remaining.
231248ec83bcSWill Deacon 			 * The range in pages is:
231348ec83bcSWill Deacon 			 *
2314df198b37SRobin Murphy 			 * range = (num_pages & (0x1f << __ffs(num_pages)))
2315df198b37SRobin Murphy 			 */
2316e89573cfSJason Gunthorpe 			unsigned long scale, num;
2317e89573cfSJason Gunthorpe 
231848ec83bcSWill Deacon 			/* Determine the power of 2 multiple number of pages */
23194a20ce0fSRobin Murphy 			scale = __ffs(num_pages);
232048ec83bcSWill Deacon 			cmd->tlbi.scale = scale;
232125c776ddSKunkun Jiang 
232225c776ddSKunkun Jiang 			/* Determine how many chunks of 2^scale size we have */
232348ec83bcSWill Deacon 			num = (num_pages >> scale) & CMDQ_TLBI_RANGE_NUM_MAX;
232448ec83bcSWill Deacon 			cmd->tlbi.num = num - 1;
232548ec83bcSWill Deacon 
232648ec83bcSWill Deacon 			/* range is num * 2^scale * pgsize */
232748ec83bcSWill Deacon 			inv_range = num << (scale + tg);
2328e89573cfSJason Gunthorpe 
2329e89573cfSJason Gunthorpe 			/* Clear out the lower order bits for the next iteration */
2330e89573cfSJason Gunthorpe 			num_pages -= num << scale;
2331e89573cfSJason Gunthorpe 		}
2332e89573cfSJason Gunthorpe 
2333e89573cfSJason Gunthorpe 		cmd->tlbi.addr = iova;
2334e89573cfSJason Gunthorpe 		arm_smmu_cmdq_batch_add(smmu, &cmds, cmd);
2335e89573cfSJason Gunthorpe 		iova += inv_range;
2336e89573cfSJason Gunthorpe 	}
2337e89573cfSJason Gunthorpe 	arm_smmu_cmdq_batch_submit(smmu, &cmds);
2338e89573cfSJason Gunthorpe }
2339e89573cfSJason Gunthorpe 
arm_smmu_tlb_inv_range_domain(unsigned long iova,size_t size,size_t granule,bool leaf,struct arm_smmu_domain * smmu_domain)2340e89573cfSJason Gunthorpe static void arm_smmu_tlb_inv_range_domain(unsigned long iova, size_t size,
2341e89573cfSJason Gunthorpe 					  size_t granule, bool leaf,
2342e89573cfSJason Gunthorpe 					  struct arm_smmu_domain *smmu_domain)
2343e89573cfSJason Gunthorpe {
2344e89573cfSJason Gunthorpe 	struct arm_smmu_cmdq_ent cmd = {
2345e89573cfSJason Gunthorpe 		.tlbi = {
2346e89573cfSJason Gunthorpe 			.leaf	= leaf,
2347e89573cfSJason Gunthorpe 		},
2348d7b2d2baSJason Gunthorpe 	};
2349d7b2d2baSJason Gunthorpe 
2350d7b2d2baSJason Gunthorpe 	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
2351d7b2d2baSJason Gunthorpe 		cmd.opcode	= smmu_domain->smmu->features & ARM_SMMU_FEAT_E2H ?
2352d7b2d2baSJason Gunthorpe 				  CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA;
2353d7b2d2baSJason Gunthorpe 		cmd.tlbi.asid	= smmu_domain->cd.asid;
2354d7b2d2baSJason Gunthorpe 	} else {
2355d7b2d2baSJason Gunthorpe 		cmd.opcode	= CMDQ_OP_TLBI_S2_IPA;
2356d7b2d2baSJason Gunthorpe 		cmd.tlbi.vmid	= smmu_domain->s2_cfg.vmid;
2357d7b2d2baSJason Gunthorpe 	}
2358d7b2d2baSJason Gunthorpe 	__arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
2359d7b2d2baSJason Gunthorpe 
2360d7b2d2baSJason Gunthorpe 	if (smmu_domain->nest_parent) {
2361d7b2d2baSJason Gunthorpe 		/*
2362d7b2d2baSJason Gunthorpe 		 * When the S2 domain changes all the nested S1 ASIDs have to be
2363327e10b4SJason Gunthorpe 		 * flushed too.
2364327e10b4SJason Gunthorpe 		 */
2365327e10b4SJason Gunthorpe 		cmd.opcode = CMDQ_OP_TLBI_NH_ALL;
236648ec83bcSWill Deacon 		arm_smmu_cmdq_issue_cmd_with_sync(smmu_domain->smmu, &cmd);
236748ec83bcSWill Deacon 	}
236848ec83bcSWill Deacon 
236948ec83bcSWill Deacon 	/*
237048ec83bcSWill Deacon 	 * Unfortunately, this can't be leaf-only since we may have
237148ec83bcSWill Deacon 	 * zapped an entire table.
2372d7b2d2baSJason Gunthorpe 	 */
2373d7b2d2baSJason Gunthorpe 	arm_smmu_atc_inv_domain(smmu_domain, iova, size);
2374d7b2d2baSJason Gunthorpe }
23752a7e62f5SJean-Philippe Brucker 
arm_smmu_tlb_inv_range_asid(unsigned long iova,size_t size,int asid,size_t granule,bool leaf,struct arm_smmu_domain * smmu_domain)2376327e10b4SJason Gunthorpe void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,
2377327e10b4SJason Gunthorpe 				 size_t granule, bool leaf,
2378327e10b4SJason Gunthorpe 				 struct arm_smmu_domain *smmu_domain)
2379327e10b4SJason Gunthorpe {
2380eb054d67SJoao Martins 	struct arm_smmu_cmdq_ent cmd = {
2381327e10b4SJason Gunthorpe 		.opcode	= smmu_domain->smmu->features & ARM_SMMU_FEAT_E2H ?
2382327e10b4SJason Gunthorpe 			  CMDQ_OP_TLBI_EL2_VA : CMDQ_OP_TLBI_NH_VA,
2383327e10b4SJason Gunthorpe 		.tlbi = {
2384327e10b4SJason Gunthorpe 			.asid	= asid,
2385327e10b4SJason Gunthorpe 			.leaf	= leaf,
238648ec83bcSWill Deacon 		},
238748ec83bcSWill Deacon 	};
238848ec83bcSWill Deacon 
2389d7b2d2baSJason Gunthorpe 	__arm_smmu_tlb_inv_range(&cmd, iova, size, granule, smmu_domain);
239048ec83bcSWill Deacon }
239148ec83bcSWill Deacon 
arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather * gather,unsigned long iova,size_t granule,void * cookie)239248ec83bcSWill Deacon static void arm_smmu_tlb_inv_page_nosync(struct iommu_iotlb_gather *gather,
239348ec83bcSWill Deacon 					 unsigned long iova, size_t granule,
239448ec83bcSWill Deacon 					 void *cookie)
239548ec83bcSWill Deacon {
239610e4968cSMichael Shavit 	struct arm_smmu_domain *smmu_domain = cookie;
239748ec83bcSWill Deacon 	struct iommu_domain *domain = &smmu_domain->domain;
23983f1ce8e8SJean-Philippe Brucker 
23993f1ce8e8SJean-Philippe Brucker 	iommu_iotlb_gather_add_page(domain, gather, iova, granule);
2400d38c28dbSJason Gunthorpe }
24013f1ce8e8SJean-Philippe Brucker 
arm_smmu_tlb_inv_walk(unsigned long iova,size_t size,size_t granule,void * cookie)240248ec83bcSWill Deacon static void arm_smmu_tlb_inv_walk(unsigned long iova, size_t size,
240348ec83bcSWill Deacon 				  size_t granule, void *cookie)
240448ec83bcSWill Deacon {
24051672730cSDawei Li 	arm_smmu_tlb_inv_range_domain(iova, size, granule, false, cookie);
240648ec83bcSWill Deacon }
240748ec83bcSWill Deacon 
240848ec83bcSWill Deacon static const struct iommu_flush_ops arm_smmu_flush_ops = {
240948ec83bcSWill Deacon 	.tlb_flush_all	= arm_smmu_tlb_inv_context,
241048ec83bcSWill Deacon 	.tlb_flush_walk = arm_smmu_tlb_inv_walk,
2411d8cd2006SJason Gunthorpe 	.tlb_add_page	= arm_smmu_tlb_inv_page_nosync,
241204905c17SJason Gunthorpe };
241348ec83bcSWill Deacon 
arm_smmu_dbm_capable(struct arm_smmu_device * smmu)241448ec83bcSWill Deacon static bool arm_smmu_dbm_capable(struct arm_smmu_device *smmu)
2415d3867e71SMostafa Saleh {
2416987a878eSMichael Shavit 	u32 features = (ARM_SMMU_FEAT_HD | ARM_SMMU_FEAT_COHERENCY);
241748ec83bcSWill Deacon 
24183f1ce8e8SJean-Philippe Brucker 	return (smmu->features & features) == features;
24193f1ce8e8SJean-Philippe Brucker }
2420d38c28dbSJason Gunthorpe 
24210299a1a8SJean-Philippe Brucker /* IOMMU API */
arm_smmu_capable(struct device * dev,enum iommu_cap cap)2422987a878eSMichael Shavit static bool arm_smmu_capable(struct device *dev, enum iommu_cap cap)
24233f1ce8e8SJean-Philippe Brucker {
242448ec83bcSWill Deacon 	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
242548ec83bcSWill Deacon 
242648ec83bcSWill Deacon 	switch (cap) {
2427d8cd2006SJason Gunthorpe 	case IOMMU_CAP_CACHE_COHERENCY:
242804905c17SJason Gunthorpe 		/* Assume that a coherent TCU implies coherent TBUs */
242948ec83bcSWill Deacon 		return master->smmu->features & ARM_SMMU_FEAT_COHERENCY;
2430c0733a2cSWill Deacon 	case IOMMU_CAP_ENFORCE_CACHE_COHERENCY:
243148ec83bcSWill Deacon 		return arm_smmu_master_canwbs(master);
243248ec83bcSWill Deacon 	case IOMMU_CAP_NOEXEC:
24331672730cSDawei Li 	case IOMMU_CAP_DEFERRED_FLUSH:
24341672730cSDawei Li 		return true;
24351672730cSDawei Li 	case IOMMU_CAP_DIRTY_TRACKING:
2436287980e4SArnd Bergmann 		return arm_smmu_dbm_capable(master->smmu);
243748ec83bcSWill Deacon 	default:
243848ec83bcSWill Deacon 		return false;
2439c0733a2cSWill Deacon 	}
244048ec83bcSWill Deacon }
244148ec83bcSWill Deacon 
arm_smmu_enforce_cache_coherency(struct iommu_domain * domain)244248ec83bcSWill Deacon static bool arm_smmu_enforce_cache_coherency(struct iommu_domain *domain)
2443d8cd2006SJason Gunthorpe {
2444eb054d67SJoao Martins 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
244548ec83bcSWill Deacon 	struct arm_smmu_master_domain *master_domain;
244648ec83bcSWill Deacon 	unsigned long flags;
244748ec83bcSWill Deacon 	bool ret = true;
244848ec83bcSWill Deacon 
244948ec83bcSWill Deacon 	spin_lock_irqsave(&smmu_domain->devices_lock, flags);
2450d8cd2006SJason Gunthorpe 	list_for_each_entry(master_domain, &smmu_domain->devices,
245104905c17SJason Gunthorpe 			    devices_elm) {
2452eb054d67SJoao Martins 		if (!arm_smmu_master_canwbs(master_domain->master)) {
2453beb3c6a0SWill Deacon 			ret = false;
245448ec83bcSWill Deacon 			break;
245548ec83bcSWill Deacon 		}
245648ec83bcSWill Deacon 	}
245748ec83bcSWill Deacon 	smmu_domain->enforce_cache_coherency = ret;
245848ec83bcSWill Deacon 	spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
245948ec83bcSWill Deacon 	return ret;
2460eb054d67SJoao Martins }
2461eb054d67SJoao Martins 
arm_smmu_domain_alloc(void)2462eb054d67SJoao Martins struct arm_smmu_domain *arm_smmu_domain_alloc(void)
2463eb054d67SJoao Martins {
2464eb054d67SJoao Martins 	struct arm_smmu_domain *smmu_domain;
2465eb054d67SJoao Martins 
2466eb054d67SJoao Martins 	smmu_domain = kzalloc(sizeof(*smmu_domain), GFP_KERNEL);
246748ec83bcSWill Deacon 	if (!smmu_domain)
2468eb054d67SJoao Martins 		return ERR_PTR(-ENOMEM);
2469eb054d67SJoao Martins 
2470eb054d67SJoao Martins 	INIT_LIST_HEAD(&smmu_domain->devices);
2471eb054d67SJoao Martins 	spin_lock_init(&smmu_domain->devices_lock);
2472eb054d67SJoao Martins 
2473eb054d67SJoao Martins 	return smmu_domain;
2474eb054d67SJoao Martins }
2475eb054d67SJoao Martins 
arm_smmu_domain_free_paging(struct iommu_domain * domain)247648ec83bcSWill Deacon static void arm_smmu_domain_free_paging(struct iommu_domain *domain)
247748ec83bcSWill Deacon {
247848ec83bcSWill Deacon 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
2479eb054d67SJoao Martins 	struct arm_smmu_device *smmu = smmu_domain->smmu;
248048ec83bcSWill Deacon 
2481eb054d67SJoao Martins 	free_io_pgtable_ops(smmu_domain->pgtbl_ops);
2482eb054d67SJoao Martins 
2483eb054d67SJoao Martins 	/* Free the ASID or VMID */
2484eb054d67SJoao Martins 	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
248548ec83bcSWill Deacon 		/* Prevent SVA from touching the CD while we're freeing it */
248648ec83bcSWill Deacon 		mutex_lock(&arm_smmu_asid_lock);
248767e4fe39SJason Gunthorpe 		xa_erase(&arm_smmu_asid_xa, smmu_domain->cd.asid);
248867e4fe39SJason Gunthorpe 		mutex_unlock(&arm_smmu_asid_lock);
248967e4fe39SJason Gunthorpe 	} else {
249048ec83bcSWill Deacon 		struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
249148ec83bcSWill Deacon 		if (cfg->vmid)
249248ec83bcSWill Deacon 			ida_free(&smmu->vmid_map, cfg->vmid);
249348ec83bcSWill Deacon 	}
249448ec83bcSWill Deacon 
249548ec83bcSWill Deacon 	kfree(smmu_domain);
249648ec83bcSWill Deacon }
249748ec83bcSWill Deacon 
arm_smmu_domain_finalise_s1(struct arm_smmu_device * smmu,struct arm_smmu_domain * smmu_domain)249848ec83bcSWill Deacon static int arm_smmu_domain_finalise_s1(struct arm_smmu_device *smmu,
2499d8cd2006SJason Gunthorpe 				       struct arm_smmu_domain *smmu_domain)
2500d8cd2006SJason Gunthorpe {
2501d8cd2006SJason Gunthorpe 	int ret;
2502eb054d67SJoao Martins 	u32 asid = 0;
2503eb054d67SJoao Martins 	struct arm_smmu_ctx_desc *cd = &smmu_domain->cd;
250448ec83bcSWill Deacon 
250504905c17SJason Gunthorpe 	/* Prevent SVA from modifying the ASID until it is written to the CD */
250657d72e15SJean-Philippe Brucker 	mutex_lock(&arm_smmu_asid_lock);
250748ec83bcSWill Deacon 	ret = xa_alloc(&arm_smmu_asid_xa, &asid, smmu_domain,
250848ec83bcSWill Deacon 		       XA_LIMIT(1, (1 << smmu->asid_bits) - 1), GFP_KERNEL);
250948ec83bcSWill Deacon 	cd->asid	= (u16)asid;
251048ec83bcSWill Deacon 	mutex_unlock(&arm_smmu_asid_lock);
251157d72e15SJean-Philippe Brucker 	return ret;
2512d8cd2006SJason Gunthorpe }
251357d72e15SJean-Philippe Brucker 
arm_smmu_domain_finalise_s2(struct arm_smmu_device * smmu,struct arm_smmu_domain * smmu_domain)251457d72e15SJean-Philippe Brucker static int arm_smmu_domain_finalise_s2(struct arm_smmu_device *smmu,
251557d72e15SJean-Philippe Brucker 				       struct arm_smmu_domain *smmu_domain)
251657b89048SJason Gunthorpe {
251757b89048SJason Gunthorpe 	int vmid;
251848ec83bcSWill Deacon 	struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
251948ec83bcSWill Deacon 
252048ec83bcSWill Deacon 	/* Reserve VMID 0 for stage-2 bypass STEs */
252148ec83bcSWill Deacon 	vmid = ida_alloc_range(&smmu->vmid_map, 1, (1 << smmu->vmid_bits) - 1,
252248ec83bcSWill Deacon 			       GFP_KERNEL);
252385196f54SJason Gunthorpe 	if (vmid < 0)
252485196f54SJason Gunthorpe 		return vmid;
252548ec83bcSWill Deacon 
252648ec83bcSWill Deacon 	cfg->vmid	= (u16)vmid;
252785196f54SJason Gunthorpe 	return 0;
252848ec83bcSWill Deacon }
252948ec83bcSWill Deacon 
arm_smmu_domain_finalise(struct arm_smmu_domain * smmu_domain,struct arm_smmu_device * smmu,u32 flags)253048ec83bcSWill Deacon static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
2531f6681abdSJason Gunthorpe 				    struct arm_smmu_device *smmu, u32 flags)
253265547275SJason Gunthorpe {
253348ec83bcSWill Deacon 	int ret;
2534563b5cbeSRobin Murphy 	enum io_pgtable_fmt fmt;
25358f785154SRobin Murphy 	struct io_pgtable_cfg pgtbl_cfg;
253648ec83bcSWill Deacon 	struct io_pgtable_ops *pgtbl_ops;
253785f2fb6eSJason Gunthorpe 	int (*finalise_stage_fn)(struct arm_smmu_device *smmu,
253885f2fb6eSJason Gunthorpe 				 struct arm_smmu_domain *smmu_domain);
253985f2fb6eSJason Gunthorpe 	bool enable_dirty = flags & IOMMU_HWPT_ALLOC_DIRTY_TRACKING;
25408ee9175cSJason Gunthorpe 
25418ee9175cSJason Gunthorpe 	pgtbl_cfg = (struct io_pgtable_cfg) {
25428ee9175cSJason Gunthorpe 		.pgsize_bitmap	= smmu->pgsize_bitmap,
254385f2fb6eSJason Gunthorpe 		.coherent_walk	= smmu->features & ARM_SMMU_FEAT_COHERENCY,
2544cdf315f9SJean-Philippe Brucker 		.tlb		= &arm_smmu_flush_ops,
2545cdf315f9SJean-Philippe Brucker 		.iommu_dev	= smmu->dev,
254657b89048SJason Gunthorpe 	};
254757b89048SJason Gunthorpe 
254848ec83bcSWill Deacon 	switch (smmu_domain->stage) {
2549563b5cbeSRobin Murphy 	case ARM_SMMU_DOMAIN_S1: {
2550563b5cbeSRobin Murphy 		unsigned long ias = (smmu->features &
2551cdf315f9SJean-Philippe Brucker 				     ARM_SMMU_FEAT_VAX) ? 52 : 48;
2552563b5cbeSRobin Murphy 
2553563b5cbeSRobin Murphy 		pgtbl_cfg.ias = min_t(unsigned long, ias, VA_BITS);
2554563b5cbeSRobin Murphy 		pgtbl_cfg.oas = smmu->ias;
2555563b5cbeSRobin Murphy 		if (enable_dirty)
255665547275SJason Gunthorpe 			pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_ARM_HD;
255748ec83bcSWill Deacon 		fmt = ARM_64_LPAE_S1;
255848ec83bcSWill Deacon 		finalise_stage_fn = arm_smmu_domain_finalise_s1;
255948ec83bcSWill Deacon 		break;
2560bfff88ecSWill Deacon 	}
25619ce27afcSJean-Philippe Brucker 	case ARM_SMMU_DOMAIN_S2:
25620b2527a6SJean-Philippe Brucker 		if (enable_dirty)
25639ce27afcSJean-Philippe Brucker 			return -EOPNOTSUPP;
25640b2527a6SJean-Philippe Brucker 		pgtbl_cfg.ias = smmu->ias;
25659ce27afcSJean-Philippe Brucker 		pgtbl_cfg.oas = smmu->oas;
25660b2527a6SJean-Philippe Brucker 		fmt = ARM_64_LPAE_S2;
2567bfff88ecSWill Deacon 		finalise_stage_fn = arm_smmu_domain_finalise_s2;
25689ce27afcSJean-Philippe Brucker 		if ((smmu->features & ARM_SMMU_FEAT_S2FWB) &&
25690b2527a6SJean-Philippe Brucker 		    (flags & IOMMU_HWPT_ALLOC_NEST_PARENT))
2570097a7df2SYueHaibing 			pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_ARM_S2FWB;
25710b2527a6SJean-Philippe Brucker 		break;
25720b2527a6SJean-Philippe Brucker 	default:
2573097a7df2SYueHaibing 		return -EINVAL;
2574bfff88ecSWill Deacon 	}
25757497f421SJason Gunthorpe 
2576bfff88ecSWill Deacon 	pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain);
2577bfff88ecSWill Deacon 	if (!pgtbl_ops)
2578bfff88ecSWill Deacon 		return -ENOMEM;
2579bfff88ecSWill Deacon 
2580bfff88ecSWill Deacon 	smmu_domain->domain.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
25819ce27afcSJean-Philippe Brucker 	smmu_domain->domain.geometry.aperture_end = (1UL << pgtbl_cfg.ias) - 1;
25829ce27afcSJean-Philippe Brucker 	smmu_domain->domain.geometry.force_aperture = true;
2583bfff88ecSWill Deacon 	if (enable_dirty && smmu_domain->stage == ARM_SMMU_DOMAIN_S1)
25849ce27afcSJean-Philippe Brucker 		smmu_domain->domain.dirty_ops = &arm_smmu_dirty_ops;
258586e5ca09SJason Gunthorpe 
258686e5ca09SJason Gunthorpe 	ret = finalise_stage_fn(smmu, smmu_domain);
258786e5ca09SJason Gunthorpe 	if (ret < 0) {
25881d5f34f0SJason Gunthorpe 		free_io_pgtable_ops(pgtbl_ops);
2589bfff88ecSWill Deacon 		return ret;
2590bfff88ecSWill Deacon 	}
25919ce27afcSJean-Philippe Brucker 
25929ce27afcSJean-Philippe Brucker 	smmu_domain->pgtbl_ops = pgtbl_ops;
2593058c59a0SJean-Philippe Brucker 	smmu_domain->smmu = smmu;
2594058c59a0SJean-Philippe Brucker 	return 0;
2595058c59a0SJean-Philippe Brucker }
2596058c59a0SJean-Philippe Brucker 
2597058c59a0SJean-Philippe Brucker static struct arm_smmu_ste *
arm_smmu_get_step_for_sid(struct arm_smmu_device * smmu,u32 sid)2598058c59a0SJean-Philippe Brucker arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
2599058c59a0SJean-Philippe Brucker {
2600058c59a0SJean-Philippe Brucker 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
2601058c59a0SJean-Philippe Brucker 
2602058c59a0SJean-Philippe Brucker 	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
2603058c59a0SJean-Philippe Brucker 		/* Two-level walk */
2604058c59a0SJean-Philippe Brucker 		return &cfg->l2.l2ptrs[arm_smmu_strtab_l1_idx(sid)]
2605058c59a0SJean-Philippe Brucker 				->stes[arm_smmu_strtab_l2_idx(sid)];
2606058c59a0SJean-Philippe Brucker 	} else {
2607058c59a0SJean-Philippe Brucker 		/* Simple linear lookup */
2608058c59a0SJean-Philippe Brucker 		return &cfg->linear.table[sid];
2609058c59a0SJean-Philippe Brucker 	}
2610058c59a0SJean-Philippe Brucker }
2611058c59a0SJean-Philippe Brucker 
arm_smmu_install_ste_for_dev(struct arm_smmu_master * master,const struct arm_smmu_ste * target)2612058c59a0SJean-Philippe Brucker void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master,
2613058c59a0SJean-Philippe Brucker 				  const struct arm_smmu_ste *target)
2614058c59a0SJean-Philippe Brucker {
2615058c59a0SJean-Philippe Brucker 	int i, j;
2616058c59a0SJean-Philippe Brucker 	struct arm_smmu_device *smmu = master->smmu;
2617058c59a0SJean-Philippe Brucker 
2618058c59a0SJean-Philippe Brucker 	master->cd_table.in_ste =
2619058c59a0SJean-Philippe Brucker 		FIELD_GET(STRTAB_STE_0_CFG, le64_to_cpu(target->data[0])) ==
2620058c59a0SJean-Philippe Brucker 		STRTAB_STE_0_CFG_S1_TRANS;
2621058c59a0SJean-Philippe Brucker 	master->ste_ats_enabled =
2622058c59a0SJean-Philippe Brucker 		FIELD_GET(STRTAB_STE_1_EATS, le64_to_cpu(target->data[1])) ==
2623058c59a0SJean-Philippe Brucker 		STRTAB_STE_1_EATS_TRANS;
2624058c59a0SJean-Philippe Brucker 
2625058c59a0SJean-Philippe Brucker 	for (i = 0; i < master->num_streams; ++i) {
2626058c59a0SJean-Philippe Brucker 		u32 sid = master->streams[i].id;
2627058c59a0SJean-Philippe Brucker 		struct arm_smmu_ste *step =
2628058c59a0SJean-Philippe Brucker 			arm_smmu_get_step_for_sid(smmu, sid);
2629058c59a0SJean-Philippe Brucker 
2630058c59a0SJean-Philippe Brucker 		/* Bridged PCI devices may end up with duplicated IDs */
2631058c59a0SJean-Philippe Brucker 		for (j = 0; j < i; j++)
2632058c59a0SJean-Philippe Brucker 			if (master->streams[j].id == sid)
2633058c59a0SJean-Philippe Brucker 				break;
2634058c59a0SJean-Philippe Brucker 		if (j < i)
2635058c59a0SJean-Philippe Brucker 			continue;
2636058c59a0SJean-Philippe Brucker 
2637058c59a0SJean-Philippe Brucker 		arm_smmu_write_ste(master, sid, step, target);
2638058c59a0SJean-Philippe Brucker 	}
2639058c59a0SJean-Philippe Brucker }
2640ad10dce6SJason Gunthorpe 
arm_smmu_ats_supported(struct arm_smmu_master * master)2641ad10dce6SJason Gunthorpe static bool arm_smmu_ats_supported(struct arm_smmu_master *master)
264264efb3deSJason Gunthorpe {
2643f27298a8SJason Gunthorpe 	struct device *dev = master->dev;
2644ad10dce6SJason Gunthorpe 	struct arm_smmu_device *smmu = master->smmu;
2645ad10dce6SJason Gunthorpe 	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
2646ad10dce6SJason Gunthorpe 
2647ad10dce6SJason Gunthorpe 	if (!(smmu->features & ARM_SMMU_FEAT_ATS))
2648ad10dce6SJason Gunthorpe 		return false;
2649ad10dce6SJason Gunthorpe 
2650ad10dce6SJason Gunthorpe 	if (!(fwspec->flags & IOMMU_FWSPEC_PCI_RC_ATS))
265164efb3deSJason Gunthorpe 		return false;
2652f27298a8SJason Gunthorpe 
2653f27298a8SJason Gunthorpe 	return dev_is_pci(dev) && pci_ats_supported(to_pci_dev(dev));
2654ad10dce6SJason Gunthorpe }
2655ad10dce6SJason Gunthorpe 
arm_smmu_enable_ats(struct arm_smmu_master * master)2656ad10dce6SJason Gunthorpe static void arm_smmu_enable_ats(struct arm_smmu_master *master)
2657ad10dce6SJason Gunthorpe {
2658ad10dce6SJason Gunthorpe 	size_t stu;
26597497f421SJason Gunthorpe 	struct pci_dev *pdev;
26607497f421SJason Gunthorpe 	struct arm_smmu_device *smmu = master->smmu;
26617497f421SJason Gunthorpe 
26627497f421SJason Gunthorpe 	/* Smallest Translation Unit: log2 of the smallest supported granule */
26637497f421SJason Gunthorpe 	stu = __ffs(smmu->pgsize_bitmap);
26647497f421SJason Gunthorpe 	pdev = to_pci_dev(master->dev);
26657497f421SJason Gunthorpe 
2666bc7f2ce0SWill Deacon 	/*
26677497f421SJason Gunthorpe 	 * ATC invalidation of PASID 0 causes the entire ATC to be flushed.
26687497f421SJason Gunthorpe 	 */
26697497f421SJason Gunthorpe 	arm_smmu_atc_inv_master(master, IOMMU_NO_PASID);
267049db2ed2SJason Gunthorpe 	if (pci_enable_ats(pdev, stu))
267149db2ed2SJason Gunthorpe 		dev_err(master->dev, "Failed to enable ATS (STU %zu)\n", stu);
26727497f421SJason Gunthorpe }
26731e8be08dSJason Gunthorpe 
arm_smmu_enable_pasid(struct arm_smmu_master * master)26741e8be08dSJason Gunthorpe static int arm_smmu_enable_pasid(struct arm_smmu_master *master)
26757497f421SJason Gunthorpe {
26767497f421SJason Gunthorpe 	int ret;
26777497f421SJason Gunthorpe 	int features;
26787497f421SJason Gunthorpe 	int num_pasids;
26791d5f34f0SJason Gunthorpe 	struct pci_dev *pdev;
26801d5f34f0SJason Gunthorpe 
26817497f421SJason Gunthorpe 	if (!dev_is_pci(master->dev))
26827497f421SJason Gunthorpe 		return -ENODEV;
2683ad10dce6SJason Gunthorpe 
2684f27298a8SJason Gunthorpe 	pdev = to_pci_dev(master->dev);
26852a7e62f5SJean-Philippe Brucker 
26862a7e62f5SJean-Philippe Brucker 	features = pci_pasid_features(pdev);
26877497f421SJason Gunthorpe 	if (features < 0)
26888be39a1aSJean-Philippe Brucker 		return features;
26898be39a1aSJean-Philippe Brucker 
2690f27298a8SJason Gunthorpe 	num_pasids = pci_max_pasids(pdev);
2691f27298a8SJason Gunthorpe 	if (num_pasids <= 0)
2692f27298a8SJason Gunthorpe 		return num_pasids;
26932a7e62f5SJean-Philippe Brucker 
2694f27298a8SJason Gunthorpe 	ret = pci_enable_pasid(pdev, features);
2695f27298a8SJason Gunthorpe 	if (ret) {
2696ad10dce6SJason Gunthorpe 		dev_err(&pdev->dev, "Failed to enable PASID\n");
2697ad10dce6SJason Gunthorpe 		return ret;
2698ad10dce6SJason Gunthorpe 	}
26997497f421SJason Gunthorpe 
27007497f421SJason Gunthorpe 	master->ssid_bits = min_t(u8, ilog2(num_pasids),
2701ad10dce6SJason Gunthorpe 				  master->smmu->ssid_bits);
27022a7e62f5SJean-Philippe Brucker 	return 0;
27037497f421SJason Gunthorpe }
27042a7e62f5SJean-Philippe Brucker 
arm_smmu_disable_pasid(struct arm_smmu_master * master)27057497f421SJason Gunthorpe static void arm_smmu_disable_pasid(struct arm_smmu_master *master)
27067497f421SJason Gunthorpe {
27077497f421SJason Gunthorpe 	struct pci_dev *pdev;
27087497f421SJason Gunthorpe 
27097497f421SJason Gunthorpe 	if (!dev_is_pci(master->dev))
27107497f421SJason Gunthorpe 		return;
27117497f421SJason Gunthorpe 
27127497f421SJason Gunthorpe 	pdev = to_pci_dev(master->dev);
27137497f421SJason Gunthorpe 
27147497f421SJason Gunthorpe 	if (!pdev->pasid_enabled)
27157497f421SJason Gunthorpe 		return;
27167497f421SJason Gunthorpe 
27177497f421SJason Gunthorpe 	master->ssid_bits = 0;
27187497f421SJason Gunthorpe 	pci_disable_pasid(pdev);
27197497f421SJason Gunthorpe }
27207497f421SJason Gunthorpe 
27217497f421SJason Gunthorpe static struct arm_smmu_master_domain *
arm_smmu_find_master_domain(struct arm_smmu_domain * smmu_domain,struct iommu_domain * domain,struct arm_smmu_master * master,ioasid_t ssid,bool nested_ats_flush)27227497f421SJason Gunthorpe arm_smmu_find_master_domain(struct arm_smmu_domain *smmu_domain,
27237497f421SJason Gunthorpe 			    struct iommu_domain *domain,
27247497f421SJason Gunthorpe 			    struct arm_smmu_master *master,
2725f6681abdSJason Gunthorpe 			    ioasid_t ssid, bool nested_ats_flush)
27267497f421SJason Gunthorpe {
27277497f421SJason Gunthorpe 	struct arm_smmu_master_domain *master_domain;
27287497f421SJason Gunthorpe 
27297497f421SJason Gunthorpe 	lockdep_assert_held(&smmu_domain->devices_lock);
27307497f421SJason Gunthorpe 
27317497f421SJason Gunthorpe 	list_for_each_entry(master_domain, &smmu_domain->devices,
27327497f421SJason Gunthorpe 			    devices_elm) {
27337497f421SJason Gunthorpe 		if (master_domain->master == master &&
27347497f421SJason Gunthorpe 		    master_domain->domain == domain &&
27357497f421SJason Gunthorpe 		    master_domain->ssid == ssid &&
27367497f421SJason Gunthorpe 		    master_domain->nested_ats_flush == nested_ats_flush)
27377497f421SJason Gunthorpe 			return master_domain;
27387497f421SJason Gunthorpe 	}
27397497f421SJason Gunthorpe 	return NULL;
27407497f421SJason Gunthorpe }
2741ce26ea9eSJason Gunthorpe 
27427497f421SJason Gunthorpe /*
27437497f421SJason Gunthorpe  * If the domain uses the smmu_domain->devices list return the arm_smmu_domain
27447497f421SJason Gunthorpe  * structure, otherwise NULL. These domains track attached devices so they can
27457497f421SJason Gunthorpe  * issue invalidations.
27467497f421SJason Gunthorpe  */
27477497f421SJason Gunthorpe static struct arm_smmu_domain *
to_smmu_domain_devices(struct iommu_domain * domain)27487497f421SJason Gunthorpe to_smmu_domain_devices(struct iommu_domain *domain)
27497497f421SJason Gunthorpe {
27507497f421SJason Gunthorpe 	/* The domain can be NULL only when processing the first attach */
27517497f421SJason Gunthorpe 	if (!domain)
27521e8be08dSJason Gunthorpe 		return NULL;
27531e8be08dSJason Gunthorpe 	if ((domain->type & __IOMMU_DOMAIN_PAGING) ||
2754ce26ea9eSJason Gunthorpe 	    domain->type == IOMMU_DOMAIN_SVA)
27557497f421SJason Gunthorpe 		return to_smmu_domain(domain);
2756ce26ea9eSJason Gunthorpe 	if (domain->type == IOMMU_DOMAIN_NESTED)
27577497f421SJason Gunthorpe 		return to_smmu_nested_domain(domain)->vsmmu->s2_parent;
27587497f421SJason Gunthorpe 	return NULL;
27597497f421SJason Gunthorpe }
27607497f421SJason Gunthorpe 
arm_smmu_enable_iopf(struct arm_smmu_master * master,struct arm_smmu_master_domain * master_domain)27611d5f34f0SJason Gunthorpe static int arm_smmu_enable_iopf(struct arm_smmu_master *master,
2762f27298a8SJason Gunthorpe 				struct arm_smmu_master_domain *master_domain)
2763f27298a8SJason Gunthorpe {
2764f27298a8SJason Gunthorpe 	int ret;
27657497f421SJason Gunthorpe 
27667497f421SJason Gunthorpe 	iommu_group_mutex_assert(master->dev);
27677497f421SJason Gunthorpe 
27687497f421SJason Gunthorpe 	if (!IS_ENABLED(CONFIG_ARM_SMMU_V3_SVA))
27697497f421SJason Gunthorpe 		return -EOPNOTSUPP;
27707497f421SJason Gunthorpe 
27717497f421SJason Gunthorpe 	/*
27727497f421SJason Gunthorpe 	 * Drivers for devices supporting PRI or stall require iopf others have
27737497f421SJason Gunthorpe 	 * device-specific fault handlers and don't need IOPF, so this is not a
27747497f421SJason Gunthorpe 	 * failure.
27757497f421SJason Gunthorpe 	 */
27767497f421SJason Gunthorpe 	if (!master->stall_enabled)
27777497f421SJason Gunthorpe 		return 0;
27787497f421SJason Gunthorpe 
27797497f421SJason Gunthorpe 	/* We're not keeping track of SIDs in fault events */
27807497f421SJason Gunthorpe 	if (master->num_streams != 1)
2781e89573cfSJason Gunthorpe 		return -EOPNOTSUPP;
2782e89573cfSJason Gunthorpe 
2783e89573cfSJason Gunthorpe 	if (master->iopf_refcount) {
2784e89573cfSJason Gunthorpe 		master->iopf_refcount++;
2785e89573cfSJason Gunthorpe 		master_domain->using_iopf = true;
2786e89573cfSJason Gunthorpe 		return 0;
2787e89573cfSJason Gunthorpe 	}
2788e89573cfSJason Gunthorpe 
27897497f421SJason Gunthorpe 	ret = iopf_queue_add_device(master->smmu->evtq.iopf, master->dev);
27907497f421SJason Gunthorpe 	if (ret)
27917497f421SJason Gunthorpe 		return ret;
27927497f421SJason Gunthorpe 	master->iopf_refcount = 1;
27937497f421SJason Gunthorpe 	master_domain->using_iopf = true;
27947497f421SJason Gunthorpe 	return 0;
27957497f421SJason Gunthorpe }
27967497f421SJason Gunthorpe 
arm_smmu_disable_iopf(struct arm_smmu_master * master,struct arm_smmu_master_domain * master_domain)27977497f421SJason Gunthorpe static void arm_smmu_disable_iopf(struct arm_smmu_master *master,
27987497f421SJason Gunthorpe 				  struct arm_smmu_master_domain *master_domain)
27997497f421SJason Gunthorpe {
28007497f421SJason Gunthorpe 	iommu_group_mutex_assert(master->dev);
28017497f421SJason Gunthorpe 
28027497f421SJason Gunthorpe 	if (!IS_ENABLED(CONFIG_ARM_SMMU_V3_SVA))
28037497f421SJason Gunthorpe 		return;
28047497f421SJason Gunthorpe 
28057497f421SJason Gunthorpe 	if (!master_domain || !master_domain->using_iopf)
28067497f421SJason Gunthorpe 		return;
28077497f421SJason Gunthorpe 
28087497f421SJason Gunthorpe 	master->iopf_refcount--;
28097497f421SJason Gunthorpe 	if (master->iopf_refcount == 0)
28107497f421SJason Gunthorpe 		iopf_queue_remove_device(master->smmu->evtq.iopf, master->dev);
28117497f421SJason Gunthorpe }
2812f6681abdSJason Gunthorpe 
arm_smmu_remove_master_domain(struct arm_smmu_master * master,struct iommu_domain * domain,ioasid_t ssid)28137497f421SJason Gunthorpe static void arm_smmu_remove_master_domain(struct arm_smmu_master *master,
28147497f421SJason Gunthorpe 					  struct iommu_domain *domain,
28157497f421SJason Gunthorpe 					  ioasid_t ssid)
28167497f421SJason Gunthorpe {
28177497f421SJason Gunthorpe 	struct arm_smmu_domain *smmu_domain = to_smmu_domain_devices(domain);
28187497f421SJason Gunthorpe 	struct arm_smmu_master_domain *master_domain;
28197497f421SJason Gunthorpe 	bool nested_ats_flush = false;
28201d5f34f0SJason Gunthorpe 	unsigned long flags;
28217497f421SJason Gunthorpe 
28227497f421SJason Gunthorpe 	if (!smmu_domain)
28237497f421SJason Gunthorpe 		return;
28247497f421SJason Gunthorpe 
28257497f421SJason Gunthorpe 	if (domain->type == IOMMU_DOMAIN_NESTED)
28261d5f34f0SJason Gunthorpe 		nested_ats_flush = to_smmu_nested_domain(domain)->enable_ats;
28271d5f34f0SJason Gunthorpe 
28281d5f34f0SJason Gunthorpe 	spin_lock_irqsave(&smmu_domain->devices_lock, flags);
28291d5f34f0SJason Gunthorpe 	master_domain = arm_smmu_find_master_domain(smmu_domain, domain, master,
28307497f421SJason Gunthorpe 						    ssid, nested_ats_flush);
28317497f421SJason Gunthorpe 	if (master_domain) {
28327497f421SJason Gunthorpe 		list_del(&master_domain->devices_elm);
28331d5f34f0SJason Gunthorpe 		if (master->ats_enabled)
2834bc7f2ce0SWill Deacon 			atomic_dec(&smmu_domain->nr_ats_masters);
2835bc7f2ce0SWill Deacon 	}
283648ec83bcSWill Deacon 	spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
283748ec83bcSWill Deacon 
283848ec83bcSWill Deacon 	arm_smmu_disable_iopf(master, master_domain);
283965547275SJason Gunthorpe 	kfree(master_domain);
28409b468f7dSJoerg Roedel }
284148ec83bcSWill Deacon 
284248ec83bcSWill Deacon /*
28437497f421SJason Gunthorpe  * Start the sequence to attach a domain to a master. The sequence contains three
28447497f421SJason Gunthorpe  * steps:
28451d5f34f0SJason Gunthorpe  *  arm_smmu_attach_prepare()
28467497f421SJason Gunthorpe  *  arm_smmu_install_ste_for_dev()
2847b54f4260SJean-Philippe Brucker  *  arm_smmu_attach_commit()
284813abe4faSJason Gunthorpe  *
284948ec83bcSWill Deacon  * If prepare succeeds then the sequence must be completed. The STE installed
28509b468f7dSJoerg Roedel  * must set the STE.EATS field according to state.ats_enabled.
285148ec83bcSWill Deacon  *
285248ec83bcSWill Deacon  * If the device supports ATS then this determines if EATS should be enabled
28537497f421SJason Gunthorpe  * in the STE, and starts sequencing EATS disable if required.
28548f785154SRobin Murphy  *
28558f785154SRobin Murphy  * The change of the EATS in the STE and the PCI ATS config space is managed by
285648ec83bcSWill Deacon  * this sequence to be in the right order so that if PCI ATS is enabled then
285748ec83bcSWill Deacon  * STE.ETAS is enabled.
285848ec83bcSWill Deacon  *
2859eb054d67SJoao Martins  * new_domain can be a non-paging domain. In this case ATS will not be enabled,
286010e4968cSMichael Shavit  * and invalidations won't be tracked.
2861f4a14773SNicolin Chen  */
arm_smmu_attach_prepare(struct arm_smmu_attach_state * state,struct iommu_domain * new_domain)286210e4968cSMichael Shavit int arm_smmu_attach_prepare(struct arm_smmu_attach_state *state,
286310e4968cSMichael Shavit 			    struct iommu_domain *new_domain)
286410e4968cSMichael Shavit {
286510e4968cSMichael Shavit 	struct arm_smmu_master *master = state->master;
286648ec83bcSWill Deacon 	struct arm_smmu_master_domain *master_domain;
286713abe4faSJason Gunthorpe 	struct arm_smmu_domain *smmu_domain =
286813abe4faSJason Gunthorpe 		to_smmu_domain_devices(new_domain);
286913abe4faSJason Gunthorpe 	unsigned long flags;
287013abe4faSJason Gunthorpe 	int ret;
2871be7c90deSJason Gunthorpe 
2872be7c90deSJason Gunthorpe 	/*
287313abe4faSJason Gunthorpe 	 * arm_smmu_share_asid() must not see two domains pointing to the same
28748c153645SJean-Philippe Brucker 	 * arm_smmu_master_domain contents otherwise it could randomly write one
28759f7c6891SJason Gunthorpe 	 * or the other to the CD.
28769f7c6891SJason Gunthorpe 	 */
28779f7c6891SJason Gunthorpe 	lockdep_assert_held(&arm_smmu_asid_lock);
28789f7c6891SJason Gunthorpe 
28798c153645SJean-Philippe Brucker 	if (smmu_domain || state->cd_needs_ats) {
28809f7c6891SJason Gunthorpe 		/*
28819f7c6891SJason Gunthorpe 		 * The SMMU does not support enabling ATS with bypass/abort.
28827497f421SJason Gunthorpe 		 * When the STE is in bypass (STE.Config[2:0] == 0b100), ATS
28837497f421SJason Gunthorpe 		 * Translation Requests and Translated transactions are denied
28847497f421SJason Gunthorpe 		 * as though ATS is disabled for the stream (STE.EATS == 0b00),
28857497f421SJason Gunthorpe 		 * causing F_BAD_ATS_TREQ and F_TRANSL_FORBIDDEN events
28867497f421SJason Gunthorpe 		 * (IHI0070Ea 5.2 Stream Table Entry).
2887cdb8a3c3SWill Deacon 		 *
288865547275SJason Gunthorpe 		 * However, if we have installed a CD table and are using S1DSS
2889e9d1e4ffSJason Gunthorpe 		 * then ATS will work in S1DSS bypass. See "13.6.4 Full ATS
2890e9d1e4ffSJason Gunthorpe 		 * skipping stage 1".
2891cdb8a3c3SWill Deacon 		 *
2892e9d1e4ffSJason Gunthorpe 		 * Disable ATS if we are going to create a normal 0b100 bypass
2893e9d1e4ffSJason Gunthorpe 		 * STE.
2894e9d1e4ffSJason Gunthorpe 		 */
2895ce26ea9eSJason Gunthorpe 		state->ats_enabled = !state->disable_ats &&
2896ce26ea9eSJason Gunthorpe 				     arm_smmu_ats_supported(master);
2897d2e053d7SJason Gunthorpe 	}
289865547275SJason Gunthorpe 
2899e9d1e4ffSJason Gunthorpe 	if (smmu_domain) {
290065547275SJason Gunthorpe 		if (new_domain->type == IOMMU_DOMAIN_NESTED) {
29017497f421SJason Gunthorpe 			ret = arm_smmu_attach_prepare_vmaster(
29027497f421SJason Gunthorpe 				state, to_smmu_nested_domain(new_domain));
2903d2e053d7SJason Gunthorpe 			if (ret)
2904af8f0b83SJason Gunthorpe 				return ret;
290565547275SJason Gunthorpe 		}
290610e4968cSMichael Shavit 
290710e4968cSMichael Shavit 		master_domain = kzalloc(sizeof(*master_domain), GFP_KERNEL);
29087497f421SJason Gunthorpe 		if (!master_domain) {
29099f7c6891SJason Gunthorpe 			ret = -ENOMEM;
291013abe4faSJason Gunthorpe 			goto err_free_vmaster;
291148ec83bcSWill Deacon 		}
291248ec83bcSWill Deacon 		master_domain->domain = new_domain;
2913f3b273b7SJason Gunthorpe 		master_domain->master = master;
2914b45a3777SYi Liu 		master_domain->ssid = state->ssid;
2915b45a3777SYi Liu 		if (new_domain->type == IOMMU_DOMAIN_NESTED)
2916f3b273b7SJason Gunthorpe 			master_domain->nested_ats_flush =
2917f3b273b7SJason Gunthorpe 				to_smmu_nested_domain(new_domain)->enable_ats;
2918f3b273b7SJason Gunthorpe 
2919f3b273b7SJason Gunthorpe 		if (new_domain->iopf_handler) {
2920f3b273b7SJason Gunthorpe 			ret = arm_smmu_enable_iopf(master, master_domain);
2921f3b273b7SJason Gunthorpe 			if (ret)
2922f3b273b7SJason Gunthorpe 				goto err_free_master_domain;
2923f3b273b7SJason Gunthorpe 		}
2924f3b273b7SJason Gunthorpe 
2925eb054d67SJoao Martins 		/*
2926f3b273b7SJason Gunthorpe 		 * During prepare we want the current smmu_domain and new
2927f3b273b7SJason Gunthorpe 		 * smmu_domain to be in the devices list before we change any
2928f3b273b7SJason Gunthorpe 		 * HW. This ensures that both domains will send ATS
2929f3b273b7SJason Gunthorpe 		 * invalidations to the master until we are done.
2930f3b273b7SJason Gunthorpe 		 *
2931f3b273b7SJason Gunthorpe 		 * It is tempting to make this list only track masters that are
2932f3b273b7SJason Gunthorpe 		 * using ATS, but arm_smmu_share_asid() also uses this to change
2933f3b273b7SJason Gunthorpe 		 * the ASID of a domain, unrelated to ATS.
2934f3b273b7SJason Gunthorpe 		 *
2935f3b273b7SJason Gunthorpe 		 * Notice if we are re-attaching the same domain then the list
2936f3b273b7SJason Gunthorpe 		 * will have two identical entries and commit will remove only
2937f3b273b7SJason Gunthorpe 		 * one of them.
2938f3b273b7SJason Gunthorpe 		 */
2939f3b273b7SJason Gunthorpe 		spin_lock_irqsave(&smmu_domain->devices_lock, flags);
2940f3b273b7SJason Gunthorpe 		if (smmu_domain->enforce_cache_coherency &&
2941e9f1f727SJason Gunthorpe 		    !arm_smmu_master_canwbs(master)) {
2942f3b273b7SJason Gunthorpe 			spin_unlock_irqrestore(&smmu_domain->devices_lock,
2943f3b273b7SJason Gunthorpe 					       flags);
29448ee9175cSJason Gunthorpe 			ret = -EINVAL;
29458ee9175cSJason Gunthorpe 			goto err_iopf;
29468ee9175cSJason Gunthorpe 		}
29478ee9175cSJason Gunthorpe 
29488ee9175cSJason Gunthorpe 		if (state->ats_enabled)
29498ee9175cSJason Gunthorpe 			atomic_inc(&smmu_domain->nr_ats_masters);
29508ee9175cSJason Gunthorpe 		list_add(&master_domain->devices_elm, &smmu_domain->devices);
29518ee9175cSJason Gunthorpe 		spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
29528ee9175cSJason Gunthorpe 	}
29538ee9175cSJason Gunthorpe 
29548ee9175cSJason Gunthorpe 	if (!state->ats_enabled && master->ats_enabled) {
29558ee9175cSJason Gunthorpe 		pci_disable_ats(to_pci_dev(master->dev));
29568ee9175cSJason Gunthorpe 		/*
29578ee9175cSJason Gunthorpe 		 * This is probably overkill, but the config write for disabling
29588ee9175cSJason Gunthorpe 		 * ATS should complete before the STE is configured to generate
29598ee9175cSJason Gunthorpe 		 * UR to avoid AER noise.
29608ee9175cSJason Gunthorpe 		 */
29618ee9175cSJason Gunthorpe 		wmb();
29628ee9175cSJason Gunthorpe 	}
29638ee9175cSJason Gunthorpe 	return 0;
29648ee9175cSJason Gunthorpe 
29658ee9175cSJason Gunthorpe err_iopf:
29668ee9175cSJason Gunthorpe 	arm_smmu_disable_iopf(master, master_domain);
29678ee9175cSJason Gunthorpe err_free_master_domain:
29688ee9175cSJason Gunthorpe 	kfree(master_domain);
296985f2fb6eSJason Gunthorpe err_free_vmaster:
297085f2fb6eSJason Gunthorpe 	kfree(state->vmaster);
2971e9f1f727SJason Gunthorpe 	return ret;
297285f2fb6eSJason Gunthorpe }
29738ee9175cSJason Gunthorpe 
297449db2ed2SJason Gunthorpe /*
297549db2ed2SJason Gunthorpe  * Commit is done after the STE/CD are configured with the EATS setting. It
297649db2ed2SJason Gunthorpe  * completes synchronizing the PCI device's ATC and finishes manipulating the
2977e9f1f727SJason Gunthorpe  * smmu_domain->devices list.
297849db2ed2SJason Gunthorpe  */
arm_smmu_attach_commit(struct arm_smmu_attach_state * state)297985f2fb6eSJason Gunthorpe void arm_smmu_attach_commit(struct arm_smmu_attach_state *state)
298049db2ed2SJason Gunthorpe {
298185f2fb6eSJason Gunthorpe 	struct arm_smmu_master *master = state->master;
298285f2fb6eSJason Gunthorpe 
298385f2fb6eSJason Gunthorpe 	lockdep_assert_held(&arm_smmu_asid_lock);
2984d38c28dbSJason Gunthorpe 
2985d38c28dbSJason Gunthorpe 	arm_smmu_attach_commit_vmaster(state);
2986d38c28dbSJason Gunthorpe 
29878ee9175cSJason Gunthorpe 	if (state->ats_enabled && !master->ats_enabled) {
29888ee9175cSJason Gunthorpe 		arm_smmu_enable_ats(master);
29898ee9175cSJason Gunthorpe 	} else if (state->ats_enabled && master->ats_enabled) {
29908ee9175cSJason Gunthorpe 		/*
299185f2fb6eSJason Gunthorpe 		 * The translation has changed, flush the ATC. At this point the
299285f2fb6eSJason Gunthorpe 		 * SMMU is translating for the new domain and both the old&new
299385f2fb6eSJason Gunthorpe 		 * domain will issue invalidations.
299485f2fb6eSJason Gunthorpe 		 */
299549db2ed2SJason Gunthorpe 		arm_smmu_atc_inv_master(master, state->ssid);
299649db2ed2SJason Gunthorpe 	} else if (!state->ats_enabled && master->ats_enabled) {
299749db2ed2SJason Gunthorpe 		/* ATS is being switched off, invalidate the entire ATC */
299849db2ed2SJason Gunthorpe 		arm_smmu_atc_inv_master(master, IOMMU_NO_PASID);
299949db2ed2SJason Gunthorpe 	}
300049db2ed2SJason Gunthorpe 
3001f3b273b7SJason Gunthorpe 	arm_smmu_remove_master_domain(master, state->old_domain, state->ssid);
3002f3b273b7SJason Gunthorpe 	master->ats_enabled = state->ats_enabled;
3003f3b273b7SJason Gunthorpe }
3004f3b273b7SJason Gunthorpe 
arm_smmu_attach_dev(struct iommu_domain * domain,struct device * dev)3005f3b273b7SJason Gunthorpe static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
3006f3b273b7SJason Gunthorpe {
3007f3b273b7SJason Gunthorpe 	int ret = 0;
3008f3b273b7SJason Gunthorpe 	struct arm_smmu_ste target;
300985f2fb6eSJason Gunthorpe 	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
30108ee9175cSJason Gunthorpe 	struct arm_smmu_device *smmu;
301149db2ed2SJason Gunthorpe 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
301249db2ed2SJason Gunthorpe 	struct arm_smmu_attach_state state = {
301349db2ed2SJason Gunthorpe 		.old_domain = iommu_get_domain_for_dev(dev),
301449db2ed2SJason Gunthorpe 		.ssid = IOMMU_NO_PASID,
301549db2ed2SJason Gunthorpe 	};
301649db2ed2SJason Gunthorpe 	struct arm_smmu_master *master;
301785f2fb6eSJason Gunthorpe 	struct arm_smmu_cd *cdptr;
301885f2fb6eSJason Gunthorpe 
3019d38c28dbSJason Gunthorpe 	if (!fwspec)
3020d38c28dbSJason Gunthorpe 		return -ENOENT;
302185f2fb6eSJason Gunthorpe 
3022d38c28dbSJason Gunthorpe 	state.master = master = dev_iommu_priv_get(dev);
3023d38c28dbSJason Gunthorpe 	smmu = master->smmu;
3024d38c28dbSJason Gunthorpe 
3025d38c28dbSJason Gunthorpe 	if (smmu_domain->smmu != smmu)
3026d38c28dbSJason Gunthorpe 		return -EINVAL;
302749db2ed2SJason Gunthorpe 
302885f2fb6eSJason Gunthorpe 	if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
302949db2ed2SJason Gunthorpe 		cdptr = arm_smmu_alloc_cd_ptr(master, IOMMU_NO_PASID);
303049db2ed2SJason Gunthorpe 		if (!cdptr)
303149db2ed2SJason Gunthorpe 			return -ENOMEM;
303249db2ed2SJason Gunthorpe 	} else if (arm_smmu_ssids_in_use(&master->cd_table))
30338ee9175cSJason Gunthorpe 		return -EBUSY;
30348ee9175cSJason Gunthorpe 
30358ee9175cSJason Gunthorpe 	/*
30368ee9175cSJason Gunthorpe 	 * Prevent arm_smmu_share_asid() from trying to change the ASID
30378ee9175cSJason Gunthorpe 	 * of either the old or new domain while we are working on it.
30388ee9175cSJason Gunthorpe 	 * This allows the STE and the smmu_domain->devices list to
30398ee9175cSJason Gunthorpe 	 * be inconsistent during this routine.
30408ee9175cSJason Gunthorpe 	 */
30418ee9175cSJason Gunthorpe 	mutex_lock(&arm_smmu_asid_lock);
30428ee9175cSJason Gunthorpe 
30438ee9175cSJason Gunthorpe 	ret = arm_smmu_attach_prepare(&state, domain);
30448ee9175cSJason Gunthorpe 	if (ret) {
30458ee9175cSJason Gunthorpe 		mutex_unlock(&arm_smmu_asid_lock);
304685f2fb6eSJason Gunthorpe 		return ret;
304785f2fb6eSJason Gunthorpe 	}
3048ce26ea9eSJason Gunthorpe 
3049ce26ea9eSJason Gunthorpe 	switch (smmu_domain->stage) {
3050ce26ea9eSJason Gunthorpe 	case ARM_SMMU_DOMAIN_S1: {
3051ce26ea9eSJason Gunthorpe 		struct arm_smmu_cd target_cd;
305212dacfb5SJason Gunthorpe 
305312dacfb5SJason Gunthorpe 		arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
30547497f421SJason Gunthorpe 		arm_smmu_write_cd_entry(master, IOMMU_NO_PASID, cdptr,
30557497f421SJason Gunthorpe 					&target_cd);
30567497f421SJason Gunthorpe 		arm_smmu_make_cdtable_ste(&target, master, state.ats_enabled,
30571d5f34f0SJason Gunthorpe 					  STRTAB_STE_1_S1DSS_SSID0);
30587497f421SJason Gunthorpe 		arm_smmu_install_ste_for_dev(master, &target);
305912dacfb5SJason Gunthorpe 		break;
306012dacfb5SJason Gunthorpe 	}
306112dacfb5SJason Gunthorpe 	case ARM_SMMU_DOMAIN_S2:
306212dacfb5SJason Gunthorpe 		arm_smmu_make_s2_domain_ste(&target, master, smmu_domain,
306312dacfb5SJason Gunthorpe 					    state.ats_enabled);
306412dacfb5SJason Gunthorpe 		arm_smmu_install_ste_for_dev(master, &target);
306512dacfb5SJason Gunthorpe 		arm_smmu_clear_cd(master, IOMMU_NO_PASID);
3066ce26ea9eSJason Gunthorpe 		break;
3067ce26ea9eSJason Gunthorpe 	}
3068ce26ea9eSJason Gunthorpe 
3069ce26ea9eSJason Gunthorpe 	arm_smmu_attach_commit(&state);
3070ce26ea9eSJason Gunthorpe 	mutex_unlock(&arm_smmu_asid_lock);
3071ce26ea9eSJason Gunthorpe 	return 0;
3072ce26ea9eSJason Gunthorpe }
3073ce26ea9eSJason Gunthorpe 
arm_smmu_s1_set_dev_pasid(struct iommu_domain * domain,struct device * dev,ioasid_t id,struct iommu_domain * old)3074ce26ea9eSJason Gunthorpe static int arm_smmu_s1_set_dev_pasid(struct iommu_domain *domain,
3075ce26ea9eSJason Gunthorpe 				     struct device *dev, ioasid_t id,
3076ce26ea9eSJason Gunthorpe 				     struct iommu_domain *old)
30777497f421SJason Gunthorpe {
3078ce26ea9eSJason Gunthorpe 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
3079ce26ea9eSJason Gunthorpe 	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
3080ce26ea9eSJason Gunthorpe 	struct arm_smmu_device *smmu = master->smmu;
3081ce26ea9eSJason Gunthorpe 	struct arm_smmu_cd target_cd;
308212dacfb5SJason Gunthorpe 
30837497f421SJason Gunthorpe 	if (smmu_domain->smmu != smmu)
308412dacfb5SJason Gunthorpe 		return -EINVAL;
308512dacfb5SJason Gunthorpe 
308612dacfb5SJason Gunthorpe 	if (smmu_domain->stage != ARM_SMMU_DOMAIN_S1)
308712dacfb5SJason Gunthorpe 		return -EINVAL;
308812dacfb5SJason Gunthorpe 
308912dacfb5SJason Gunthorpe 	/*
309012dacfb5SJason Gunthorpe 	 * We can read cd.asid outside the lock because arm_smmu_set_pasid()
3091af8f0b83SJason Gunthorpe 	 * will fix it
309212dacfb5SJason Gunthorpe 	 */
309312dacfb5SJason Gunthorpe 	arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
309412dacfb5SJason Gunthorpe 	return arm_smmu_set_pasid(master, to_smmu_domain(domain), id,
309512dacfb5SJason Gunthorpe 				  &target_cd, old);
309612dacfb5SJason Gunthorpe }
309712dacfb5SJason Gunthorpe 
arm_smmu_update_ste(struct arm_smmu_master * master,struct iommu_domain * sid_domain,bool ats_enabled)3098ec9098d6SMostafa Saleh static void arm_smmu_update_ste(struct arm_smmu_master *master,
309912dacfb5SJason Gunthorpe 				struct iommu_domain *sid_domain,
3100ec9098d6SMostafa Saleh 				bool ats_enabled)
3101ce26ea9eSJason Gunthorpe {
3102ce26ea9eSJason Gunthorpe 	unsigned int s1dss = STRTAB_STE_1_S1DSS_TERMINATE;
310312dacfb5SJason Gunthorpe 	struct arm_smmu_ste ste;
310412dacfb5SJason Gunthorpe 
310512dacfb5SJason Gunthorpe 	if (master->cd_table.in_ste && master->ste_ats_enabled == ats_enabled)
310612dacfb5SJason Gunthorpe 		return;
310712dacfb5SJason Gunthorpe 
310812dacfb5SJason Gunthorpe 	if (sid_domain->type == IOMMU_DOMAIN_IDENTITY)
310912dacfb5SJason Gunthorpe 		s1dss = STRTAB_STE_1_S1DSS_BYPASS;
311012dacfb5SJason Gunthorpe 	else
311112dacfb5SJason Gunthorpe 		WARN_ON(sid_domain->type != IOMMU_DOMAIN_BLOCKED);
311212dacfb5SJason Gunthorpe 
311312dacfb5SJason Gunthorpe 	/*
3114352bd64cSJason Gunthorpe 	 * Change the STE into a cdtable one with SID IDENTITY/BLOCKED behavior
3115352bd64cSJason Gunthorpe 	 * using s1dss if necessary. If the cd_table is already installed then
3116352bd64cSJason Gunthorpe 	 * the S1DSS is correct and this will just update the EATS. Otherwise it
3117352bd64cSJason Gunthorpe 	 * installs the entire thing. This will be hitless.
3118352bd64cSJason Gunthorpe 	 */
3119352bd64cSJason Gunthorpe 	arm_smmu_make_cdtable_ste(&ste, master, ats_enabled, s1dss);
3120ce26ea9eSJason Gunthorpe 	arm_smmu_install_ste_for_dev(master, &ste);
3121ce26ea9eSJason Gunthorpe }
3122ce26ea9eSJason Gunthorpe 
arm_smmu_set_pasid(struct arm_smmu_master * master,struct arm_smmu_domain * smmu_domain,ioasid_t pasid,struct arm_smmu_cd * cd,struct iommu_domain * old)3123352bd64cSJason Gunthorpe int arm_smmu_set_pasid(struct arm_smmu_master *master,
3124352bd64cSJason Gunthorpe 		       struct arm_smmu_domain *smmu_domain, ioasid_t pasid,
3125352bd64cSJason Gunthorpe 		       struct arm_smmu_cd *cd, struct iommu_domain *old)
3126352bd64cSJason Gunthorpe {
3127352bd64cSJason Gunthorpe 	struct iommu_domain *sid_domain = iommu_get_domain_for_dev(master->dev);
3128352bd64cSJason Gunthorpe 	struct arm_smmu_attach_state state = {
3129352bd64cSJason Gunthorpe 		.master = master,
3130352bd64cSJason Gunthorpe 		.ssid = pasid,
3131352bd64cSJason Gunthorpe 		.old_domain = old,
3132352bd64cSJason Gunthorpe 	};
3133352bd64cSJason Gunthorpe 	struct arm_smmu_cd *cdptr;
313452acd7d8SShameer Kolothum 	int ret;
3135d5376472SJason Gunthorpe 
313652acd7d8SShameer Kolothum 	/* The core code validates pasid */
313752acd7d8SShameer Kolothum 
313852acd7d8SShameer Kolothum 	if (smmu_domain->smmu != master->smmu)
3139874b87c7SJason Gunthorpe 		return -EINVAL;
314042f0cbb2SJoerg Roedel 
3141874b87c7SJason Gunthorpe 	if (!master->cd_table.in_ste &&
314252acd7d8SShameer Kolothum 	    sid_domain->type != IOMMU_DOMAIN_IDENTITY &&
314352acd7d8SShameer Kolothum 	    sid_domain->type != IOMMU_DOMAIN_BLOCKED)
314452acd7d8SShameer Kolothum 		return -EINVAL;
3145eb054d67SJoao Martins 
3146eb054d67SJoao Martins 	cdptr = arm_smmu_alloc_cd_ptr(master, pasid);
3147d5376472SJason Gunthorpe 	if (!cdptr)
314852acd7d8SShameer Kolothum 		return -ENOMEM;
314952acd7d8SShameer Kolothum 
315060c30aa6SVasant Hegde 	mutex_lock(&arm_smmu_asid_lock);
315160c30aa6SVasant Hegde 	ret = arm_smmu_attach_prepare(&state, &smmu_domain->domain);
315260c30aa6SVasant Hegde 	if (ret)
315352acd7d8SShameer Kolothum 		goto out_unlock;
3154af048ec9SDan Carpenter 
3155af048ec9SDan Carpenter 	/*
315652acd7d8SShameer Kolothum 	 * We don't want to obtain to the asid_lock too early, so fix up the
3157874b87c7SJason Gunthorpe 	 * caller set ASID under the lock in case it changed.
3158874b87c7SJason Gunthorpe 	 */
3159874b87c7SJason Gunthorpe 	cd->data[0] &= ~cpu_to_le64(CTXDESC_CD_0_ASID);
3160874b87c7SJason Gunthorpe 	cd->data[0] |= cpu_to_le64(
3161874b87c7SJason Gunthorpe 		FIELD_PREP(CTXDESC_CD_0_ASID, smmu_domain->cd.asid));
3162874b87c7SJason Gunthorpe 
31631e8be08dSJason Gunthorpe 	arm_smmu_write_cd_entry(master, pasid, cdptr, cd);
3164874b87c7SJason Gunthorpe 	arm_smmu_update_ste(master, sid_domain, state.ats_enabled);
3165874b87c7SJason Gunthorpe 
316652acd7d8SShameer Kolothum 	arm_smmu_attach_commit(&state);
316752acd7d8SShameer Kolothum 
3168eb054d67SJoao Martins out_unlock:
316952acd7d8SShameer Kolothum 	mutex_unlock(&arm_smmu_asid_lock);
317052acd7d8SShameer Kolothum 	return ret;
317152acd7d8SShameer Kolothum }
317252acd7d8SShameer Kolothum 
arm_smmu_blocking_set_dev_pasid(struct iommu_domain * new_domain,struct device * dev,ioasid_t pasid,struct iommu_domain * old_domain)317352acd7d8SShameer Kolothum static int arm_smmu_blocking_set_dev_pasid(struct iommu_domain *new_domain,
317452acd7d8SShameer Kolothum 					   struct device *dev, ioasid_t pasid,
317552acd7d8SShameer Kolothum 					   struct iommu_domain *old_domain)
317652acd7d8SShameer Kolothum {
317752acd7d8SShameer Kolothum 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(old_domain);
31789eec3f9bSXiang Chen 	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
31799eec3f9bSXiang Chen 
31809eec3f9bSXiang Chen 	mutex_lock(&arm_smmu_asid_lock);
318148ec83bcSWill Deacon 	arm_smmu_clear_cd(master, pasid);
318258188afeSRobin Murphy 	if (master->ats_enabled)
318348ec83bcSWill Deacon 		arm_smmu_atc_inv_master(master, pasid);
318448ec83bcSWill Deacon 	arm_smmu_remove_master_domain(master, &smmu_domain->domain, pasid);
318548ec83bcSWill Deacon 	mutex_unlock(&arm_smmu_asid_lock);
318648ec83bcSWill Deacon 
31879eec3f9bSXiang Chen 	/*
318848ec83bcSWill Deacon 	 * When the last user of the CD table goes away downgrade the STE back
318948ec83bcSWill Deacon 	 * to a non-cd_table one.
319059103c79SXiang Chen 	 */
319159103c79SXiang Chen 	if (!arm_smmu_ssids_in_use(&master->cd_table)) {
319259103c79SXiang Chen 		struct iommu_domain *sid_domain =
319348ec83bcSWill Deacon 			iommu_get_domain_for_dev(master->dev);
31949ce27afcSJean-Philippe Brucker 
31959ce27afcSJean-Philippe Brucker 		if (sid_domain->type == IOMMU_DOMAIN_IDENTITY ||
319648ec83bcSWill Deacon 		    sid_domain->type == IOMMU_DOMAIN_BLOCKED)
319748ec83bcSWill Deacon 			sid_domain->ops->attach_dev(sid_domain, dev);
319848ec83bcSWill Deacon 	}
319948ec83bcSWill Deacon 	return 0;
320059103c79SXiang Chen }
320148ec83bcSWill Deacon 
arm_smmu_attach_dev_ste(struct iommu_domain * domain,struct device * dev,struct arm_smmu_ste * ste,unsigned int s1dss)320248ec83bcSWill Deacon static void arm_smmu_attach_dev_ste(struct iommu_domain *domain,
320307fdef34SZhen Lei 				    struct device *dev,
320407fdef34SZhen Lei 				    struct arm_smmu_ste *ste,
320507fdef34SZhen Lei 				    unsigned int s1dss)
320607fdef34SZhen Lei {
320707fdef34SZhen Lei 	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
320807fdef34SZhen Lei 	struct arm_smmu_attach_state state = {
320907fdef34SZhen Lei 		.master = master,
321007fdef34SZhen Lei 		.old_domain = iommu_get_domain_for_dev(dev),
321156f8af5eSWill Deacon 		.ssid = IOMMU_NO_PASID,
321256f8af5eSWill Deacon 	};
321332b12449SRobin Murphy 
32142af2e72bSWill Deacon 	/*
321532b12449SRobin Murphy 	 * Do not allow any ASID to be changed while are working on the STE,
32166cc7e5a9SXiang Chen 	 * otherwise we could miss invalidations.
32176cc7e5a9SXiang Chen 	 */
32186cc7e5a9SXiang Chen 	mutex_lock(&arm_smmu_asid_lock);
3219eba8d2f8SJean-Philippe Brucker 
32207060377cSWill Deacon 	/*
32212af2e72bSWill Deacon 	 * If the CD table is not in use we can use the provided STE, otherwise
322232b12449SRobin Murphy 	 * we use a cdtable STE with the provided S1DSS.
322332b12449SRobin Murphy 	 */
322448ec83bcSWill Deacon 	if (arm_smmu_ssids_in_use(&master->cd_table)) {
322548ec83bcSWill Deacon 		/*
322648ec83bcSWill Deacon 		 * If a CD table has to be present then we need to run with ATS
322758188afeSRobin Murphy 		 * on because we have to assume a PASID is using ATS. For
322848ec83bcSWill Deacon 		 * IDENTITY this will setup things so that S1DSS=bypass which
322948ec83bcSWill Deacon 		 * follows the explanation in "13.6.4 Full ATS skipping stage 1"
323048ec83bcSWill Deacon 		 * and allows for ATS on the RID to work.
323148ec83bcSWill Deacon 		 */
323258188afeSRobin Murphy 		state.cd_needs_ats = true;
323348ec83bcSWill Deacon 		arm_smmu_attach_prepare(&state, domain);
323448ec83bcSWill Deacon 		arm_smmu_make_cdtable_ste(ste, master, state.ats_enabled, s1dss);
32358f785154SRobin Murphy 	} else {
32368f785154SRobin Murphy 		arm_smmu_attach_prepare(&state, domain);
3237778de074SLorenzo Pieralisi 	}
3238778de074SLorenzo Pieralisi 	arm_smmu_install_ste_for_dev(master, ste);
323948ec83bcSWill Deacon 	arm_smmu_attach_commit(&state);
324067843bbaSSuzuki K Poulose 	mutex_unlock(&arm_smmu_asid_lock);
324167843bbaSSuzuki K Poulose 
32428f785154SRobin Murphy 	/*
32438f785154SRobin Murphy 	 * This has to be done after removing the master from the
324448ec83bcSWill Deacon 	 * arm_smmu_domain->devices to avoid races updating the same context
324548ec83bcSWill Deacon 	 * descriptor from arm_smmu_share_asid().
324648ec83bcSWill Deacon 	 */
324748ec83bcSWill Deacon 	arm_smmu_clear_cd(master, IOMMU_NO_PASID);
324848ec83bcSWill Deacon }
324985196f54SJason Gunthorpe 
arm_smmu_attach_dev_identity(struct iommu_domain * domain,struct device * dev)325085196f54SJason Gunthorpe static int arm_smmu_attach_dev_identity(struct iommu_domain *domain,
325148ec83bcSWill Deacon 					struct device *dev)
325248ec83bcSWill Deacon {
325304e2afd1SShameer Kolothum 	struct arm_smmu_ste ste;
325404e2afd1SShameer Kolothum 	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
325504e2afd1SShameer Kolothum 
325604e2afd1SShameer Kolothum 	arm_smmu_master_clear_vmaster(master);
325704e2afd1SShameer Kolothum 	arm_smmu_make_bypass_ste(master->smmu, &ste);
325804e2afd1SShameer Kolothum 	arm_smmu_attach_dev_ste(domain, dev, &ste, STRTAB_STE_1_S1DSS_BYPASS);
325904e2afd1SShameer Kolothum 	return 0;
326004e2afd1SShameer Kolothum }
326104e2afd1SShameer Kolothum 
326204e2afd1SShameer Kolothum static const struct iommu_domain_ops arm_smmu_identity_ops = {
326304e2afd1SShameer Kolothum 	.attach_dev = arm_smmu_attach_dev_identity,
326404e2afd1SShameer Kolothum };
326504e2afd1SShameer Kolothum 
3266cdf315f9SJean-Philippe Brucker static struct iommu_domain arm_smmu_identity_domain = {
3267cdf315f9SJean-Philippe Brucker 	.type = IOMMU_DOMAIN_IDENTITY,
3268cdf315f9SJean-Philippe Brucker 	.ops = &arm_smmu_identity_ops,
3269cdf315f9SJean-Philippe Brucker };
3270cdf315f9SJean-Philippe Brucker 
arm_smmu_attach_dev_blocked(struct iommu_domain * domain,struct device * dev)3271cdf315f9SJean-Philippe Brucker static int arm_smmu_attach_dev_blocked(struct iommu_domain *domain,
3272cdf315f9SJean-Philippe Brucker 					struct device *dev)
3273cdf315f9SJean-Philippe Brucker {
3274cdf315f9SJean-Philippe Brucker 	struct arm_smmu_ste ste;
3275cdf315f9SJean-Philippe Brucker 	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
3276cdf315f9SJean-Philippe Brucker 
3277cdf315f9SJean-Philippe Brucker 	arm_smmu_master_clear_vmaster(master);
3278cdf315f9SJean-Philippe Brucker 	arm_smmu_make_abort_ste(&ste);
3279cdf315f9SJean-Philippe Brucker 	arm_smmu_attach_dev_ste(domain, dev, &ste,
3280cdf315f9SJean-Philippe Brucker 				STRTAB_STE_1_S1DSS_TERMINATE);
3281a2bb820eSJason Gunthorpe 	return 0;
3282cdf315f9SJean-Philippe Brucker }
3283cdf315f9SJean-Philippe Brucker 
3284cdf315f9SJean-Philippe Brucker static const struct iommu_domain_ops arm_smmu_blocked_ops = {
3285cdf315f9SJean-Philippe Brucker 	.attach_dev = arm_smmu_attach_dev_blocked,
3286cdf315f9SJean-Philippe Brucker 	.set_dev_pasid = arm_smmu_blocking_set_dev_pasid,
328704e2afd1SShameer Kolothum };
3288cdf315f9SJean-Philippe Brucker 
3289cdf315f9SJean-Philippe Brucker static struct iommu_domain arm_smmu_blocked_domain = {
3290cdf315f9SJean-Philippe Brucker 	.type = IOMMU_DOMAIN_BLOCKED,
3291cdf315f9SJean-Philippe Brucker 	.ops = &arm_smmu_blocked_ops,
3292a2bb820eSJason Gunthorpe };
3293a2bb820eSJason Gunthorpe 
3294a2bb820eSJason Gunthorpe static struct iommu_domain *
arm_smmu_domain_alloc_paging_flags(struct device * dev,u32 flags,const struct iommu_user_data * user_data)3295a2bb820eSJason Gunthorpe arm_smmu_domain_alloc_paging_flags(struct device *dev, u32 flags,
3296cdf315f9SJean-Philippe Brucker 				   const struct iommu_user_data *user_data)
3297cdf315f9SJean-Philippe Brucker {
3298cdf315f9SJean-Philippe Brucker 	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
3299cdf315f9SJean-Philippe Brucker 	struct arm_smmu_device *smmu = master->smmu;
3300cdf315f9SJean-Philippe Brucker 	const u32 PAGING_FLAGS = IOMMU_HWPT_ALLOC_DIRTY_TRACKING |
3301cdf315f9SJean-Philippe Brucker 				 IOMMU_HWPT_ALLOC_PASID |
3302cdf315f9SJean-Philippe Brucker 				 IOMMU_HWPT_ALLOC_NEST_PARENT;
3303cdf315f9SJean-Philippe Brucker 	struct arm_smmu_domain *smmu_domain;
3304cdf315f9SJean-Philippe Brucker 	int ret;
3305cdf315f9SJean-Philippe Brucker 
3306cdf315f9SJean-Philippe Brucker 	if (flags & ~PAGING_FLAGS)
3307cdf315f9SJean-Philippe Brucker 		return ERR_PTR(-EOPNOTSUPP);
3308cdf315f9SJean-Philippe Brucker 	if (user_data)
3309cdf315f9SJean-Philippe Brucker 		return ERR_PTR(-EOPNOTSUPP);
3310cdf315f9SJean-Philippe Brucker 
3311cdf315f9SJean-Philippe Brucker 	smmu_domain = arm_smmu_domain_alloc();
3312cdf315f9SJean-Philippe Brucker 	if (IS_ERR(smmu_domain))
3313cdf315f9SJean-Philippe Brucker 		return ERR_CAST(smmu_domain);
3314cdf315f9SJean-Philippe Brucker 
3315cdf315f9SJean-Philippe Brucker 	switch (flags) {
3316cdf315f9SJean-Philippe Brucker 	case 0:
3317cdf315f9SJean-Philippe Brucker 		/* Prefer S1 if available */
3318cdf315f9SJean-Philippe Brucker 		if (smmu->features & ARM_SMMU_FEAT_TRANS_S1)
3319cdf315f9SJean-Philippe Brucker 			smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
3320cdf315f9SJean-Philippe Brucker 		else
3321cdf315f9SJean-Philippe Brucker 			smmu_domain->stage = ARM_SMMU_DOMAIN_S2;
3322cdf315f9SJean-Philippe Brucker 		break;
3323cdf315f9SJean-Philippe Brucker 	case IOMMU_HWPT_ALLOC_NEST_PARENT:
3324cdf315f9SJean-Philippe Brucker 		if (!(smmu->features & ARM_SMMU_FEAT_NESTING)) {
3325cdf315f9SJean-Philippe Brucker 			ret = -EOPNOTSUPP;
3326cdf315f9SJean-Philippe Brucker 			goto err_free;
3327cdf315f9SJean-Philippe Brucker 		}
3328cefa0d55SJoerg Roedel 		smmu_domain->stage = ARM_SMMU_DOMAIN_S2;
332948ec83bcSWill Deacon 		smmu_domain->nest_parent = true;
3330cdf315f9SJean-Philippe Brucker 		break;
333148ec83bcSWill Deacon 	case IOMMU_HWPT_ALLOC_DIRTY_TRACKING:
3332b54f4260SJean-Philippe Brucker 	case IOMMU_HWPT_ALLOC_DIRTY_TRACKING | IOMMU_HWPT_ALLOC_PASID:
33339b468f7dSJoerg Roedel 	case IOMMU_HWPT_ALLOC_PASID:
333448ec83bcSWill Deacon 		if (!(smmu->features & ARM_SMMU_FEAT_TRANS_S1)) {
3335b7a9662fSJoerg Roedel 			ret = -EOPNOTSUPP;
3336cefa0d55SJoerg Roedel 			goto err_free;
333792c1d360SWill Deacon 		}
3338778de074SLorenzo Pieralisi 		smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
33398f785154SRobin Murphy 		break;
3340cefa0d55SJoerg Roedel 	default:
334192c1d360SWill Deacon 		ret = -EOPNOTSUPP;
33428f785154SRobin Murphy 		goto err_free;
33438f785154SRobin Murphy 	}
3344cefa0d55SJoerg Roedel 
33458f785154SRobin Murphy 	smmu_domain->domain.type = IOMMU_DOMAIN_UNMANAGED;
33469ce27afcSJean-Philippe Brucker 	smmu_domain->domain.ops = arm_smmu_ops.default_domain_ops;
33478f785154SRobin Murphy 	ret = arm_smmu_domain_finalise(smmu_domain, smmu, flags);
3348b7a9662fSJoerg Roedel 	if (ret)
334948ec83bcSWill Deacon 		goto err_free;
3350cdf315f9SJean-Philippe Brucker 	return &smmu_domain->domain;
335148ec83bcSWill Deacon 
3352a2be6218SJean-Philippe Brucker err_free:
33538f785154SRobin Murphy 	kfree(smmu_domain);
3354434b73e6SJean-Philippe Brucker 	return ERR_PTR(ret);
3355434b73e6SJean-Philippe Brucker }
335689535821SJean-Philippe Brucker 
arm_smmu_map_pages(struct iommu_domain * domain,unsigned long iova,phys_addr_t paddr,size_t pgsize,size_t pgcount,int prot,gfp_t gfp,size_t * mapped)3357058c59a0SJean-Philippe Brucker static int arm_smmu_map_pages(struct iommu_domain *domain, unsigned long iova,
3358058c59a0SJean-Philippe Brucker 			      phys_addr_t paddr, size_t pgsize, size_t pgcount,
3359058c59a0SJean-Philippe Brucker 			      int prot, gfp_t gfp, size_t *mapped)
3360058c59a0SJean-Philippe Brucker {
3361058c59a0SJean-Philippe Brucker 	struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
3362058c59a0SJean-Philippe Brucker 
3363058c59a0SJean-Philippe Brucker 	if (!ops)
3364058c59a0SJean-Philippe Brucker 		return -ENODEV;
3365058c59a0SJean-Philippe Brucker 
3366058c59a0SJean-Philippe Brucker 	return ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, gfp, mapped);
336789535821SJean-Philippe Brucker }
336889535821SJean-Philippe Brucker 
arm_smmu_unmap_pages(struct iommu_domain * domain,unsigned long iova,size_t pgsize,size_t pgcount,struct iommu_iotlb_gather * gather)336989535821SJean-Philippe Brucker static size_t arm_smmu_unmap_pages(struct iommu_domain *domain, unsigned long iova,
337089535821SJean-Philippe Brucker 				   size_t pgsize, size_t pgcount,
3371395ad89dSJean-Philippe Brucker 				   struct iommu_iotlb_gather *gather)
3372395ad89dSJean-Philippe Brucker {
3373395ad89dSJean-Philippe Brucker 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
3374395ad89dSJean-Philippe Brucker 	struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
3375395ad89dSJean-Philippe Brucker 
33766c17c7d5SJason Gunthorpe 	if (!ops)
33776c17c7d5SJason Gunthorpe 		return 0;
33786c17c7d5SJason Gunthorpe 
33796c17c7d5SJason Gunthorpe 	return ops->unmap_pages(ops, iova, pgsize, pgcount, gather);
33806c17c7d5SJason Gunthorpe }
33816c17c7d5SJason Gunthorpe 
arm_smmu_flush_iotlb_all(struct iommu_domain * domain)3382cefa0d55SJoerg Roedel static void arm_smmu_flush_iotlb_all(struct iommu_domain *domain)
3383a2be6218SJean-Philippe Brucker {
3384a2be6218SJean-Philippe Brucker 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
3385a2be6218SJean-Philippe Brucker 
3386cefa0d55SJoerg Roedel 	if (smmu_domain->smmu)
33878f785154SRobin Murphy 		arm_smmu_tlb_inv_context(smmu_domain);
338848ec83bcSWill Deacon }
3389cefa0d55SJoerg Roedel 
arm_smmu_iotlb_sync(struct iommu_domain * domain,struct iommu_iotlb_gather * gather)339048ec83bcSWill Deacon static void arm_smmu_iotlb_sync(struct iommu_domain *domain,
33914d26ba67SRobin Murphy 				struct iommu_iotlb_gather *gather)
33928f785154SRobin Murphy {
3393395ad89dSJean-Philippe Brucker 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
3394395ad89dSJean-Philippe Brucker 
33958c73c32cSJason Gunthorpe 	if (!gather->pgsize)
33968c73c32cSJason Gunthorpe 		return;
3397734554fdSRobin Murphy 
3398d36464f4SJason Gunthorpe 	arm_smmu_tlb_inv_range_domain(gather->start,
3399734554fdSRobin Murphy 				      gather->end - gather->start + 1,
3400734554fdSRobin Murphy 				      gather->pgsize, true, smmu_domain);
34018c73c32cSJason Gunthorpe }
3402058c59a0SJean-Philippe Brucker 
3403cdf315f9SJean-Philippe Brucker static phys_addr_t
arm_smmu_iova_to_phys(struct iommu_domain * domain,dma_addr_t iova)3404e3b1be2eSJason Gunthorpe arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
340510e4968cSMichael Shavit {
34068f785154SRobin Murphy 	struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
340748ec83bcSWill Deacon 
340848ec83bcSWill Deacon 	if (!ops)
3409eb054d67SJoao Martins 		return 0;
3410eb054d67SJoao Martins 
3411eb054d67SJoao Martins 	return ops->iova_to_phys(ops, iova);
3412eb054d67SJoao Martins }
3413eb054d67SJoao Martins 
3414eb054d67SJoao Martins static struct platform_driver arm_smmu_driver;
3415eb054d67SJoao Martins 
3416eb054d67SJoao Martins static
arm_smmu_get_by_fwnode(struct fwnode_handle * fwnode)3417eb054d67SJoao Martins struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode)
3418eb054d67SJoao Martins {
3419eb054d67SJoao Martins 	struct device *dev = bus_find_device_by_fwnode(&platform_bus_type, fwnode);
3420eb054d67SJoao Martins 
3421eb054d67SJoao Martins 	put_device(dev);
3422eb054d67SJoao Martins 	return dev ? dev_get_drvdata(dev) : NULL;
3423eb054d67SJoao Martins }
3424eb054d67SJoao Martins 
arm_smmu_sid_in_range(struct arm_smmu_device * smmu,u32 sid)3425eb054d67SJoao Martins static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
3426eb054d67SJoao Martins {
3427eb054d67SJoao Martins 	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
3428eb054d67SJoao Martins 		return arm_smmu_strtab_l1_idx(sid) < smmu->strtab_cfg.l2.num_l1_ents;
3429eb054d67SJoao Martins 	return sid < smmu->strtab_cfg.linear.num_ents;
343008d4ca2aSRobin Murphy }
343108d4ca2aSRobin Murphy 
arm_smmu_init_sid_strtab(struct arm_smmu_device * smmu,u32 sid)343208d4ca2aSRobin Murphy static int arm_smmu_init_sid_strtab(struct arm_smmu_device *smmu, u32 sid)
343308d4ca2aSRobin Murphy {
343408d4ca2aSRobin Murphy 	/* Check the SIDs are in range of the SMMU and our stream table */
343508d4ca2aSRobin Murphy 	if (!arm_smmu_sid_in_range(smmu, sid))
343608d4ca2aSRobin Murphy 		return -ERANGE;
343708d4ca2aSRobin Murphy 
343808d4ca2aSRobin Murphy 	/* Ensure l2 strtab is initialised */
343908d4ca2aSRobin Murphy 	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
344008d4ca2aSRobin Murphy 		return arm_smmu_init_l2_strtab(smmu, sid);
344108d4ca2aSRobin Murphy 
344208d4ca2aSRobin Murphy 	return 0;
344308d4ca2aSRobin Murphy }
344408d4ca2aSRobin Murphy 
arm_smmu_insert_master(struct arm_smmu_device * smmu,struct arm_smmu_master * master)344508d4ca2aSRobin Murphy static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
344608d4ca2aSRobin Murphy 				  struct arm_smmu_master *master)
3447b42a905bSKrzysztof Kozlowski {
3448b42a905bSKrzysztof Kozlowski 	int i;
34498f785154SRobin Murphy 	int ret = 0;
34508f785154SRobin Murphy 	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev);
34518f785154SRobin Murphy 
34528f785154SRobin Murphy 	master->streams = kcalloc(fwspec->num_ids, sizeof(*master->streams),
345350019f09SEric Auger 				  GFP_KERNEL);
345450019f09SEric Auger 	if (!master->streams)
345550019f09SEric Auger 		return -ENOMEM;
345650019f09SEric Auger 	master->num_streams = fwspec->num_ids;
345750019f09SEric Auger 
345850019f09SEric Auger 	mutex_lock(&smmu->streams_mutex);
345950019f09SEric Auger 	for (i = 0; i < fwspec->num_ids; i++) {
34600251d010SLu Baolu 		struct arm_smmu_stream *new_stream = &master->streams[i];
346150019f09SEric Auger 		struct rb_node *existing;
346250019f09SEric Auger 		u32 sid = fwspec->ids[i];
346350019f09SEric Auger 
346450019f09SEric Auger 		new_stream->id = sid;
3465273df963SRobin Murphy 		new_stream->master = master;
3466273df963SRobin Murphy 
346750019f09SEric Auger 		ret = arm_smmu_init_sid_strtab(smmu, sid);
346850019f09SEric Auger 		if (ret)
3469f534d98bSJean-Philippe Brucker 			break;
3470f534d98bSJean-Philippe Brucker 
3471f534d98bSJean-Philippe Brucker 		/* Insert into SID tree */
3472395ad89dSJean-Philippe Brucker 		existing = rb_find_add(&new_stream->node, &smmu->streams,
3473395ad89dSJean-Philippe Brucker 				       arm_smmu_streams_cmp_node);
3474469b7b8aSChristoph Hellwig 		if (existing) {
3475f534d98bSJean-Philippe Brucker 			struct arm_smmu_master *existing_master =
3476f534d98bSJean-Philippe Brucker 				rb_entry(existing, struct arm_smmu_stream, node)
3477f534d98bSJean-Philippe Brucker 					->master;
3478395ad89dSJean-Philippe Brucker 
3479469b7b8aSChristoph Hellwig 			/* Bridged PCI devices may end up with duplicated IDs */
3480469b7b8aSChristoph Hellwig 			if (existing_master == master)
3481469b7b8aSChristoph Hellwig 				continue;
3482469b7b8aSChristoph Hellwig 
3483395ad89dSJean-Philippe Brucker 			dev_warn(master->dev,
3484395ad89dSJean-Philippe Brucker 				 "Aliasing StreamID 0x%x (from %s) unsupported, expect DMA to be broken\n",
3485f534d98bSJean-Philippe Brucker 				 sid, dev_name(existing_master->dev));
3486469b7b8aSChristoph Hellwig 			ret = -ENODEV;
3487469b7b8aSChristoph Hellwig 			break;
3488469b7b8aSChristoph Hellwig 		}
3489469b7b8aSChristoph Hellwig 	}
3490395ad89dSJean-Philippe Brucker 
3491f534d98bSJean-Philippe Brucker 	if (ret) {
3492f534d98bSJean-Philippe Brucker 		for (i--; i >= 0; i--)
3493f534d98bSJean-Philippe Brucker 			rb_erase(&master->streams[i].node, &smmu->streams);
3494f534d98bSJean-Philippe Brucker 		kfree(master->streams);
3495f534d98bSJean-Philippe Brucker 	}
3496f534d98bSJean-Philippe Brucker 	mutex_unlock(&smmu->streams_mutex);
3497f534d98bSJean-Philippe Brucker 
3498f534d98bSJean-Philippe Brucker 	return ret;
3499395ad89dSJean-Philippe Brucker }
3500395ad89dSJean-Philippe Brucker 
arm_smmu_remove_master(struct arm_smmu_master * master)3501469b7b8aSChristoph Hellwig static void arm_smmu_remove_master(struct arm_smmu_master *master)
3502f534d98bSJean-Philippe Brucker {
3503f534d98bSJean-Philippe Brucker 	int i;
3504f534d98bSJean-Philippe Brucker 	struct arm_smmu_device *smmu = master->smmu;
3505395ad89dSJean-Philippe Brucker 	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(master->dev);
3506469b7b8aSChristoph Hellwig 
3507469b7b8aSChristoph Hellwig 	if (!smmu || !master->streams)
3508395ad89dSJean-Philippe Brucker 		return;
3509395ad89dSJean-Philippe Brucker 
3510395ad89dSJean-Philippe Brucker 	mutex_lock(&smmu->streams_mutex);
3511395ad89dSJean-Philippe Brucker 	for (i = 0; i < fwspec->num_ids; i++)
3512f534d98bSJean-Philippe Brucker 		rb_erase(&master->streams[i].node, &smmu->streams);
3513469b7b8aSChristoph Hellwig 	mutex_unlock(&smmu->streams_mutex);
3514469b7b8aSChristoph Hellwig 
3515395ad89dSJean-Philippe Brucker 	kfree(master->streams);
3516f534d98bSJean-Philippe Brucker }
3517f534d98bSJean-Philippe Brucker 
arm_smmu_probe_device(struct device * dev)3518f534d98bSJean-Philippe Brucker static struct iommu_device *arm_smmu_probe_device(struct device *dev)
3519f534d98bSJean-Philippe Brucker {
3520f534d98bSJean-Philippe Brucker 	int ret;
352124b6c779SYicong Yang 	struct arm_smmu_device *smmu;
352224b6c779SYicong Yang 	struct arm_smmu_master *master;
352324b6c779SYicong Yang 	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
352424b6c779SYicong Yang 
352524b6c779SYicong Yang 	if (WARN_ON_ONCE(dev_iommu_priv_get(dev)))
352624b6c779SYicong Yang 		return ERR_PTR(-EBUSY);
352724b6c779SYicong Yang 
352824b6c779SYicong Yang 	smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
352924b6c779SYicong Yang 	if (!smmu)
353024b6c779SYicong Yang 		return ERR_PTR(-ENODEV);
353124b6c779SYicong Yang 
353224b6c779SYicong Yang 	master = kzalloc(sizeof(*master), GFP_KERNEL);
353324b6c779SYicong Yang 	if (!master)
353424b6c779SYicong Yang 		return ERR_PTR(-ENOMEM);
353524b6c779SYicong Yang 
353624b6c779SYicong Yang 	master->dev = dev;
353724b6c779SYicong Yang 	master->smmu = smmu;
353824b6c779SYicong Yang 	dev_iommu_priv_set(dev, master);
353924b6c779SYicong Yang 
354024b6c779SYicong Yang 	ret = arm_smmu_insert_master(smmu, master);
354148ec83bcSWill Deacon 	if (ret)
354212dacfb5SJason Gunthorpe 		goto err_free_master;
3543352bd64cSJason Gunthorpe 
354448ec83bcSWill Deacon 	device_property_read_u32(dev, "pasid-num-bits", &master->ssid_bits);
35456912ec91SNicolin Chen 	master->ssid_bits = min(smmu->ssid_bits, master->ssid_bits);
3546327e10b4SJason Gunthorpe 
3547678d79b9SJason Gunthorpe 	/*
3548d5376472SJason Gunthorpe 	 * Note that PASID must be enabled before, and disabled after ATS:
3549cefa0d55SJoerg Roedel 	 * PCI Express Base 4.0r1.0 - 10.5.1.3 ATS Control Register
3550cefa0d55SJoerg Roedel 	 *
355108d4ca2aSRobin Murphy 	 *   Behavior is undefined if this bit is Set and the value of the PASID
35528f785154SRobin Murphy 	 *   Enable, Execute Requested Enable, or Privileged Mode Requested bits
355350019f09SEric Auger 	 *   are changed.
3554386fa64fSLu Baolu 	 */
3555f534d98bSJean-Philippe Brucker 	arm_smmu_enable_pasid(master);
3556f534d98bSJean-Philippe Brucker 
3557395ad89dSJean-Philippe Brucker 	if (!(smmu->features & ARM_SMMU_FEAT_2_LVL_CDTAB))
355824b6c779SYicong Yang 		master->ssid_bits = min_t(u8, master->ssid_bits,
355969d9b312SNicolin Chen 					  CTXDESC_LINEAR_CDMAX);
35601e8be08dSJason Gunthorpe 
356148ec83bcSWill Deacon 	if ((smmu->features & ARM_SMMU_FEAT_STALLS &&
3562c0aec668SRobin Murphy 	     device_property_read_bool(dev, "dma-can-stall")) ||
35639a630a4bSLu Baolu 	    smmu->features & ARM_SMMU_FEAT_STALL_FORCE)
35649a630a4bSLu Baolu 		master->stall_enabled = true;
3565e89573cfSJason Gunthorpe 
3566f3b273b7SJason Gunthorpe 	if (dev_is_pci(dev)) {
35679a630a4bSLu Baolu 		unsigned int stu = __ffs(smmu->pgsize_bitmap);
35689a630a4bSLu Baolu 
35699a630a4bSLu Baolu 		pci_prepare_ats(to_pci_dev(dev), stu);
35709a630a4bSLu Baolu 	}
35719a630a4bSLu Baolu 
3572d7b2d2baSJason Gunthorpe 	return &smmu->iommu;
35739a630a4bSLu Baolu 
357448ec83bcSWill Deacon err_free_master:
357548ec83bcSWill Deacon 	kfree(master);
3576eb054d67SJoao Martins 	return ERR_PTR(ret);
3577eb054d67SJoao Martins }
3578eb054d67SJoao Martins 
arm_smmu_release_device(struct device * dev)3579eb054d67SJoao Martins static void arm_smmu_release_device(struct device *dev)
3580eb054d67SJoao Martins {
358148ec83bcSWill Deacon 	struct arm_smmu_master *master = dev_iommu_priv_get(dev);
3582a7a08b85SNicolin Chen 
3583a7a08b85SNicolin Chen 	WARN_ON(master->iopf_refcount);
3584a7a08b85SNicolin Chen 
3585d25f6eadSWill Deacon 	/* Put the STE back to what arm_smmu_init_strtab() sets */
358648ec83bcSWill Deacon 	if (dev->iommu->require_direct)
3587d25f6eadSWill Deacon 		arm_smmu_attach_dev_identity(&arm_smmu_identity_domain, dev);
358848ec83bcSWill Deacon 	else
3589d25f6eadSWill Deacon 		arm_smmu_attach_dev_blocked(&arm_smmu_blocked_domain, dev);
359052be8637SWill Deacon 
3591d25f6eadSWill Deacon 	arm_smmu_disable_pasid(master);
3592d25f6eadSWill Deacon 	arm_smmu_remove_master(master);
3593d25f6eadSWill Deacon 	if (arm_smmu_cdtab_allocated(&master->cd_table))
3594d25f6eadSWill Deacon 		arm_smmu_free_cd_tables(master);
3595d25f6eadSWill Deacon 	kfree(master);
359652be8637SWill Deacon }
3597d25f6eadSWill Deacon 
arm_smmu_read_and_clear_dirty(struct iommu_domain * domain,unsigned long iova,size_t size,unsigned long flags,struct iommu_dirty_bitmap * dirty)3598d25f6eadSWill Deacon static int arm_smmu_read_and_clear_dirty(struct iommu_domain *domain,
359948ec83bcSWill Deacon 					 unsigned long iova, size_t size,
3600d25f6eadSWill Deacon 					 unsigned long flags,
3601d25f6eadSWill Deacon 					 struct iommu_dirty_bitmap *dirty)
3602d25f6eadSWill Deacon {
360348ec83bcSWill Deacon 	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
360448ec83bcSWill Deacon 	struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
360548ec83bcSWill Deacon 
3606d25f6eadSWill Deacon 	return ops->read_and_clear_dirty(ops, iova, size, flags, dirty);
3607d25f6eadSWill Deacon }
360852be8637SWill Deacon 
arm_smmu_set_dirty_tracking(struct iommu_domain * domain,bool enabled)3609d25f6eadSWill Deacon static int arm_smmu_set_dirty_tracking(struct iommu_domain *domain,
3610d25f6eadSWill Deacon 				       bool enabled)
361186d2d921SRobin Murphy {
361286d2d921SRobin Murphy 	/*
361348ec83bcSWill Deacon 	 * Always enabled and the dirty bitmap is cleared prior to
361448ec83bcSWill Deacon 	 * set_dirty_tracking().
361548ec83bcSWill Deacon 	 */
36161cf9e54eSRobin Murphy 	return 0;
361752be8637SWill Deacon }
361848ec83bcSWill Deacon 
arm_smmu_device_group(struct device * dev)361952be8637SWill Deacon static struct iommu_group *arm_smmu_device_group(struct device *dev)
362048ec83bcSWill Deacon {
362148ec83bcSWill Deacon 	struct iommu_group *group;
362248ec83bcSWill Deacon 
3623a7a08b85SNicolin Chen 	/*
3624e736c895SNicolin Chen 	 * We don't support devices sharing stream IDs other than PCI RID
3625587e6c10SWill Deacon 	 * aliases, since the necessary ID-to-device lookup becomes rather
3626587e6c10SWill Deacon 	 * impractical given a potential sparse 32-bit stream ID space.
3627587e6c10SWill Deacon 	 */
3628587e6c10SWill Deacon 	if (dev_is_pci(dev))
3629587e6c10SWill Deacon 		group = pci_device_group(dev);
3630587e6c10SWill Deacon 	else
3631fcdeb8c3SChristophe JAILLET 		group = generic_device_group(dev);
3632fcdeb8c3SChristophe JAILLET 
3633fcdeb8c3SChristophe JAILLET 	return group;
3634fcdeb8c3SChristophe JAILLET }
3635587e6c10SWill Deacon 
arm_smmu_of_xlate(struct device * dev,const struct of_phandle_args * args)3636fcdeb8c3SChristophe JAILLET static int arm_smmu_of_xlate(struct device *dev,
3637587e6c10SWill Deacon 			     const struct of_phandle_args *args)
3638587e6c10SWill Deacon {
363948ec83bcSWill Deacon 	return iommu_fwspec_add_ids(dev, args->args, 1);
364048ec83bcSWill Deacon }
364148ec83bcSWill Deacon 
arm_smmu_get_resv_regions(struct device * dev,struct list_head * head)364248ec83bcSWill Deacon static void arm_smmu_get_resv_regions(struct device *dev,
364348ec83bcSWill Deacon 				      struct list_head *head)
364486d2d921SRobin Murphy {
364586d2d921SRobin Murphy 	struct iommu_resv_region *region;
364686d2d921SRobin Murphy 	int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
364748ec83bcSWill Deacon 
364804fa26c7SWill Deacon 	region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
364948ec83bcSWill Deacon 					 prot, IOMMU_RESV_SW_MSI, GFP_KERNEL);
3650e736c895SNicolin Chen 	if (!region)
3651587e6c10SWill Deacon 		return;
3652587e6c10SWill Deacon 
3653587e6c10SWill Deacon 	list_add_tail(&region->list, head);
365448ec83bcSWill Deacon 
365586d2d921SRobin Murphy 	iommu_dma_get_resv_regions(dev, head);
365686d2d921SRobin Murphy }
365786d2d921SRobin Murphy 
365848ec83bcSWill Deacon /*
365904fa26c7SWill Deacon  * HiSilicon PCIe tune and trace device can be used to trace TLP headers on the
366048ec83bcSWill Deacon  * PCIe link and save the data to memory by DMA. The hardware is restricted to
3661395ad89dSJean-Philippe Brucker  * use identity mapping only.
3662395ad89dSJean-Philippe Brucker  */
3663395ad89dSJean-Philippe Brucker #define IS_HISI_PTT_DEVICE(pdev)	((pdev)->vendor == PCI_VENDOR_ID_HUAWEI && \
3664395ad89dSJean-Philippe Brucker 					 (pdev)->device == 0xa12e)
3665395ad89dSJean-Philippe Brucker 
arm_smmu_def_domain_type(struct device * dev)3666395ad89dSJean-Philippe Brucker static int arm_smmu_def_domain_type(struct device *dev)
3667395ad89dSJean-Philippe Brucker {
366848ec83bcSWill Deacon 	if (dev_is_pci(dev)) {
366948ec83bcSWill Deacon 		struct pci_dev *pdev = to_pci_dev(dev);
367048ec83bcSWill Deacon 
367148ec83bcSWill Deacon 		if (IS_HISI_PTT_DEVICE(pdev))
367286d2d921SRobin Murphy 			return IOMMU_DOMAIN_IDENTITY;
367386d2d921SRobin Murphy 	}
367486d2d921SRobin Murphy 
367548ec83bcSWill Deacon 	return 0;
367648ec83bcSWill Deacon }
367748ec83bcSWill Deacon 
367848ec83bcSWill Deacon static const struct iommu_ops arm_smmu_ops = {
3679ce410410SJason Gunthorpe 	.identity_domain	= &arm_smmu_identity_domain,
368048ec83bcSWill Deacon 	.blocked_domain		= &arm_smmu_blocked_domain,
3681ce410410SJason Gunthorpe 	.capable		= arm_smmu_capable,
3682f63237f5SDaniel Mentz 	.hw_info		= arm_smmu_hw_info,
368348ec83bcSWill Deacon 	.domain_alloc_sva       = arm_smmu_sva_domain_alloc,
3684692c4e42SNate Watterson 	.domain_alloc_paging_flags = arm_smmu_domain_alloc_paging_flags,
368585196f54SJason Gunthorpe 	.probe_device		= arm_smmu_probe_device,
368685196f54SJason Gunthorpe 	.release_device		= arm_smmu_release_device,
368748ec83bcSWill Deacon 	.device_group		= arm_smmu_device_group,
368848ec83bcSWill Deacon 	.of_xlate		= arm_smmu_of_xlate,
368985196f54SJason Gunthorpe 	.get_resv_regions	= arm_smmu_get_resv_regions,
3690ce410410SJason Gunthorpe 	.page_response		= arm_smmu_page_response,
369148ec83bcSWill Deacon 	.def_domain_type	= arm_smmu_def_domain_type,
369285196f54SJason Gunthorpe 	.get_viommu_size	= arm_smmu_get_viommu_size,
369385196f54SJason Gunthorpe 	.viommu_init		= arm_vsmmu_init,
36949bb9069cSJean-Philippe Brucker 	.user_pasid_table	= 1,
369585196f54SJason Gunthorpe 	.owner			= THIS_MODULE,
369648ec83bcSWill Deacon 	.default_domain_ops = &(const struct iommu_domain_ops) {
369748ec83bcSWill Deacon 		.attach_dev		= arm_smmu_attach_dev,
3698dc898eb8SZenghui Yu 		.enforce_cache_coherency = arm_smmu_enforce_cache_coherency,
369948ec83bcSWill Deacon 		.set_dev_pasid		= arm_smmu_s1_set_dev_pasid,
370048ec83bcSWill Deacon 		.map_pages		= arm_smmu_map_pages,
370148ec83bcSWill Deacon 		.unmap_pages		= arm_smmu_unmap_pages,
370285196f54SJason Gunthorpe 		.flush_iotlb_all	= arm_smmu_flush_iotlb_all,
370385196f54SJason Gunthorpe 		.iotlb_sync		= arm_smmu_iotlb_sync,
370485196f54SJason Gunthorpe 		.iova_to_phys		= arm_smmu_iova_to_phys,
3705c84c5ab7SJason Gunthorpe 		.free			= arm_smmu_domain_free_paging,
3706c84c5ab7SJason Gunthorpe 	}
3707c84c5ab7SJason Gunthorpe };
370848ec83bcSWill Deacon 
370948ec83bcSWill Deacon static struct iommu_dirty_ops arm_smmu_dirty_ops = {
371048ec83bcSWill Deacon 	.read_and_clear_dirty	= arm_smmu_read_and_clear_dirty,
371148ec83bcSWill Deacon 	.set_dirty_tracking     = arm_smmu_set_dirty_tracking,
371248ec83bcSWill Deacon };
371348ec83bcSWill Deacon 
371448ec83bcSWill Deacon /* Probing and initialisation functions */
arm_smmu_init_one_queue(struct arm_smmu_device * smmu,struct arm_smmu_queue * q,void __iomem * page,unsigned long prod_off,unsigned long cons_off,size_t dwords,const char * name)371585196f54SJason Gunthorpe int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,
371685196f54SJason Gunthorpe 			    struct arm_smmu_queue *q, void __iomem *page,
371785196f54SJason Gunthorpe 			    unsigned long prod_off, unsigned long cons_off,
37189bb9069cSJean-Philippe Brucker 			    size_t dwords, const char *name)
371985196f54SJason Gunthorpe {
372048ec83bcSWill Deacon 	size_t qsz;
372148ec83bcSWill Deacon 
372248ec83bcSWill Deacon 	do {
372348ec83bcSWill Deacon 		qsz = ((1 << q->llq.max_n_shift) * dwords) << 3;
372448ec83bcSWill Deacon 		q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma,
372585196f54SJason Gunthorpe 					      GFP_KERNEL);
372648ec83bcSWill Deacon 		if (q->base || qsz < PAGE_SIZE)
372785196f54SJason Gunthorpe 			break;
372848ec83bcSWill Deacon 
372948ec83bcSWill Deacon 		q->llq.max_n_shift--;
373048ec83bcSWill Deacon 	} while (1);
373148ec83bcSWill Deacon 
373248ec83bcSWill Deacon 	if (!q->base) {
373348ec83bcSWill Deacon 		dev_err(smmu->dev,
373448ec83bcSWill Deacon 			"failed to allocate queue (0x%zx bytes) for %s\n",
373548ec83bcSWill Deacon 			qsz, name);
373648ec83bcSWill Deacon 		return -ENOMEM;
373748ec83bcSWill Deacon 	}
373848ec83bcSWill Deacon 
373948ec83bcSWill Deacon 	if (!WARN_ON(q->base_dma & (qsz - 1))) {
374048ec83bcSWill Deacon 		dev_info(smmu->dev, "allocated %u entries for %s\n",
374148ec83bcSWill Deacon 			 1 << q->llq.max_n_shift, name);
37421672730cSDawei Li 	}
37431672730cSDawei Li 
374448ec83bcSWill Deacon 	q->prod_reg	= page + prod_off;
374548ec83bcSWill Deacon 	q->cons_reg	= page + cons_off;
374648ec83bcSWill Deacon 	q->ent_dwords	= dwords;
374748ec83bcSWill Deacon 
374848ec83bcSWill Deacon 	q->q_base  = Q_BASE_RWA;
374948ec83bcSWill Deacon 	q->q_base |= q->base_dma & Q_BASE_ADDR_MASK;
375048ec83bcSWill Deacon 	q->q_base |= FIELD_PREP(Q_BASE_LOG2SIZE, q->llq.max_n_shift);
3751cdf315f9SJean-Philippe Brucker 
3752cdf315f9SJean-Philippe Brucker 	q->llq.prod = q->llq.cons = 0;
3753cdf315f9SJean-Philippe Brucker 	return 0;
375448ec83bcSWill Deacon }
375548ec83bcSWill Deacon 
arm_smmu_cmdq_init(struct arm_smmu_device * smmu,struct arm_smmu_cmdq * cmdq)375648ec83bcSWill Deacon int arm_smmu_cmdq_init(struct arm_smmu_device *smmu,
375748ec83bcSWill Deacon 		       struct arm_smmu_cmdq *cmdq)
3758483e0bd8SNicolin Chen {
3759483e0bd8SNicolin Chen 	unsigned int nents = 1 << cmdq->q.llq.max_n_shift;
3760483e0bd8SNicolin Chen 
3761483e0bd8SNicolin Chen 	atomic_set(&cmdq->owner_prod, 0);
3762483e0bd8SNicolin Chen 	atomic_set(&cmdq->lock, 0);
3763483e0bd8SNicolin Chen 
3764483e0bd8SNicolin Chen 	cmdq->valid_map = (atomic_long_t *)devm_bitmap_zalloc(smmu->dev, nents,
3765483e0bd8SNicolin Chen 							      GFP_KERNEL);
376648ec83bcSWill Deacon 	if (!cmdq->valid_map)
376748ec83bcSWill Deacon 		return -ENOMEM;
376848ec83bcSWill Deacon 
376948ec83bcSWill Deacon 	return 0;
377048ec83bcSWill Deacon }
377148ec83bcSWill Deacon 
arm_smmu_init_queues(struct arm_smmu_device * smmu)377248ec83bcSWill Deacon static int arm_smmu_init_queues(struct arm_smmu_device *smmu)
377348ec83bcSWill Deacon {
377448ec83bcSWill Deacon 	int ret;
377548ec83bcSWill Deacon 
377648ec83bcSWill Deacon 	/* cmdq */
377748ec83bcSWill Deacon 	ret = arm_smmu_init_one_queue(smmu, &smmu->cmdq.q, smmu->base,
3778dc87a98dSRobin Murphy 				      ARM_SMMU_CMDQ_PROD, ARM_SMMU_CMDQ_CONS,
3779dc87a98dSRobin Murphy 				      CMDQ_ENT_DWORDS, "cmdq");
3780dc87a98dSRobin Murphy 	if (ret)
3781dc87a98dSRobin Murphy 		return ret;
3782dc87a98dSRobin Murphy 
3783dc87a98dSRobin Murphy 	ret = arm_smmu_cmdq_init(smmu, &smmu->cmdq);
3784dc87a98dSRobin Murphy 	if (ret)
3785dc87a98dSRobin Murphy 		return ret;
3786dc87a98dSRobin Murphy 
3787dc87a98dSRobin Murphy 	/* evtq */
3788dc87a98dSRobin Murphy 	ret = arm_smmu_init_one_queue(smmu, &smmu->evtq.q, smmu->page1,
3789dc87a98dSRobin Murphy 				      ARM_SMMU_EVTQ_PROD, ARM_SMMU_EVTQ_CONS,
3790dc87a98dSRobin Murphy 				      EVTQ_ENT_DWORDS, "evtq");
3791dc87a98dSRobin Murphy 	if (ret)
3792b63b3439SWill Deacon 		return ret;
3793dc87a98dSRobin Murphy 
3794b63b3439SWill Deacon 	if ((smmu->features & ARM_SMMU_FEAT_SVA) &&
3795b63b3439SWill Deacon 	    (smmu->features & ARM_SMMU_FEAT_STALLS)) {
3796b63b3439SWill Deacon 		smmu->evtq.iopf = iopf_queue_alloc(dev_name(smmu->dev));
3797b63b3439SWill Deacon 		if (!smmu->evtq.iopf)
3798dc87a98dSRobin Murphy 			return -ENOMEM;
3799dc87a98dSRobin Murphy 	}
3800166bdbd2SMarc Zyngier 
3801166bdbd2SMarc Zyngier 	/* priq */
3802166bdbd2SMarc Zyngier 	if (!(smmu->features & ARM_SMMU_FEAT_PRI))
380314fd06c7SThomas Gleixner 		return 0;
380414fd06c7SThomas Gleixner 
3805166bdbd2SMarc Zyngier 	return arm_smmu_init_one_queue(smmu, &smmu->priq.q, smmu->page1,
3806166bdbd2SMarc Zyngier 				       ARM_SMMU_PRIQ_PROD, ARM_SMMU_PRIQ_CONS,
3807166bdbd2SMarc Zyngier 				       PRIQ_ENT_DWORDS, "priq");
3808166bdbd2SMarc Zyngier }
3809166bdbd2SMarc Zyngier 
arm_smmu_init_strtab_2lvl(struct arm_smmu_device * smmu)3810166bdbd2SMarc Zyngier static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
3811166bdbd2SMarc Zyngier {
3812dba27c7fSThomas Gleixner 	u32 l1size;
3813166bdbd2SMarc Zyngier 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
3814166bdbd2SMarc Zyngier 	unsigned int last_sid_idx =
38151cf9e54eSRobin Murphy 		arm_smmu_strtab_l1_idx((1ULL << smmu->sid_bits) - 1);
3816166bdbd2SMarc Zyngier 
3817166bdbd2SMarc Zyngier 	/* Calculate the L1 size, capped to the SIDSIZE. */
3818166bdbd2SMarc Zyngier 	cfg->l2.num_l1_ents = min(last_sid_idx + 1, STRTAB_MAX_L1_ENTRIES);
3819cbcee19aSRobin Murphy 	if (cfg->l2.num_l1_ents <= last_sid_idx)
3820166bdbd2SMarc Zyngier 		dev_warn(smmu->dev,
3821166bdbd2SMarc Zyngier 			 "2-level strtab only covers %u/%u bits of SID\n",
3822166bdbd2SMarc Zyngier 			 ilog2(cfg->l2.num_l1_ents * STRTAB_NUM_L2_STES),
3823166bdbd2SMarc Zyngier 			 smmu->sid_bits);
3824166bdbd2SMarc Zyngier 
3825166bdbd2SMarc Zyngier 	l1size = cfg->l2.num_l1_ents * sizeof(struct arm_smmu_strtab_l1);
3826166bdbd2SMarc Zyngier 	cfg->l2.l1tab = dmam_alloc_coherent(smmu->dev, l1size, &cfg->l2.l1_dma,
3827166bdbd2SMarc Zyngier 					    GFP_KERNEL);
3828166bdbd2SMarc Zyngier 	if (!cfg->l2.l1tab) {
3829166bdbd2SMarc Zyngier 		dev_err(smmu->dev,
3830166bdbd2SMarc Zyngier 			"failed to allocate l1 stream table (%u bytes)\n",
3831166bdbd2SMarc Zyngier 			l1size);
3832166bdbd2SMarc Zyngier 		return -ENOMEM;
3833166bdbd2SMarc Zyngier 	}
3834166bdbd2SMarc Zyngier 
3835166bdbd2SMarc Zyngier 	cfg->l2.l2ptrs = devm_kcalloc(smmu->dev, cfg->l2.num_l1_ents,
3836166bdbd2SMarc Zyngier 				      sizeof(*cfg->l2.l2ptrs), GFP_KERNEL);
3837166bdbd2SMarc Zyngier 	if (!cfg->l2.l2ptrs)
3838166bdbd2SMarc Zyngier 		return -ENOMEM;
383934fff628SThomas Gleixner 
3840940ded9cSNate Watterson 	return 0;
3841940ded9cSNate Watterson }
3842940ded9cSNate Watterson 
arm_smmu_init_strtab_linear(struct arm_smmu_device * smmu)3843940ded9cSNate Watterson static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu)
3844166bdbd2SMarc Zyngier {
384514fd06c7SThomas Gleixner 	u32 size;
3846166bdbd2SMarc Zyngier 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
3847940ded9cSNate Watterson 
3848166bdbd2SMarc Zyngier 	size = (1 << smmu->sid_bits) * sizeof(struct arm_smmu_ste);
3849166bdbd2SMarc Zyngier 	cfg->linear.table = dmam_alloc_coherent(smmu->dev, size,
3850166bdbd2SMarc Zyngier 						&cfg->linear.ste_dma,
3851065afdc9SThomas Gleixner 						GFP_KERNEL);
3852065afdc9SThomas Gleixner 	if (!cfg->linear.table) {
3853065afdc9SThomas Gleixner 		dev_err(smmu->dev,
3854166bdbd2SMarc Zyngier 			"failed to allocate linear stream table (%u bytes)\n",
3855166bdbd2SMarc Zyngier 			size);
385680fea979SAleksandr Aprelkov 		return -ENOMEM;
3857166bdbd2SMarc Zyngier 	}
3858166bdbd2SMarc Zyngier 	cfg->linear.num_ents = 1 << smmu->sid_bits;
3859f935448aSGeetha Sowjanya 
386048ec83bcSWill Deacon 	arm_smmu_init_initial_stes(cfg->linear.table, cfg->linear.num_ents);
3861f935448aSGeetha Sowjanya 	return 0;
386248ec83bcSWill Deacon }
3863166bdbd2SMarc Zyngier 
arm_smmu_init_strtab(struct arm_smmu_device * smmu)386448ec83bcSWill Deacon static int arm_smmu_init_strtab(struct arm_smmu_device *smmu)
3865166bdbd2SMarc Zyngier {
386648ec83bcSWill Deacon 	int ret;
386748ec83bcSWill Deacon 
3868b4163fb3SJean-Philippe Brucker 	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
386948ec83bcSWill Deacon 		ret = arm_smmu_init_strtab_2lvl(smmu);
3870b4163fb3SJean-Philippe Brucker 	else
3871b4163fb3SJean-Philippe Brucker 		ret = arm_smmu_init_strtab_linear(smmu);
3872287980e4SArnd Bergmann 	if (ret)
387348ec83bcSWill Deacon 		return ret;
38744c8996d7SRobin Murphy 
38754c8996d7SRobin Murphy 	ida_init(&smmu->vmid_map);
387648ec83bcSWill Deacon 
387748ec83bcSWill Deacon 	return 0;
387848ec83bcSWill Deacon }
387948ec83bcSWill Deacon 
arm_smmu_init_structures(struct arm_smmu_device * smmu)388048ec83bcSWill Deacon static int arm_smmu_init_structures(struct arm_smmu_device *smmu)
388148ec83bcSWill Deacon {
3882287980e4SArnd Bergmann 	int ret;
388348ec83bcSWill Deacon 
38844c8996d7SRobin Murphy 	mutex_init(&smmu->streams_mutex);
38854c8996d7SRobin Murphy 	smmu->streams = RB_ROOT;
388648ec83bcSWill Deacon 
388748ec83bcSWill Deacon 	ret = arm_smmu_init_queues(smmu);
388848ec83bcSWill Deacon 	if (ret)
388948ec83bcSWill Deacon 		return ret;
389048ec83bcSWill Deacon 
3891b4163fb3SJean-Philippe Brucker 	ret = arm_smmu_init_strtab(smmu);
389248ec83bcSWill Deacon 	if (ret)
3893b4163fb3SJean-Philippe Brucker 		return ret;
3894b4163fb3SJean-Philippe Brucker 
389548ec83bcSWill Deacon 	if (smmu->impl_ops && smmu->impl_ops->init_structures)
3896287980e4SArnd Bergmann 		return smmu->impl_ops->init_structures(smmu);
389748ec83bcSWill Deacon 
389848ec83bcSWill Deacon 	return 0;
38994c8996d7SRobin Murphy }
39004c8996d7SRobin Murphy 
arm_smmu_write_reg_sync(struct arm_smmu_device * smmu,u32 val,unsigned int reg_off,unsigned int ack_off)3901f935448aSGeetha Sowjanya static int arm_smmu_write_reg_sync(struct arm_smmu_device *smmu, u32 val,
3902f935448aSGeetha Sowjanya 				   unsigned int reg_off, unsigned int ack_off)
3903f935448aSGeetha Sowjanya {
3904f935448aSGeetha Sowjanya 	u32 reg;
3905f935448aSGeetha Sowjanya 
3906f935448aSGeetha Sowjanya 	writel_relaxed(val, smmu->base + reg_off);
3907f935448aSGeetha Sowjanya 	return readl_relaxed_poll_timeout(smmu->base + ack_off, reg, reg == val,
3908f935448aSGeetha Sowjanya 					  1, ARM_SMMU_POLL_TIMEOUT_US);
3909f935448aSGeetha Sowjanya }
3910f935448aSGeetha Sowjanya 
3911f935448aSGeetha Sowjanya /* GBPA is "special" */
arm_smmu_update_gbpa(struct arm_smmu_device * smmu,u32 set,u32 clr)3912f935448aSGeetha Sowjanya static int arm_smmu_update_gbpa(struct arm_smmu_device *smmu, u32 set, u32 clr)
3913f935448aSGeetha Sowjanya {
3914f935448aSGeetha Sowjanya 	int ret;
3915f935448aSGeetha Sowjanya 	u32 reg, __iomem *gbpa = smmu->base + ARM_SMMU_GBPA;
3916f935448aSGeetha Sowjanya 
3917f935448aSGeetha Sowjanya 	ret = readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE),
3918f935448aSGeetha Sowjanya 					 1, ARM_SMMU_POLL_TIMEOUT_US);
3919f935448aSGeetha Sowjanya 	if (ret)
3920f935448aSGeetha Sowjanya 		return ret;
3921657135f3SJohn Garry 
3922657135f3SJohn Garry 	reg &= ~clr;
3923f935448aSGeetha Sowjanya 	reg |= set;
3924f935448aSGeetha Sowjanya 	writel_relaxed(reg | GBPA_UPDATE, gbpa);
3925f935448aSGeetha Sowjanya 	ret = readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE),
3926f935448aSGeetha Sowjanya 					 1, ARM_SMMU_POLL_TIMEOUT_US);
3927f935448aSGeetha Sowjanya 
3928f935448aSGeetha Sowjanya 	if (ret)
3929f935448aSGeetha Sowjanya 		dev_err(smmu->dev, "GBPA not responding to update\n");
3930f935448aSGeetha Sowjanya 	return ret;
3931f935448aSGeetha Sowjanya }
3932f935448aSGeetha Sowjanya 
arm_smmu_free_msis(void * data)3933f935448aSGeetha Sowjanya static void arm_smmu_free_msis(void *data)
3934f935448aSGeetha Sowjanya {
3935ccd6385dSMarc Zyngier 	struct device *dev = data;
393648ec83bcSWill Deacon 
393748ec83bcSWill Deacon 	platform_device_msi_free_irqs_all(dev);
3938ccd6385dSMarc Zyngier }
393948ec83bcSWill Deacon 
arm_smmu_write_msi_msg(struct msi_desc * desc,struct msi_msg * msg)394048ec83bcSWill Deacon static void arm_smmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
394148ec83bcSWill Deacon {
394248ec83bcSWill Deacon 	phys_addr_t doorbell;
394348ec83bcSWill Deacon 	struct device *dev = msi_desc_to_dev(desc);
394448ec83bcSWill Deacon 	struct arm_smmu_device *smmu = dev_get_drvdata(dev);
394548ec83bcSWill Deacon 	phys_addr_t *cfg = arm_smmu_msi_cfg[desc->msi_index];
394648ec83bcSWill Deacon 
394748ec83bcSWill Deacon 	doorbell = (((u64)msg->address_hi) << 32) | msg->address_lo;
394848ec83bcSWill Deacon 	doorbell &= MSI_CFG0_ADDR_MASK;
394948ec83bcSWill Deacon 
395048ec83bcSWill Deacon 	writeq_relaxed(doorbell, smmu->base + cfg[0]);
395148ec83bcSWill Deacon 	writel_relaxed(msg->data, smmu->base + cfg[1]);
395248ec83bcSWill Deacon 	writel_relaxed(ARM_SMMU_MEMATTR_DEVICE_nGnRE, smmu->base + cfg[2]);
395348ec83bcSWill Deacon }
395448ec83bcSWill Deacon 
arm_smmu_setup_msis(struct arm_smmu_device * smmu)395548ec83bcSWill Deacon static void arm_smmu_setup_msis(struct arm_smmu_device *smmu)
395648ec83bcSWill Deacon {
39578c153ef9SJason Gunthorpe 	int ret, nvec = ARM_SMMU_MAX_MSIS;
39588c153ef9SJason Gunthorpe 	struct device *dev = smmu->dev;
39598c153ef9SJason Gunthorpe 
39608c153ef9SJason Gunthorpe 	/* Clear the MSI address regs */
39618c153ef9SJason Gunthorpe 	writeq_relaxed(0, smmu->base + ARM_SMMU_GERROR_IRQ_CFG0);
39628c153ef9SJason Gunthorpe 	writeq_relaxed(0, smmu->base + ARM_SMMU_EVTQ_IRQ_CFG0);
39638c153ef9SJason Gunthorpe 
39648c153ef9SJason Gunthorpe 	if (smmu->features & ARM_SMMU_FEAT_PRI)
39658c153ef9SJason Gunthorpe 		writeq_relaxed(0, smmu->base + ARM_SMMU_PRIQ_IRQ_CFG0);
39668c153ef9SJason Gunthorpe 	else
39678c153ef9SJason Gunthorpe 		nvec--;
39688c153ef9SJason Gunthorpe 
39698c153ef9SJason Gunthorpe 	if (!(smmu->features & ARM_SMMU_FEAT_MSI))
39708c153ef9SJason Gunthorpe 		return;
39718c153ef9SJason Gunthorpe 
39728c153ef9SJason Gunthorpe 	if (!dev->msi.domain) {
39738c153ef9SJason Gunthorpe 		dev_info(smmu->dev, "msi_domain absent - falling back to wired irqs\n");
39748c153ef9SJason Gunthorpe 		return;
39758c153ef9SJason Gunthorpe 	}
39768c153ef9SJason Gunthorpe 
39778c153ef9SJason Gunthorpe 	/* Allocate MSIs for evtq, gerror and priq. Ignore cmdq */
39788c153ef9SJason Gunthorpe 	ret = platform_device_msi_init_and_alloc_irqs(dev, nvec, arm_smmu_write_msi_msg);
39798c153ef9SJason Gunthorpe 	if (ret) {
39808c153ef9SJason Gunthorpe 		dev_warn(dev, "failed to allocate MSIs - falling back to wired irqs\n");
3981734554fdSRobin Murphy 		return;
398248ec83bcSWill Deacon 	}
398348ec83bcSWill Deacon 
398448ec83bcSWill Deacon 	smmu->evtq.q.irq = msi_get_virq(dev, EVTQ_MSI_INDEX);
398548ec83bcSWill Deacon 	smmu->gerr_irq = msi_get_virq(dev, GERROR_MSI_INDEX);
398648ec83bcSWill Deacon 	smmu->priq.q.irq = msi_get_virq(dev, PRIQ_MSI_INDEX);
398748ec83bcSWill Deacon 
398848ec83bcSWill Deacon 	/* Add callback to free MSIs on teardown */
3989b63b3439SWill Deacon 	devm_add_action_or_reset(dev, arm_smmu_free_msis, dev);
399048ec83bcSWill Deacon }
39913f54c447SWill Deacon 
arm_smmu_setup_unique_irqs(struct arm_smmu_device * smmu)3992b63b3439SWill Deacon static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu)
399348ec83bcSWill Deacon {
399448ec83bcSWill Deacon 	int irq, ret;
399548ec83bcSWill Deacon 
399648ec83bcSWill Deacon 	arm_smmu_setup_msis(smmu);
399748ec83bcSWill Deacon 
399848ec83bcSWill Deacon 	/* Request interrupt lines */
3999cbcee19aSRobin Murphy 	irq = smmu->evtq.q.irq;
4000cbcee19aSRobin Murphy 	if (irq) {
4001cbcee19aSRobin Murphy 		ret = devm_request_threaded_irq(smmu->dev, irq, NULL,
4002cbcee19aSRobin Murphy 						arm_smmu_evtq_thread,
4003cbcee19aSRobin Murphy 						IRQF_ONESHOT,
4004cbcee19aSRobin Murphy 						"arm-smmu-v3-evtq", smmu);
400548ec83bcSWill Deacon 		if (ret < 0)
400648ec83bcSWill Deacon 			dev_warn(smmu->dev, "failed to enable evtq irq\n");
400748ec83bcSWill Deacon 	} else {
40089111aebfSJean-Philippe Brucker 		dev_warn(smmu->dev, "no evtq irq - events will not be reported!\n");
40099111aebfSJean-Philippe Brucker 	}
40109111aebfSJean-Philippe Brucker 
40119111aebfSJean-Philippe Brucker 	irq = smmu->gerr_irq;
40129111aebfSJean-Philippe Brucker 	if (irq) {
401348ec83bcSWill Deacon 		ret = devm_request_irq(smmu->dev, irq, arm_smmu_gerror_handler,
401448ec83bcSWill Deacon 				       0, "arm-smmu-v3-gerror", smmu);
401548ec83bcSWill Deacon 		if (ret < 0)
40168c153ef9SJason Gunthorpe 			dev_warn(smmu->dev, "failed to enable gerror irq\n");
401748ec83bcSWill Deacon 	} else {
401848ec83bcSWill Deacon 		dev_warn(smmu->dev, "no gerr irq - errors will not be reported!\n");
401948ec83bcSWill Deacon 	}
402052be8637SWill Deacon 
402152be8637SWill Deacon 	if (smmu->features & ARM_SMMU_FEAT_PRI) {
402248ec83bcSWill Deacon 		irq = smmu->priq.q.irq;
402348ec83bcSWill Deacon 		if (irq) {
402448ec83bcSWill Deacon 			ret = devm_request_threaded_irq(smmu->dev, irq, NULL,
402548ec83bcSWill Deacon 							arm_smmu_priq_thread,
402648ec83bcSWill Deacon 							IRQF_ONESHOT,
402748ec83bcSWill Deacon 							"arm-smmu-v3-priq",
402848ec83bcSWill Deacon 							smmu);
402948ec83bcSWill Deacon 			if (ret < 0)
403048ec83bcSWill Deacon 				dev_warn(smmu->dev,
403148ec83bcSWill Deacon 					 "failed to enable priq irq\n");
403248ec83bcSWill Deacon 		} else {
40334537f6f1SZhen Lei 			dev_warn(smmu->dev, "no priq irq - PRI will be broken\n");
403448ec83bcSWill Deacon 		}
403548ec83bcSWill Deacon 	}
403648ec83bcSWill Deacon }
403748ec83bcSWill Deacon 
arm_smmu_setup_irqs(struct arm_smmu_device * smmu)40384537f6f1SZhen Lei static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
403948ec83bcSWill Deacon {
404048ec83bcSWill Deacon 	int ret, irq;
404148ec83bcSWill Deacon 	u32 irqen_flags = IRQ_CTRL_EVTQ_IRQEN | IRQ_CTRL_GERROR_IRQEN;
40424537f6f1SZhen Lei 
404348ec83bcSWill Deacon 	/* Disable IRQs first */
404448ec83bcSWill Deacon 	ret = arm_smmu_write_reg_sync(smmu, 0, ARM_SMMU_IRQ_CTRL,
404548ec83bcSWill Deacon 				      ARM_SMMU_IRQ_CTRLACK);
404686d2d921SRobin Murphy 	if (ret) {
404786d2d921SRobin Murphy 		dev_err(smmu->dev, "failed to disable irqs\n");
404848ec83bcSWill Deacon 		return ret;
404948ec83bcSWill Deacon 	}
405048ec83bcSWill Deacon 
405148ec83bcSWill Deacon 	irq = smmu->combined_irq;
405248ec83bcSWill Deacon 	if (irq) {
405348ec83bcSWill Deacon 		/*
405448ec83bcSWill Deacon 		 * Cavium ThunderX2 implementation doesn't support unique irq
405548ec83bcSWill Deacon 		 * lines. Use a single irq line for all the SMMUv3 interrupts.
405648ec83bcSWill Deacon 		 */
405748ec83bcSWill Deacon 		ret = devm_request_threaded_irq(smmu->dev, irq,
405848ec83bcSWill Deacon 					arm_smmu_combined_irq_handler,
405948ec83bcSWill Deacon 					arm_smmu_combined_irq_thread,
406048ec83bcSWill Deacon 					IRQF_ONESHOT,
406152be8637SWill Deacon 					"arm-smmu-v3-combined-irq", smmu);
406286d2d921SRobin Murphy 		if (ret < 0)
406352be8637SWill Deacon 			dev_warn(smmu->dev, "failed to enable combined irq\n");
406486d2d921SRobin Murphy 	} else
406548ec83bcSWill Deacon 		arm_smmu_setup_unique_irqs(smmu);
406648ec83bcSWill Deacon 
406748ec83bcSWill Deacon 	if (smmu->features & ARM_SMMU_FEAT_PRI)
406848ec83bcSWill Deacon 		irqen_flags |= IRQ_CTRL_PRIQ_IRQEN;
406948ec83bcSWill Deacon 
407048ec83bcSWill Deacon 	/* Enable interrupt generation on the SMMU */
407148ec83bcSWill Deacon 	ret = arm_smmu_write_reg_sync(smmu, irqen_flags,
407248ec83bcSWill Deacon 				      ARM_SMMU_IRQ_CTRL, ARM_SMMU_IRQ_CTRLACK);
407348ec83bcSWill Deacon 	if (ret)
407448ec83bcSWill Deacon 		dev_warn(smmu->dev, "failed to enable irqs\n");
40759ce27afcSJean-Philippe Brucker 
40769ce27afcSJean-Philippe Brucker 	return 0;
40779ce27afcSJean-Philippe Brucker }
40789ce27afcSJean-Philippe Brucker 
arm_smmu_device_disable(struct arm_smmu_device * smmu)40799ce27afcSJean-Philippe Brucker static int arm_smmu_device_disable(struct arm_smmu_device *smmu)
40809ce27afcSJean-Philippe Brucker {
40819ce27afcSJean-Philippe Brucker 	int ret;
40829ce27afcSJean-Philippe Brucker 
40839ce27afcSJean-Philippe Brucker 	ret = arm_smmu_write_reg_sync(smmu, 0, ARM_SMMU_CR0, ARM_SMMU_CR0ACK);
40849ce27afcSJean-Philippe Brucker 	if (ret)
408548ec83bcSWill Deacon 		dev_err(smmu->dev, "failed to clear cr0\n");
408648ec83bcSWill Deacon 
408748ec83bcSWill Deacon 	return ret;
408848ec83bcSWill Deacon }
408948ec83bcSWill Deacon 
arm_smmu_write_strtab(struct arm_smmu_device * smmu)409048ec83bcSWill Deacon static void arm_smmu_write_strtab(struct arm_smmu_device *smmu)
40913f54c447SWill Deacon {
40923f54c447SWill Deacon 	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
4093dc87a98dSRobin Murphy 	dma_addr_t dma;
4094734554fdSRobin Murphy 	u32 reg;
409548ec83bcSWill Deacon 
409648ec83bcSWill Deacon 	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
409748ec83bcSWill Deacon 		reg = FIELD_PREP(STRTAB_BASE_CFG_FMT,
409848ec83bcSWill Deacon 				 STRTAB_BASE_CFG_FMT_2LVL) |
409948ec83bcSWill Deacon 		      FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE,
410048ec83bcSWill Deacon 				 ilog2(cfg->l2.num_l1_ents) + STRTAB_SPLIT) |
410148ec83bcSWill Deacon 		      FIELD_PREP(STRTAB_BASE_CFG_SPLIT, STRTAB_SPLIT);
410248ec83bcSWill Deacon 		dma = cfg->l2.l1_dma;
41036de80d61SJason Gunthorpe 	} else {
41046de80d61SJason Gunthorpe 		reg = FIELD_PREP(STRTAB_BASE_CFG_FMT,
41056de80d61SJason Gunthorpe 				 STRTAB_BASE_CFG_FMT_LINEAR) |
41066de80d61SJason Gunthorpe 		      FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, smmu->sid_bits);
41076de80d61SJason Gunthorpe 		dma = cfg->linear.ste_dma;
41086de80d61SJason Gunthorpe 	}
41096de80d61SJason Gunthorpe 	writeq_relaxed((dma & STRTAB_BASE_ADDR_MASK) | STRTAB_BASE_RA,
41106de80d61SJason Gunthorpe 		       smmu->base + ARM_SMMU_STRTAB_BASE);
411148ec83bcSWill Deacon 	writel_relaxed(reg, smmu->base + ARM_SMMU_STRTAB_BASE_CFG);
411248ec83bcSWill Deacon }
411348ec83bcSWill Deacon 
arm_smmu_device_reset(struct arm_smmu_device * smmu)4114f322e8afSRobin Murphy static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
4115f322e8afSRobin Murphy {
4116309a15cbSRobin Murphy 	int ret;
4117f322e8afSRobin Murphy 	u32 reg, enables;
4118f322e8afSRobin Murphy 	struct arm_smmu_cmdq_ent cmd;
4119f322e8afSRobin Murphy 
4120f322e8afSRobin Murphy 	/* Clear CR0 and sync (disables SMMU and queue processing) */
4121f322e8afSRobin Murphy 	reg = readl_relaxed(smmu->base + ARM_SMMU_CR0);
4122f322e8afSRobin Murphy 	if (reg & CR0_SMMUEN) {
4123f322e8afSRobin Murphy 		dev_warn(smmu->dev, "SMMU currently enabled! Resetting...\n");
4124f322e8afSRobin Murphy 		arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
4125f322e8afSRobin Murphy 	}
4126f322e8afSRobin Murphy 
4127f322e8afSRobin Murphy 	ret = arm_smmu_device_disable(smmu);
4128f322e8afSRobin Murphy 	if (ret)
4129f322e8afSRobin Murphy 		return ret;
4130f322e8afSRobin Murphy 
4131f322e8afSRobin Murphy 	/* CR1 (table and queue memory attributes) */
4132f322e8afSRobin Murphy 	reg = FIELD_PREP(CR1_TABLE_SH, ARM_SMMU_SH_ISH) |
4133f322e8afSRobin Murphy 	      FIELD_PREP(CR1_TABLE_OC, CR1_CACHE_WB) |
4134f322e8afSRobin Murphy 	      FIELD_PREP(CR1_TABLE_IC, CR1_CACHE_WB) |
4135f322e8afSRobin Murphy 	      FIELD_PREP(CR1_QUEUE_SH, ARM_SMMU_SH_ISH) |
41360bfbfc52SRobin Murphy 	      FIELD_PREP(CR1_QUEUE_OC, CR1_CACHE_WB) |
41370bfbfc52SRobin Murphy 	      FIELD_PREP(CR1_QUEUE_IC, CR1_CACHE_WB);
41380bfbfc52SRobin Murphy 	writel_relaxed(reg, smmu->base + ARM_SMMU_CR1);
4139f322e8afSRobin Murphy 
4140309a15cbSRobin Murphy 	/* CR2 (random crap) */
4141309a15cbSRobin Murphy 	reg = CR2_PTM | CR2_RECINVSID;
4142309a15cbSRobin Murphy 
4143309a15cbSRobin Murphy 	if (smmu->features & ARM_SMMU_FEAT_E2H)
41440bfbfc52SRobin Murphy 		reg |= CR2_E2H;
41450bfbfc52SRobin Murphy 
4146309a15cbSRobin Murphy 	writel_relaxed(reg, smmu->base + ARM_SMMU_CR2);
4147f322e8afSRobin Murphy 
4148f322e8afSRobin Murphy 	/* Stream table */
4149f322e8afSRobin Murphy 	arm_smmu_write_strtab(smmu);
4150f322e8afSRobin Murphy 
4151f322e8afSRobin Murphy 	/* Command queue */
41522f8d6178SJean-Philippe Brucker 	writeq_relaxed(smmu->cmdq.q.q_base, smmu->base + ARM_SMMU_CMDQ_BASE);
41532f8d6178SJean-Philippe Brucker 	writel_relaxed(smmu->cmdq.q.llq.prod, smmu->base + ARM_SMMU_CMDQ_PROD);
41542f8d6178SJean-Philippe Brucker 	writel_relaxed(smmu->cmdq.q.llq.cons, smmu->base + ARM_SMMU_CMDQ_CONS);
41552f8d6178SJean-Philippe Brucker 
41562f8d6178SJean-Philippe Brucker 	enables = CR0_CMDQEN;
41572f8d6178SJean-Philippe Brucker 	ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
41582f8d6178SJean-Philippe Brucker 				      ARM_SMMU_CR0ACK);
41592f8d6178SJean-Philippe Brucker 	if (ret) {
41602f8d6178SJean-Philippe Brucker 		dev_err(smmu->dev, "failed to enable command queue\n");
41612f8d6178SJean-Philippe Brucker 		return ret;
41622f8d6178SJean-Philippe Brucker 	}
41632f8d6178SJean-Philippe Brucker 
41642f8d6178SJean-Philippe Brucker 	/* Invalidate any cached configuration */
41652f8d6178SJean-Philippe Brucker 	cmd.opcode = CMDQ_OP_CFGI_ALL;
41662f8d6178SJean-Philippe Brucker 	arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
41672f8d6178SJean-Philippe Brucker 
41682f8d6178SJean-Philippe Brucker 	/* Invalidate any stale TLB entries */
41692f8d6178SJean-Philippe Brucker 	if (smmu->features & ARM_SMMU_FEAT_HYP) {
41702f8d6178SJean-Philippe Brucker 		cmd.opcode = CMDQ_OP_TLBI_EL2_ALL;
41712f8d6178SJean-Philippe Brucker 		arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
41722f8d6178SJean-Philippe Brucker 	}
41732f8d6178SJean-Philippe Brucker 
41742985b521SLorenzo Pieralisi 	cmd.opcode = CMDQ_OP_TLBI_NSNH_ALL;
417548ec83bcSWill Deacon 	arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
417648ec83bcSWill Deacon 
41772985b521SLorenzo Pieralisi 	/* Event queue */
417848ec83bcSWill Deacon 	writeq_relaxed(smmu->evtq.q.q_base, smmu->base + ARM_SMMU_EVTQ_BASE);
417948ec83bcSWill Deacon 	writel_relaxed(smmu->evtq.q.llq.prod, smmu->page1 + ARM_SMMU_EVTQ_PROD);
418048ec83bcSWill Deacon 	writel_relaxed(smmu->evtq.q.llq.cons, smmu->page1 + ARM_SMMU_EVTQ_CONS);
418148ec83bcSWill Deacon 
418248ec83bcSWill Deacon 	enables |= CR0_EVTQEN;
4183cbcee19aSRobin Murphy 	ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
418448ec83bcSWill Deacon 				      ARM_SMMU_CR0ACK);
418548ec83bcSWill Deacon 	if (ret) {
418648ec83bcSWill Deacon 		dev_err(smmu->dev, "failed to enable event queue\n");
418748ec83bcSWill Deacon 		return ret;
418848ec83bcSWill Deacon 	}
418948ec83bcSWill Deacon 
419048ec83bcSWill Deacon 	/* PRI queue */
419148ec83bcSWill Deacon 	if (smmu->features & ARM_SMMU_FEAT_PRI) {
419248ec83bcSWill Deacon 		writeq_relaxed(smmu->priq.q.q_base,
419348ec83bcSWill Deacon 			       smmu->base + ARM_SMMU_PRIQ_BASE);
4194cbcee19aSRobin Murphy 		writel_relaxed(smmu->priq.q.llq.prod,
419548ec83bcSWill Deacon 			       smmu->page1 + ARM_SMMU_PRIQ_PROD);
419648ec83bcSWill Deacon 		writel_relaxed(smmu->priq.q.llq.cons,
419748ec83bcSWill Deacon 			       smmu->page1 + ARM_SMMU_PRIQ_CONS);
419848ec83bcSWill Deacon 
419948ec83bcSWill Deacon 		enables |= CR0_PRIQEN;
420048ec83bcSWill Deacon 		ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
420148ec83bcSWill Deacon 					      ARM_SMMU_CR0ACK);
420248ec83bcSWill Deacon 		if (ret) {
420348ec83bcSWill Deacon 			dev_err(smmu->dev, "failed to enable PRI queue\n");
420448ec83bcSWill Deacon 			return ret;
420548ec83bcSWill Deacon 		}
420648ec83bcSWill Deacon 	}
420748ec83bcSWill Deacon 
420848ec83bcSWill Deacon 	if (smmu->features & ARM_SMMU_FEAT_ATS) {
420948ec83bcSWill Deacon 		enables |= CR0_ATSCHK;
421048ec83bcSWill Deacon 		ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
421148ec83bcSWill Deacon 					      ARM_SMMU_CR0ACK);
421248ec83bcSWill Deacon 		if (ret) {
421348ec83bcSWill Deacon 			dev_err(smmu->dev, "failed to enable ATS check\n");
421448ec83bcSWill Deacon 			return ret;
421548ec83bcSWill Deacon 		}
421648ec83bcSWill Deacon 	}
421748ec83bcSWill Deacon 
421848ec83bcSWill Deacon 	ret = arm_smmu_setup_irqs(smmu);
421948ec83bcSWill Deacon 	if (ret) {
422048ec83bcSWill Deacon 		dev_err(smmu->dev, "failed to setup irqs\n");
422148ec83bcSWill Deacon 		return ret;
4222bd07a20aSBarry Song 	}
422348ec83bcSWill Deacon 
4224bd07a20aSBarry Song 	if (is_kdump_kernel())
4225bd07a20aSBarry Song 		enables &= ~(CR0_EVTQEN | CR0_PRIQEN);
4226bd07a20aSBarry Song 
422748ec83bcSWill Deacon 	/* Enable the SMMU interface */
42289111aebfSJean-Philippe Brucker 	enables |= CR0_SMMUEN;
422948ec83bcSWill Deacon 	ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
42309111aebfSJean-Philippe Brucker 				      ARM_SMMU_CR0ACK);
42319111aebfSJean-Philippe Brucker 	if (ret) {
42329111aebfSJean-Philippe Brucker 		dev_err(smmu->dev, "failed to enable SMMU interface\n");
423348ec83bcSWill Deacon 		return ret;
42342f8d6178SJean-Philippe Brucker 	}
42352f8d6178SJean-Philippe Brucker 
423648ec83bcSWill Deacon 	if (smmu->impl_ops && smmu->impl_ops->device_reset) {
42372985b521SLorenzo Pieralisi 		ret = smmu->impl_ops->device_reset(smmu);
423848ec83bcSWill Deacon 		if (ret) {
423948ec83bcSWill Deacon 			dev_err(smmu->dev, "failed to reset impl\n");
424048ec83bcSWill Deacon 			return ret;
42412a22baa2SRobin Murphy 		}
424248ec83bcSWill Deacon 	}
424348ec83bcSWill Deacon 
4244cbcee19aSRobin Murphy 	return 0;
42456380be05SPrem Mallappa }
42469cff86fdSYisheng Xie 
4247df561f66SGustavo A. R. Silva #define IIDR_IMPLEMENTER_ARM		0x43b
42489cff86fdSYisheng Xie #define IIDR_PRODUCTID_ARM_MMU_600	0x483
424948ec83bcSWill Deacon #define IIDR_PRODUCTID_ARM_MMU_700	0x487
42506380be05SPrem Mallappa 
arm_smmu_device_iidr_probe(struct arm_smmu_device * smmu)425148ec83bcSWill Deacon static void arm_smmu_device_iidr_probe(struct arm_smmu_device *smmu)
425248ec83bcSWill Deacon {
425348ec83bcSWill Deacon 	u32 reg;
425448ec83bcSWill Deacon 	unsigned int implementer, productid, variant, revision;
425548ec83bcSWill Deacon 
425648ec83bcSWill Deacon 	reg = readl_relaxed(smmu->base + ARM_SMMU_IIDR);
425748ec83bcSWill Deacon 	implementer = FIELD_GET(IIDR_IMPLEMENTER, reg);
425848ec83bcSWill Deacon 	productid = FIELD_GET(IIDR_PRODUCTID, reg);
425948ec83bcSWill Deacon 	variant = FIELD_GET(IIDR_VARIANT, reg);
426048ec83bcSWill Deacon 	revision = FIELD_GET(IIDR_REVISION, reg);
426148ec83bcSWill Deacon 
426248ec83bcSWill Deacon 	switch (implementer) {
426348ec83bcSWill Deacon 	case IIDR_IMPLEMENTER_ARM:
4264cbcee19aSRobin Murphy 		switch (productid) {
4265f0c453dbSWill Deacon 		case IIDR_PRODUCTID_ARM_MMU_600:
4266f0c453dbSWill Deacon 			/* Arm erratum 1076982 */
4267df561f66SGustavo A. R. Silva 			if (variant == 0 && revision <= 2)
4268f0c453dbSWill Deacon 				smmu->features &= ~ARM_SMMU_FEAT_SEV;
4269f0c453dbSWill Deacon 			/* Arm erratum 1209401 */
4270f0c453dbSWill Deacon 			if (variant < 2)
427148ec83bcSWill Deacon 				smmu->features &= ~ARM_SMMU_FEAT_NESTING;
427248ec83bcSWill Deacon 			break;
427348ec83bcSWill Deacon 		case IIDR_PRODUCTID_ARM_MMU_700:
427448ec83bcSWill Deacon 			/* Arm erratum 2812531 */
427548ec83bcSWill Deacon 			smmu->features &= ~ARM_SMMU_FEAT_BTM;
427648ec83bcSWill Deacon 			smmu->options |= ARM_SMMU_OPT_CMDQ_FORCE_SYNC;
427748ec83bcSWill Deacon 			/* Arm errata 2268618, 2812531 */
427848ec83bcSWill Deacon 			smmu->features &= ~ARM_SMMU_FEAT_NESTING;
427948ec83bcSWill Deacon 			break;
428048ec83bcSWill Deacon 		}
428148ec83bcSWill Deacon 		break;
428248ec83bcSWill Deacon 	}
428348ec83bcSWill Deacon }
428448ec83bcSWill Deacon 
arm_smmu_get_httu(struct arm_smmu_device * smmu,u32 reg)428548ec83bcSWill Deacon static void arm_smmu_get_httu(struct arm_smmu_device *smmu, u32 reg)
4286ec9098d6SMostafa Saleh {
4287ec9098d6SMostafa Saleh 	u32 fw_features = smmu->features & (ARM_SMMU_FEAT_HA | ARM_SMMU_FEAT_HD);
4288ec9098d6SMostafa Saleh 	u32 hw_features = 0;
4289d25f6eadSWill Deacon 
429052be8637SWill Deacon 	switch (FIELD_GET(IDR0_HTTU, reg)) {
4291cbcee19aSRobin Murphy 	case IDR0_HTTU_ACCESS_DIRTY:
42922af2e72bSWill Deacon 		hw_features |= ARM_SMMU_FEAT_HD;
4293587e6c10SWill Deacon 		fallthrough;
42942af2e72bSWill Deacon 	case IDR0_HTTU_ACCESS:
42952af2e72bSWill Deacon 		hw_features |= ARM_SMMU_FEAT_HA;
42962af2e72bSWill Deacon 	}
42972af2e72bSWill Deacon 
4298587e6c10SWill Deacon 	if (smmu->dev->of_node)
42992af2e72bSWill Deacon 		smmu->features |= hw_features;
43002af2e72bSWill Deacon 	else if (hw_features != fw_features)
430148ec83bcSWill Deacon 		/* ACPI IORT sets the HTTU bits */
430248ec83bcSWill Deacon 		dev_warn(smmu->dev,
430348ec83bcSWill Deacon 			 "IDR0.HTTU features(0x%x) overridden by FW configuration (0x%x)\n",
430452be8637SWill Deacon 			  hw_features, fw_features);
4305cbcee19aSRobin Murphy }
430652be8637SWill Deacon 
arm_smmu_device_hw_probe(struct arm_smmu_device * smmu)4307cbcee19aSRobin Murphy static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
430848ec83bcSWill Deacon {
430948ec83bcSWill Deacon 	u32 reg;
4310cbcee19aSRobin Murphy 	bool coherent = smmu->features & ARM_SMMU_FEAT_COHERENCY;
4311cbcee19aSRobin Murphy 
43121adf3cc2SLu Baolu 	/* IDR0 */
431348ec83bcSWill Deacon 	reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0);
4314692c4e42SNate Watterson 
4315692c4e42SNate Watterson 	/* 2-level structures */
4316692c4e42SNate Watterson 	if (FIELD_GET(IDR0_ST_LVL, reg) == IDR0_ST_LVL_2LVL)
4317692c4e42SNate Watterson 		smmu->features |= ARM_SMMU_FEAT_2_LVL_STRTAB;
4318692c4e42SNate Watterson 
4319692c4e42SNate Watterson 	if (reg & IDR0_CD2L)
4320692c4e42SNate Watterson 		smmu->features |= ARM_SMMU_FEAT_2_LVL_CDTAB;
43216a481a95SRob Herring 
43226a481a95SRob Herring 	/*
43236a481a95SRob Herring 	 * Translation table endianness.
43246a481a95SRob Herring 	 * We currently require the same endianness as the CPU, but this
43256a481a95SRob Herring 	 * could be changed later by adding a new IO_PGTABLE_QUIRK.
432648ec83bcSWill Deacon 	 */
432748ec83bcSWill Deacon 	switch (FIELD_GET(IDR0_TTENDIAN, reg)) {
432848ec83bcSWill Deacon 	case IDR0_TTENDIAN_MIXED:
432948ec83bcSWill Deacon 		smmu->features |= ARM_SMMU_FEAT_TT_LE | ARM_SMMU_FEAT_TT_BE;
4330cbcee19aSRobin Murphy 		break;
433148ec83bcSWill Deacon #ifdef __BIG_ENDIAN
433248ec83bcSWill Deacon 	case IDR0_TTENDIAN_BE:
433348ec83bcSWill Deacon 		smmu->features |= ARM_SMMU_FEAT_TT_BE;
4334d5466357SRobin Murphy 		break;
433548ec83bcSWill Deacon #else
4336d5466357SRobin Murphy 	case IDR0_TTENDIAN_LE:
433748ec83bcSWill Deacon 		smmu->features |= ARM_SMMU_FEAT_TT_LE;
4338d5466357SRobin Murphy 		break;
433948ec83bcSWill Deacon #endif
4340dcd189e6SRobin Murphy 	default:
4341dcd189e6SRobin Murphy 		dev_err(smmu->dev, "unknown/unsupported TT endianness!\n");
4342dcd189e6SRobin Murphy 		return -ENXIO;
4343dcd189e6SRobin Murphy 	}
434448ec83bcSWill Deacon 
4345cbcee19aSRobin Murphy 	/* Boolean feature flags */
434648ec83bcSWill Deacon 	if (IS_ENABLED(CONFIG_PCI_PRI) && reg & IDR0_PRI)
434748ec83bcSWill Deacon 		smmu->features |= ARM_SMMU_FEAT_PRI;
434848ec83bcSWill Deacon 
434948ec83bcSWill Deacon 	if (IS_ENABLED(CONFIG_PCI_ATS) && reg & IDR0_ATS)
435048ec83bcSWill Deacon 		smmu->features |= ARM_SMMU_FEAT_ATS;
435148ec83bcSWill Deacon 
435248ec83bcSWill Deacon 	if (reg & IDR0_SEV)
435348ec83bcSWill Deacon 		smmu->features |= ARM_SMMU_FEAT_SEV;
435448ec83bcSWill Deacon 
435548ec83bcSWill Deacon 	if (reg & IDR0_MSI) {
435648ec83bcSWill Deacon 		smmu->features |= ARM_SMMU_FEAT_MSI;
435748ec83bcSWill Deacon 		if (coherent && !disable_msipolling)
435848ec83bcSWill Deacon 			smmu->options |= ARM_SMMU_OPT_MSIPOLL;
435948ec83bcSWill Deacon 	}
436048ec83bcSWill Deacon 
43616619c913SRobin Murphy 	if (reg & IDR0_HYP) {
43626619c913SRobin Murphy 		smmu->features |= ARM_SMMU_FEAT_HYP;
43636619c913SRobin Murphy 		if (cpus_have_cap(ARM64_HAS_VIRT_HOST_EXTN))
43646619c913SRobin Murphy 			smmu->features |= ARM_SMMU_FEAT_E2H;
436585430968SWill Deacon 	}
436685430968SWill Deacon 
436785430968SWill Deacon 	arm_smmu_get_httu(smmu, reg);
4368df561f66SGustavo A. R. Silva 
436948ec83bcSWill Deacon 	/*
437048ec83bcSWill Deacon 	 * The coherency feature as set by FW is used in preference to the ID
437148ec83bcSWill Deacon 	 * register, but warn on mismatch.
437248ec83bcSWill Deacon 	 */
43736619c913SRobin Murphy 	if (!!(reg & IDR0_COHACC) != coherent)
43746619c913SRobin Murphy 		dev_warn(smmu->dev, "IDR0.COHACC overridden by FW configuration (%s)\n",
43756619c913SRobin Murphy 			 str_true_false(coherent));
43766619c913SRobin Murphy 
43776619c913SRobin Murphy 	switch (FIELD_GET(IDR0_STALL_MODEL, reg)) {
437848ec83bcSWill Deacon 	case IDR0_STALL_MODEL_FORCE:
437948ec83bcSWill Deacon 		smmu->features |= ARM_SMMU_FEAT_STALL_FORCE;
438048ec83bcSWill Deacon 		fallthrough;
438148ec83bcSWill Deacon 	case IDR0_STALL_MODEL_STALL:
438248ec83bcSWill Deacon 		smmu->features |= ARM_SMMU_FEAT_STALLS;
4383f0c453dbSWill Deacon 	}
438448ec83bcSWill Deacon 
43851d9777b9SRobin Murphy 	if (reg & IDR0_S1P)
43861d9777b9SRobin Murphy 		smmu->features |= ARM_SMMU_FEAT_TRANS_S1;
43871d9777b9SRobin Murphy 
43881d9777b9SRobin Murphy 	if (reg & IDR0_S2P)
4389f322e8afSRobin Murphy 		smmu->features |= ARM_SMMU_FEAT_TRANS_S2;
4390f322e8afSRobin Murphy 
4391d744f9e6SJean-Philippe Brucker 	if (!(reg & (IDR0_S1P | IDR0_S2P))) {
4392d744f9e6SJean-Philippe Brucker 		dev_err(smmu->dev, "no translation support!\n");
4393d744f9e6SJean-Philippe Brucker 		return -ENXIO;
439448ec83bcSWill Deacon 	}
439548ec83bcSWill Deacon 
439648ec83bcSWill Deacon 	/* We only support the AArch64 table format at present */
439748ec83bcSWill Deacon 	switch (FIELD_GET(IDR0_TTF, reg)) {
439848ec83bcSWill Deacon 	case IDR0_TTF_AARCH32_64:
4399e4dadfa8SLorenzo Pieralisi 		smmu->ias = 40;
4400918eb5c8SNate Watterson 		fallthrough;
4401918eb5c8SNate Watterson 	case IDR0_TTF_AARCH64:
4402918eb5c8SNate Watterson 		break;
4403e5b829deSLinu Cherian 	default:
4404918eb5c8SNate Watterson 		dev_err(smmu->dev, "AArch64 table format not supported!\n");
4405918eb5c8SNate Watterson 		return -ENXIO;
4406918eb5c8SNate Watterson 	}
4407918eb5c8SNate Watterson 
4408918eb5c8SNate Watterson 	/* ASID/VMID sizes */
4409918eb5c8SNate Watterson 	smmu->asid_bits = reg & IDR0_ASID16 ? 16 : 8;
4410918eb5c8SNate Watterson 	smmu->vmid_bits = reg & IDR0_VMID16 ? 16 : 8;
4411918eb5c8SNate Watterson 
4412918eb5c8SNate Watterson 	/* IDR1 */
4413918eb5c8SNate Watterson 	reg = readl_relaxed(smmu->base + ARM_SMMU_IDR1);
4414918eb5c8SNate Watterson 	if (reg & (IDR1_TABLES_PRESET | IDR1_QUEUES_PRESET | IDR1_REL)) {
4415918eb5c8SNate Watterson 		dev_err(smmu->dev, "embedded implementation not supported\n");
4416918eb5c8SNate Watterson 		return -ENXIO;
4417918eb5c8SNate Watterson 	}
4418918eb5c8SNate Watterson 
4419918eb5c8SNate Watterson 	if (reg & IDR1_ATTR_TYPES_OVR)
4420918eb5c8SNate Watterson 		smmu->features |= ARM_SMMU_FEAT_ATTR_TYPES_OVR;
4421918eb5c8SNate Watterson 
4422918eb5c8SNate Watterson 	/* Queue sizes, capped to ensure natural alignment */
4423918eb5c8SNate Watterson 	smmu->cmdq.q.llq.max_n_shift = min_t(u32, CMDQ_MAX_SZ_SHIFT,
4424918eb5c8SNate Watterson 					     FIELD_GET(IDR1_CMDQS, reg));
44256f3f9ff4SNicolin Chen 	if (smmu->cmdq.q.llq.max_n_shift <= ilog2(CMDQ_BATCH_ENTRIES)) {
44266f3f9ff4SNicolin Chen 		/*
4427e5b829deSLinu Cherian 		 * We don't support splitting up batches, so one batch of
44286f3f9ff4SNicolin Chen 		 * commands plus an extra sync needs to fit inside the command
44296f3f9ff4SNicolin Chen 		 * queue. There's also no way we can handle the weird alignment
44306f3f9ff4SNicolin Chen 		 * restrictions on the base pointer for a unit-length queue.
44316f3f9ff4SNicolin Chen 		 */
443299caf177Sshameer 		dev_err(smmu->dev, "command queue size <= %d entries not supported\n",
4433e5b829deSLinu Cherian 			CMDQ_BATCH_ENTRIES);
443499caf177Sshameer 		return -ENXIO;
44356948d4a7SRobin Murphy 	}
443699caf177Sshameer 
443799caf177Sshameer 	smmu->evtq.q.llq.max_n_shift = min_t(u32, EVTQ_MAX_SZ_SHIFT,
44386f3f9ff4SNicolin Chen 					     FIELD_GET(IDR1_EVTQS, reg));
4439918eb5c8SNate Watterson 	smmu->priq.q.llq.max_n_shift = min_t(u32, PRIQ_MAX_SZ_SHIFT,
4440918eb5c8SNate Watterson 					     FIELD_GET(IDR1_PRIQS, reg));
4441918eb5c8SNate Watterson 
4442918eb5c8SNate Watterson 	/* SID/SSID sizes */
4443918eb5c8SNate Watterson 	smmu->ssid_bits = FIELD_GET(IDR1_SSIDSIZE, reg);
44446f3f9ff4SNicolin Chen 	smmu->sid_bits = FIELD_GET(IDR1_SIDSIZE, reg);
444599caf177Sshameer 	smmu->iommu.max_pasids = 1UL << smmu->ssid_bits;
4446e5b829deSLinu Cherian 
4447e5b829deSLinu Cherian 	/*
44486f3f9ff4SNicolin Chen 	 * If the SMMU supports fewer bits than would fill a single L2 stream
4449e5b829deSLinu Cherian 	 * table, use a linear table instead.
4450e5b829deSLinu Cherian 	 */
4451e4dadfa8SLorenzo Pieralisi 	if (smmu->sid_bits <= STRTAB_SPLIT)
4452e4dadfa8SLorenzo Pieralisi 		smmu->features &= ~ARM_SMMU_FEAT_2_LVL_STRTAB;
4453e4dadfa8SLorenzo Pieralisi 
4454e4dadfa8SLorenzo Pieralisi 	/* IDR3 */
4455e4dadfa8SLorenzo Pieralisi 	reg = readl_relaxed(smmu->base + ARM_SMMU_IDR3);
4456e4dadfa8SLorenzo Pieralisi 	if (FIELD_GET(IDR3_RIL, reg))
4457e4dadfa8SLorenzo Pieralisi 		smmu->features |= ARM_SMMU_FEAT_RANGE_INV;
4458e4dadfa8SLorenzo Pieralisi 	if (FIELD_GET(IDR3_FWB, reg))
4459e4dadfa8SLorenzo Pieralisi 		smmu->features |= ARM_SMMU_FEAT_S2FWB;
4460e4dadfa8SLorenzo Pieralisi 
4461e4dadfa8SLorenzo Pieralisi 	if (FIELD_GET(IDR3_BBM, reg) == 2)
4462e4dadfa8SLorenzo Pieralisi 		smmu->features |= ARM_SMMU_FEAT_BBML2;
4463e4dadfa8SLorenzo Pieralisi 
4464e4dadfa8SLorenzo Pieralisi 	/* IDR5 */
4465e4dadfa8SLorenzo Pieralisi 	reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5);
44662f8d6178SJean-Philippe Brucker 
44672f8d6178SJean-Philippe Brucker 	/* Maximum number of outstanding stalls */
44682f8d6178SJean-Philippe Brucker 	smmu->evtq.max_stalls = FIELD_GET(IDR5_STALL_MAX, reg);
44692f8d6178SJean-Philippe Brucker 
44702f8d6178SJean-Philippe Brucker 	/* Page sizes */
44712f8d6178SJean-Philippe Brucker 	if (reg & IDR5_GRAN64K)
44722f8d6178SJean-Philippe Brucker 		smmu->pgsize_bitmap |= SZ_64K | SZ_512M;
44732f8d6178SJean-Philippe Brucker 	if (reg & IDR5_GRAN16K)
44746f3f9ff4SNicolin Chen 		smmu->pgsize_bitmap |= SZ_16K | SZ_32M;
4475e4dadfa8SLorenzo Pieralisi 	if (reg & IDR5_GRAN4K)
4476e4dadfa8SLorenzo Pieralisi 		smmu->pgsize_bitmap |= SZ_4K | SZ_2M | SZ_1G;
4477e4dadfa8SLorenzo Pieralisi 
4478e4dadfa8SLorenzo Pieralisi 	/* Input address size */
4479e4dadfa8SLorenzo Pieralisi 	if (FIELD_GET(IDR5_VAX, reg) == IDR5_VAX_52_BIT)
4480e4dadfa8SLorenzo Pieralisi 		smmu->features |= ARM_SMMU_FEAT_VAX;
4481e4dadfa8SLorenzo Pieralisi 
4482e4dadfa8SLorenzo Pieralisi 	/* Output address size */
4483e4dadfa8SLorenzo Pieralisi 	switch (FIELD_GET(IDR5_OAS, reg)) {
44842985b521SLorenzo Pieralisi 	case IDR5_OAS_32_BIT:
44852985b521SLorenzo Pieralisi 		smmu->oas = 32;
448648ec83bcSWill Deacon 		break;
448748ec83bcSWill Deacon 	case IDR5_OAS_36_BIT:
4488dc87a98dSRobin Murphy 		smmu->oas = 36;
44892985b521SLorenzo Pieralisi 		break;
4490dc87a98dSRobin Murphy 	case IDR5_OAS_40_BIT:
4491dc87a98dSRobin Murphy 		smmu->oas = 40;
4492dc87a98dSRobin Murphy 		break;
4493dc87a98dSRobin Murphy 	case IDR5_OAS_42_BIT:
4494dc87a98dSRobin Murphy 		smmu->oas = 42;
4495dc87a98dSRobin Murphy 		break;
44962985b521SLorenzo Pieralisi 	case IDR5_OAS_44_BIT:
44972985b521SLorenzo Pieralisi 		smmu->oas = 44;
44982985b521SLorenzo Pieralisi 		break;
44992985b521SLorenzo Pieralisi 	case IDR5_OAS_52_BIT:
45002985b521SLorenzo Pieralisi 		smmu->oas = 52;
45012985b521SLorenzo Pieralisi 		smmu->pgsize_bitmap |= 1ULL << 42; /* 4TB */
45022985b521SLorenzo Pieralisi 		break;
45032985b521SLorenzo Pieralisi 	default:
45042985b521SLorenzo Pieralisi 		dev_info(smmu->dev,
45052985b521SLorenzo Pieralisi 			"unknown output address size. Truncating to 48-bit\n");
4506e5b829deSLinu Cherian 		fallthrough;
4507e5b829deSLinu Cherian 	case IDR5_OAS_48_BIT:
4508e5b829deSLinu Cherian 		smmu->oas = 48;
4509e5b829deSLinu Cherian 	}
4510e5b829deSLinu Cherian 
4511e5b829deSLinu Cherian 	/* Set the DMA mask for our table walker */
4512e5b829deSLinu Cherian 	if (dma_set_mask_and_coherent(smmu->dev, DMA_BIT_MASK(smmu->oas)))
4513e5b829deSLinu Cherian 		dev_warn(smmu->dev,
451452f3fab0SJean-Philippe Brucker 			 "failed to set DMA mask for table walker\n");
451552f3fab0SJean-Philippe Brucker 
451652f3fab0SJean-Philippe Brucker 	smmu->ias = max(smmu->ias, smmu->oas);
4517932bc8c7SZhen Lei 
451852f3fab0SJean-Philippe Brucker 	if ((smmu->features & ARM_SMMU_FEAT_TRANS_S1) &&
451952f3fab0SJean-Philippe Brucker 	    (smmu->features & ARM_SMMU_FEAT_TRANS_S2))
452052f3fab0SJean-Philippe Brucker 		smmu->features |= ARM_SMMU_FEAT_NESTING;
452152f3fab0SJean-Philippe Brucker 
45229bdbdaa3SShameer Kolothum 	arm_smmu_device_iidr_probe(smmu);
45239bdbdaa3SShameer Kolothum 
45249bdbdaa3SShameer Kolothum 	if (arm_smmu_sva_supported(smmu))
45259bdbdaa3SShameer Kolothum 		smmu->features |= ARM_SMMU_FEAT_SVA;
45269bdbdaa3SShameer Kolothum 
45279bdbdaa3SShameer Kolothum 	dev_info(smmu->dev, "ias %lu-bit, oas %lu-bit (features 0x%08x)\n",
45289bdbdaa3SShameer Kolothum 		 smmu->ias, smmu->oas, smmu->features);
45299bdbdaa3SShameer Kolothum 	return 0;
45309bdbdaa3SShameer Kolothum }
45319bdbdaa3SShameer Kolothum 
45329bdbdaa3SShameer Kolothum #ifdef CONFIG_ACPI
45339bdbdaa3SShameer Kolothum #ifdef CONFIG_TEGRA241_CMDQV
acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node * node,struct arm_smmu_device * smmu)45349bdbdaa3SShameer Kolothum static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
45359bdbdaa3SShameer Kolothum 						struct arm_smmu_device *smmu)
45369bdbdaa3SShameer Kolothum {
45379bdbdaa3SShameer Kolothum 	const char *uid = kasprintf(GFP_KERNEL, "%u", node->identifier);
45389bdbdaa3SShameer Kolothum 	struct acpi_device *adev;
45399bdbdaa3SShameer Kolothum 
45409bdbdaa3SShameer Kolothum 	/* Look for an NVDA200C node whose _UID matches the SMMU node ID */
45419bdbdaa3SShameer Kolothum 	adev = acpi_dev_get_first_match_dev("NVDA200C", uid, -1);
45429bdbdaa3SShameer Kolothum 	if (adev) {
45437686aa5fSJason Gunthorpe 		/* Tegra241 CMDQV driver is responsible for put_device() */
45447686aa5fSJason Gunthorpe 		smmu->impl_dev = &adev->dev;
45457686aa5fSJason Gunthorpe 		smmu->options |= ARM_SMMU_OPT_TEGRA241_CMDQV;
45467686aa5fSJason Gunthorpe 		dev_info(smmu->dev, "found companion CMDQV device: %s\n",
4547ec9098d6SMostafa Saleh 			 dev_name(smmu->impl_dev));
45487686aa5fSJason Gunthorpe 	}
45499bdbdaa3SShameer Kolothum 	kfree(uid);
45509bdbdaa3SShameer Kolothum }
45519bdbdaa3SShameer Kolothum #else
acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node * node,struct arm_smmu_device * smmu)45529bdbdaa3SShameer Kolothum static void acpi_smmu_dsdt_probe_tegra241_cmdqv(struct acpi_iort_node *node,
45539bdbdaa3SShameer Kolothum 						struct arm_smmu_device *smmu)
45549bdbdaa3SShameer Kolothum {
45556de80d61SJason Gunthorpe }
45566de80d61SJason Gunthorpe #endif
45576de80d61SJason Gunthorpe 
acpi_smmu_iort_probe_model(struct acpi_iort_node * node,struct arm_smmu_device * smmu)45586de80d61SJason Gunthorpe static int acpi_smmu_iort_probe_model(struct acpi_iort_node *node,
45596de80d61SJason Gunthorpe 				      struct arm_smmu_device *smmu)
45606de80d61SJason Gunthorpe {
45616de80d61SJason Gunthorpe 	struct acpi_iort_smmu_v3 *iort_smmu =
45626de80d61SJason Gunthorpe 		(struct acpi_iort_smmu_v3 *)node->node_data;
45636de80d61SJason Gunthorpe 
45646de80d61SJason Gunthorpe 	switch (iort_smmu->model) {
45656de80d61SJason Gunthorpe 	case ACPI_IORT_SMMU_V3_CAVIUM_CN99XX:
45666de80d61SJason Gunthorpe 		smmu->options |= ARM_SMMU_OPT_PAGE0_REGS_ONLY;
45676de80d61SJason Gunthorpe 		break;
45686de80d61SJason Gunthorpe 	case ACPI_IORT_SMMU_V3_HISILICON_HI161X:
45696de80d61SJason Gunthorpe 		smmu->options |= ARM_SMMU_OPT_SKIP_PREFETCH;
45706de80d61SJason Gunthorpe 		break;
45716de80d61SJason Gunthorpe 	case ACPI_IORT_SMMU_V3_GENERIC:
45726de80d61SJason Gunthorpe 		/*
4573918eb5c8SNate Watterson 		 * Tegra241 implementation stores its SMMU options and impl_dev
4574918eb5c8SNate Watterson 		 * in DSDT. Thus, go through the ACPI tables unconditionally.
45756de80d61SJason Gunthorpe 		 */
45766de80d61SJason Gunthorpe 		acpi_smmu_dsdt_probe_tegra241_cmdqv(node, smmu);
45776de80d61SJason Gunthorpe 		break;
45786de80d61SJason Gunthorpe 	}
45796de80d61SJason Gunthorpe 
45806de80d61SJason Gunthorpe 	dev_notice(smmu->dev, "option mask 0x%x\n", smmu->options);
45816de80d61SJason Gunthorpe 	return 0;
45826de80d61SJason Gunthorpe }
45836de80d61SJason Gunthorpe 
arm_smmu_device_acpi_probe(struct platform_device * pdev,struct arm_smmu_device * smmu)45846de80d61SJason Gunthorpe static int arm_smmu_device_acpi_probe(struct platform_device *pdev,
45856de80d61SJason Gunthorpe 				      struct arm_smmu_device *smmu)
45866de80d61SJason Gunthorpe {
45876de80d61SJason Gunthorpe 	struct acpi_iort_smmu_v3 *iort_smmu;
45882985b521SLorenzo Pieralisi 	struct device *dev = smmu->dev;
45892985b521SLorenzo Pieralisi 	struct acpi_iort_node *node;
45902985b521SLorenzo Pieralisi 
45912985b521SLorenzo Pieralisi 	node = *(struct acpi_iort_node **)dev_get_platdata(dev);
45929648cbc9SJoerg Roedel 
45932985b521SLorenzo Pieralisi 	/* Retrieve SMMUv3 specific data */
45942985b521SLorenzo Pieralisi 	iort_smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
459548ec83bcSWill Deacon 
459648ec83bcSWill Deacon 	if (iort_smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE)
4597affa9095SZhen Lei 		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
459848ec83bcSWill Deacon 
459948ec83bcSWill Deacon 	switch (FIELD_GET(ACPI_IORT_SMMU_V3_HTTU_OVERRIDE, iort_smmu->flags)) {
460048ec83bcSWill Deacon 	case IDR0_HTTU_ACCESS_DIRTY:
4601e5b829deSLinu Cherian 		smmu->features |= ARM_SMMU_FEAT_HD;
4602e5b829deSLinu Cherian 		fallthrough;
4603e5b829deSLinu Cherian 	case IDR0_HTTU_ACCESS:
4604e5b829deSLinu Cherian 		smmu->features |= ARM_SMMU_FEAT_HA;
4605e5b829deSLinu Cherian 	}
4606734554fdSRobin Murphy 
4607734554fdSRobin Murphy 	return acpi_smmu_iort_probe_model(node, smmu);
4608e5b829deSLinu Cherian }
46096de80d61SJason Gunthorpe #else
arm_smmu_device_acpi_probe(struct platform_device * pdev,struct arm_smmu_device * smmu)46106de80d61SJason Gunthorpe static inline int arm_smmu_device_acpi_probe(struct platform_device *pdev,
46116de80d61SJason Gunthorpe 					     struct arm_smmu_device *smmu)
46126de80d61SJason Gunthorpe {
461348ec83bcSWill Deacon 	return -ENODEV;
461448ec83bcSWill Deacon }
4615b131fa8cSYang Yingliang #endif
4616b131fa8cSYang Yingliang 
arm_smmu_device_dt_probe(struct platform_device * pdev,struct arm_smmu_device * smmu)4617322a9bbbSMasahiro Yamada static int arm_smmu_device_dt_probe(struct platform_device *pdev,
461848ec83bcSWill Deacon 				    struct arm_smmu_device *smmu)
461948ec83bcSWill Deacon {
462048ec83bcSWill Deacon 	struct device *dev = &pdev->dev;
46219648cbc9SJoerg Roedel 	u32 cells;
462248ec83bcSWill Deacon 	int ret = -EINVAL;
462352f3fab0SJean-Philippe Brucker 
462452f3fab0SJean-Philippe Brucker 	if (of_property_read_u32(dev->of_node, "#iommu-cells", &cells))
462552f3fab0SJean-Philippe Brucker 		dev_err(dev, "missing #iommu-cells property\n");
462652f3fab0SJean-Philippe Brucker 	else if (cells != 1)
462752f3fab0SJean-Philippe Brucker 		dev_err(dev, "invalid #iommu-cells value (%d)\n", cells);
462848ec83bcSWill Deacon 	else
462948ec83bcSWill Deacon 		ret = 0;
463048ec83bcSWill Deacon 
463152f3fab0SJean-Philippe Brucker 	parse_driver_options(smmu);
463252f3fab0SJean-Philippe Brucker 
463352f3fab0SJean-Philippe Brucker 	if (of_dma_is_coherent(dev->of_node))
463452f3fab0SJean-Philippe Brucker 		smmu->features |= ARM_SMMU_FEAT_COHERENCY;
463552f3fab0SJean-Philippe Brucker 
463652f3fab0SJean-Philippe Brucker 	return ret;
463752f3fab0SJean-Philippe Brucker }
463852f3fab0SJean-Philippe Brucker 
arm_smmu_resource_size(struct arm_smmu_device * smmu)463952f3fab0SJean-Philippe Brucker static unsigned long arm_smmu_resource_size(struct arm_smmu_device *smmu)
464048ec83bcSWill Deacon {
4641f935448aSGeetha Sowjanya 	if (smmu->options & ARM_SMMU_OPT_PAGE0_REGS_ONLY)
4642f7aff1a9SJean-Philippe Brucker 		return SZ_64K;
4643f935448aSGeetha Sowjanya 	else
4644f935448aSGeetha Sowjanya 		return SZ_128K;
4645f935448aSGeetha Sowjanya }
4646f7aff1a9SJean-Philippe Brucker 
arm_smmu_ioremap(struct device * dev,resource_size_t start,resource_size_t size)464748ec83bcSWill Deacon static void __iomem *arm_smmu_ioremap(struct device *dev, resource_size_t start,
464848ec83bcSWill Deacon 				      resource_size_t size)
464948ec83bcSWill Deacon {
4650f7aff1a9SJean-Philippe Brucker 	struct resource res = DEFINE_RES_MEM(start, size);
465148ec83bcSWill Deacon 
465248ec83bcSWill Deacon 	return devm_ioremap_resource(dev, &res);
465348ec83bcSWill Deacon }
4654f7aff1a9SJean-Philippe Brucker 
arm_smmu_rmr_install_bypass_ste(struct arm_smmu_device * smmu)465548ec83bcSWill Deacon static void arm_smmu_rmr_install_bypass_ste(struct arm_smmu_device *smmu)
465648ec83bcSWill Deacon {
4657f935448aSGeetha Sowjanya 	struct list_head rmr_list;
465848ec83bcSWill Deacon 	struct iommu_resv_region *e;
46592985b521SLorenzo Pieralisi 
466048ec83bcSWill Deacon 	INIT_LIST_HEAD(&rmr_list);
466148ec83bcSWill Deacon 	iort_get_rmr_sids(dev_fwnode(smmu->dev), &rmr_list);
466248ec83bcSWill Deacon 
466348ec83bcSWill Deacon 	list_for_each_entry(e, &rmr_list, list) {
466448ec83bcSWill Deacon 		struct iommu_iort_rmr_data *rmr;
466548ec83bcSWill Deacon 		int ret, i;
466648ec83bcSWill Deacon 
466748ec83bcSWill Deacon 		rmr = container_of(e, struct iommu_iort_rmr_data, rr);
4668166bdbd2SMarc Zyngier 		for (i = 0; i < rmr->num_sids; i++) {
4669166bdbd2SMarc Zyngier 			ret = arm_smmu_init_sid_strtab(smmu, rmr->sids[i]);
4670166bdbd2SMarc Zyngier 			if (ret) {
46719bdbdaa3SShameer Kolothum 				dev_err(smmu->dev, "RMR SID(0x%x) bypass failed\n",
46729bdbdaa3SShameer Kolothum 					rmr->sids[i]);
46739bdbdaa3SShameer Kolothum 				continue;
467448ec83bcSWill Deacon 			}
4675734554fdSRobin Murphy 
46768f785154SRobin Murphy 			/*
46778f785154SRobin Murphy 			 * STE table is not programmed to HW, see
46788f785154SRobin Murphy 			 * arm_smmu_initial_bypass_stes()
46798f785154SRobin Murphy 			 */
46809648cbc9SJoerg Roedel 			arm_smmu_make_bypass_ste(smmu,
46819648cbc9SJoerg Roedel 				arm_smmu_get_step_for_sid(smmu, rmr->sids[i]));
46829648cbc9SJoerg Roedel 		}
46839648cbc9SJoerg Roedel 	}
46849648cbc9SJoerg Roedel 
46852d471b20SRobin Murphy 	iort_put_rmr_sids(dev_fwnode(smmu->dev), &rmr_list);
46865c2d0218SArvind Yadav }
46875c2d0218SArvind Yadav 
arm_smmu_impl_remove(void * data)4688249c9dc6SAmey Narkhede static void arm_smmu_impl_remove(void *data)
4689249c9dc6SAmey Narkhede {
4690ec615f43SRobin Murphy 	struct arm_smmu_device *smmu = data;
469148ec83bcSWill Deacon 
46922efbd29bSRobin Murphy 	if (smmu->impl_ops && smmu->impl_ops->device_remove)
46932efbd29bSRobin Murphy 		smmu->impl_ops->device_remove(smmu);
46942efbd29bSRobin Murphy }
469566c7076fSUwe Kleine-König 
469648ec83bcSWill Deacon /*
4697941a802dSWill Deacon  * Probe all the compiled in implementations. Each one checks to see if it
469848ec83bcSWill Deacon  * matches this HW and if so returns a devm_krealloc'd arm_smmu_device which
4699ab246774SWill Deacon  * replaces the callers. Otherwise the original is returned or ERR_PTR.
4700ab246774SWill Deacon  */
arm_smmu_impl_probe(struct arm_smmu_device * smmu)470148ec83bcSWill Deacon static struct arm_smmu_device *arm_smmu_impl_probe(struct arm_smmu_device *smmu)
4702395ad89dSJean-Philippe Brucker {
47031672730cSDawei Li 	struct arm_smmu_device *new_smmu = ERR_PTR(-ENODEV);
470448ec83bcSWill Deacon 	const struct arm_smmu_impl_ops *ops;
470548ec83bcSWill Deacon 	int ret;
470648ec83bcSWill Deacon 
470748ec83bcSWill Deacon 	if (smmu->impl_dev && (smmu->options & ARM_SMMU_OPT_TEGRA241_CMDQV))
470832ea2c57SVladimir Oltean 		new_smmu = tegra241_cmdqv_probe(smmu);
470932ea2c57SVladimir Oltean 
471032ea2c57SVladimir Oltean 	if (new_smmu == ERR_PTR(-ENODEV))
47117aa8619aSNate Watterson 		return smmu;
47127aa8619aSNate Watterson 	if (IS_ERR(new_smmu))
4713ebdd13c9SArvind Yadav 		return new_smmu;
471448ec83bcSWill Deacon 
471548ec83bcSWill Deacon 	ops = new_smmu->impl_ops;
471648ec83bcSWill Deacon 	if (ops) {
47176e8fa740SWill Deacon 		/* get_viommu_size and vsmmu_init ops must be paired */
471848ec83bcSWill Deacon 		if (WARN_ON(!ops->get_viommu_size != !ops->vsmmu_init)) {
471932784a95SJean-Philippe Brucker 			ret = -EINVAL;
472032784a95SJean-Philippe Brucker 			goto err_remove;
472132784a95SJean-Philippe Brucker 		}
472232784a95SJean-Philippe Brucker 	}
472332784a95SJean-Philippe Brucker 
472432784a95SJean-Philippe Brucker 	ret = devm_add_action_or_reset(new_smmu->dev, arm_smmu_impl_remove,
472548ec83bcSWill Deacon 				       new_smmu);
472648ec83bcSWill Deacon 	if (ret)
472748ec83bcSWill Deacon 		return ERR_PTR(ret);
47288efda06fSMasahiro Yamada 	return new_smmu;
4729c07b6426SPaul Gortmaker 
473048ec83bcSWill Deacon err_remove:
47312985b521SLorenzo Pieralisi 	arm_smmu_impl_remove(new_smmu);
4732*e70140baSLinus Torvalds 	return ERR_PTR(ret);
47337aa8619aSNate Watterson }
473448ec83bcSWill Deacon 
arm_smmu_device_probe(struct platform_device * pdev)473532784a95SJean-Philippe Brucker static int arm_smmu_device_probe(struct platform_device *pdev)
473632784a95SJean-Philippe Brucker {
47376e8fa740SWill Deacon 	int irq, ret;
47386e8fa740SWill Deacon 	struct resource *res;
47391ea27ee2SWill Deacon 	resource_size_t ioaddr;
4740d3daf666SArd Biesheuvel 	struct arm_smmu_device *smmu;
47416e8fa740SWill Deacon 	struct device *dev = &pdev->dev;
4742 
4743 	smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
4744 	if (!smmu)
4745 		return -ENOMEM;
4746 	smmu->dev = dev;
4747 
4748 	if (dev->of_node) {
4749 		ret = arm_smmu_device_dt_probe(pdev, smmu);
4750 	} else {
4751 		ret = arm_smmu_device_acpi_probe(pdev, smmu);
4752 	}
4753 	if (ret)
4754 		return ret;
4755 
4756 	smmu = arm_smmu_impl_probe(smmu);
4757 	if (IS_ERR(smmu))
4758 		return PTR_ERR(smmu);
4759 
4760 	/* Base address */
4761 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4762 	if (!res)
4763 		return -EINVAL;
4764 	if (resource_size(res) < arm_smmu_resource_size(smmu)) {
4765 		dev_err(dev, "MMIO region too small (%pr)\n", res);
4766 		return -EINVAL;
4767 	}
4768 	ioaddr = res->start;
4769 
4770 	/*
4771 	 * Don't map the IMPLEMENTATION DEFINED regions, since they may contain
4772 	 * the PMCG registers which are reserved by the PMU driver.
4773 	 */
4774 	smmu->base = arm_smmu_ioremap(dev, ioaddr, ARM_SMMU_REG_SZ);
4775 	if (IS_ERR(smmu->base))
4776 		return PTR_ERR(smmu->base);
4777 
4778 	if (arm_smmu_resource_size(smmu) > SZ_64K) {
4779 		smmu->page1 = arm_smmu_ioremap(dev, ioaddr + SZ_64K,
4780 					       ARM_SMMU_REG_SZ);
4781 		if (IS_ERR(smmu->page1))
4782 			return PTR_ERR(smmu->page1);
4783 	} else {
4784 		smmu->page1 = smmu->base;
4785 	}
4786 
4787 	/* Interrupt lines */
4788 
4789 	irq = platform_get_irq_byname_optional(pdev, "combined");
4790 	if (irq > 0)
4791 		smmu->combined_irq = irq;
4792 	else {
4793 		irq = platform_get_irq_byname_optional(pdev, "eventq");
4794 		if (irq > 0)
4795 			smmu->evtq.q.irq = irq;
4796 
4797 		irq = platform_get_irq_byname_optional(pdev, "priq");
4798 		if (irq > 0)
4799 			smmu->priq.q.irq = irq;
4800 
4801 		irq = platform_get_irq_byname_optional(pdev, "gerror");
4802 		if (irq > 0)
4803 			smmu->gerr_irq = irq;
4804 	}
4805 	/* Probe the h/w */
4806 	ret = arm_smmu_device_hw_probe(smmu);
4807 	if (ret)
4808 		return ret;
4809 
4810 	/* Initialise in-memory data structures */
4811 	ret = arm_smmu_init_structures(smmu);
4812 	if (ret)
4813 		goto err_free_iopf;
4814 
4815 	/* Record our private device structure */
4816 	platform_set_drvdata(pdev, smmu);
4817 
4818 	/* Check for RMRs and install bypass STEs if any */
4819 	arm_smmu_rmr_install_bypass_ste(smmu);
4820 
4821 	/* Reset the device */
4822 	ret = arm_smmu_device_reset(smmu);
4823 	if (ret)
4824 		goto err_disable;
4825 
4826 	/* And we're up. Go go go! */
4827 	ret = iommu_device_sysfs_add(&smmu->iommu, dev, NULL,
4828 				     "smmu3.%pa", &ioaddr);
4829 	if (ret)
4830 		goto err_disable;
4831 
4832 	ret = iommu_device_register(&smmu->iommu, &arm_smmu_ops, dev);
4833 	if (ret) {
4834 		dev_err(dev, "Failed to register iommu\n");
4835 		goto err_free_sysfs;
4836 	}
4837 
4838 	return 0;
4839 
4840 err_free_sysfs:
4841 	iommu_device_sysfs_remove(&smmu->iommu);
4842 err_disable:
4843 	arm_smmu_device_disable(smmu);
4844 err_free_iopf:
4845 	iopf_queue_free(smmu->evtq.iopf);
4846 	return ret;
4847 }
4848 
arm_smmu_device_remove(struct platform_device * pdev)4849 static void arm_smmu_device_remove(struct platform_device *pdev)
4850 {
4851 	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
4852 
4853 	iommu_device_unregister(&smmu->iommu);
4854 	iommu_device_sysfs_remove(&smmu->iommu);
4855 	arm_smmu_device_disable(smmu);
4856 	iopf_queue_free(smmu->evtq.iopf);
4857 	ida_destroy(&smmu->vmid_map);
4858 }
4859 
arm_smmu_device_shutdown(struct platform_device * pdev)4860 static void arm_smmu_device_shutdown(struct platform_device *pdev)
4861 {
4862 	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
4863 
4864 	arm_smmu_device_disable(smmu);
4865 }
4866 
4867 static const struct of_device_id arm_smmu_of_match[] = {
4868 	{ .compatible = "arm,smmu-v3", },
4869 	{ },
4870 };
4871 MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
4872 
arm_smmu_driver_unregister(struct platform_driver * drv)4873 static void arm_smmu_driver_unregister(struct platform_driver *drv)
4874 {
4875 	arm_smmu_sva_notifier_synchronize();
4876 	platform_driver_unregister(drv);
4877 }
4878 
4879 static struct platform_driver arm_smmu_driver = {
4880 	.driver	= {
4881 		.name			= "arm-smmu-v3",
4882 		.of_match_table		= arm_smmu_of_match,
4883 		.suppress_bind_attrs	= true,
4884 	},
4885 	.probe	= arm_smmu_device_probe,
4886 	.remove = arm_smmu_device_remove,
4887 	.shutdown = arm_smmu_device_shutdown,
4888 };
4889 module_driver(arm_smmu_driver, platform_driver_register,
4890 	      arm_smmu_driver_unregister);
4891 
4892 MODULE_DESCRIPTION("IOMMU API for ARM architected SMMUv3 implementations");
4893 MODULE_AUTHOR("Will Deacon <will@kernel.org>");
4894 MODULE_ALIAS("platform:arm-smmu-v3");
4895 MODULE_LICENSE("GPL v2");
4896