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(®ion->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