Blame view

drivers/iommu/ipmmu-vmsa.c 30.4 KB
57d3f11c8   Kuninori Morimoto   iommu/ipmmu-vmsa:...
1
  // SPDX-License-Identifier: GPL-2.0
d25a2a16f   Laurent Pinchart   iommu: Add driver...
2
  /*
8128ac3b0   Paul Gortmaker   iommu/ipmmu-vmsa:...
3
4
   * IOMMU API for Renesas VMSA-compatible IPMMU
   * Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
d25a2a16f   Laurent Pinchart   iommu: Add driver...
5
   *
17fe16181   Yoshihiro Shimoda   iommu/renesas: Ad...
6
   * Copyright (C) 2014-2020 Renesas Electronics Corporation
d25a2a16f   Laurent Pinchart   iommu: Add driver...
7
   */
dbb706922   Magnus Damm   iommu/ipmmu-vmsa:...
8
  #include <linux/bitmap.h>
d25a2a16f   Laurent Pinchart   iommu: Add driver...
9
  #include <linux/delay.h>
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
10
  #include <linux/dma-iommu.h>
d25a2a16f   Laurent Pinchart   iommu: Add driver...
11
12
13
  #include <linux/dma-mapping.h>
  #include <linux/err.h>
  #include <linux/export.h>
8128ac3b0   Paul Gortmaker   iommu/ipmmu-vmsa:...
14
  #include <linux/init.h>
d25a2a16f   Laurent Pinchart   iommu: Add driver...
15
16
  #include <linux/interrupt.h>
  #include <linux/io.h>
b77cf11f0   Rob Herring   iommu: Allow io-p...
17
  #include <linux/io-pgtable.h>
d25a2a16f   Laurent Pinchart   iommu: Add driver...
18
  #include <linux/iommu.h>
275f5053c   Laurent Pinchart   iommu/ipmmu-vmsa:...
19
  #include <linux/of.h>
33f3ac9b5   Magnus Damm   iommu/ipmmu-vmsa:...
20
  #include <linux/of_device.h>
cda52fcd9   Magnus Damm   iommu/ipmmu-vmsa:...
21
  #include <linux/of_iommu.h>
7b2d59611   Magnus Damm   iommu/ipmmu-vmsa:...
22
  #include <linux/of_platform.h>
d25a2a16f   Laurent Pinchart   iommu: Add driver...
23
24
25
  #include <linux/platform_device.h>
  #include <linux/sizes.h>
  #include <linux/slab.h>
58b8e8bf4   Magnus Damm   iommu/ipmmu-vmsa:...
26
  #include <linux/sys_soc.h>
d25a2a16f   Laurent Pinchart   iommu: Add driver...
27

3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
28
  #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA)
d25a2a16f   Laurent Pinchart   iommu: Add driver...
29
  #include <asm/dma-iommu.h>
49c875f03   Robin Murphy   iommu/ipmmu-vmsa:...
30
31
32
33
34
  #else
  #define arm_iommu_create_mapping(...)	NULL
  #define arm_iommu_attach_device(...)	-ENODEV
  #define arm_iommu_release_mapping(...)	do {} while (0)
  #define arm_iommu_detach_device(...)	do {} while (0)
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
35
  #endif
d25a2a16f   Laurent Pinchart   iommu: Add driver...
36

da38e9ec9   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
37
38
39
40
  #define IPMMU_CTX_MAX		8U
  #define IPMMU_CTX_INVALID	-1
  
  #define IPMMU_UTLB_MAX		48U
dbb706922   Magnus Damm   iommu/ipmmu-vmsa:...
41

33f3ac9b5   Magnus Damm   iommu/ipmmu-vmsa:...
42
43
  struct ipmmu_features {
  	bool use_ns_alias_offset;
fd5140e29   Magnus Damm   iommu/ipmmu-vmsa:...
44
  	bool has_cache_leaf_nodes;
5fd163416   Magnus Damm   iommu/ipmmu-vmsa:...
45
  	unsigned int number_of_contexts;
b7f3f047a   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
46
  	unsigned int num_utlbs;
f5c858912   Magnus Damm   iommu/ipmmu-vmsa:...
47
  	bool setup_imbuscr;
c295f504f   Magnus Damm   iommu/ipmmu-vmsa:...
48
  	bool twobit_imttbcr_sl0;
2ae869557   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
49
  	bool reserved_context;
3623002f0   Hai Nguyen Pham   iommu/ipmmu-vmsa:...
50
  	bool cache_snoop;
3dc28d9f5   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
51
52
  	unsigned int ctx_offset_base;
  	unsigned int ctx_offset_stride;
1289f7f15   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
53
  	unsigned int utlb_offset_base;
33f3ac9b5   Magnus Damm   iommu/ipmmu-vmsa:...
54
  };
d25a2a16f   Laurent Pinchart   iommu: Add driver...
55
56
57
  struct ipmmu_vmsa_device {
  	struct device *dev;
  	void __iomem *base;
01da21e56   Magnus Damm   iommu/ipmmu-vmsa:...
58
  	struct iommu_device iommu;
fd5140e29   Magnus Damm   iommu/ipmmu-vmsa:...
59
  	struct ipmmu_vmsa_device *root;
33f3ac9b5   Magnus Damm   iommu/ipmmu-vmsa:...
60
  	const struct ipmmu_features *features;
5fd163416   Magnus Damm   iommu/ipmmu-vmsa:...
61
  	unsigned int num_ctx;
dbb706922   Magnus Damm   iommu/ipmmu-vmsa:...
62
63
64
  	spinlock_t lock;			/* Protects ctx and domains[] */
  	DECLARE_BITMAP(ctx, IPMMU_CTX_MAX);
  	struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX];
da38e9ec9   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
65
  	s8 utlb_ctx[IPMMU_UTLB_MAX];
d25a2a16f   Laurent Pinchart   iommu: Add driver...
66

b354c73ed   Robin Murphy   iommu/ipmmu-vmsa:...
67
  	struct iommu_group *group;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
68
69
70
71
72
  	struct dma_iommu_mapping *mapping;
  };
  
  struct ipmmu_vmsa_domain {
  	struct ipmmu_vmsa_device *mmu;
5914c5fdd   Joerg Roedel   iommu/ipmmu-vmsa:...
73
  	struct iommu_domain io_domain;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
74

f20ed39f5   Laurent Pinchart   iommu/ipmmu-vmsa:...
75
76
  	struct io_pgtable_cfg cfg;
  	struct io_pgtable_ops *iop;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
77
  	unsigned int context_id;
46583e8c4   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
78
  	struct mutex mutex;			/* Protects mappings */
d25a2a16f   Laurent Pinchart   iommu: Add driver...
79
  };
5914c5fdd   Joerg Roedel   iommu/ipmmu-vmsa:...
80
81
82
83
  static struct ipmmu_vmsa_domain *to_vmsa_domain(struct iommu_domain *dom)
  {
  	return container_of(dom, struct ipmmu_vmsa_domain, io_domain);
  }
e4efe4a9a   Robin Murphy   iommu/ipmmu-vmsa:...
84
  static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev)
0fbc8b04c   Magnus Damm   iommu/ipmmu-vmsa:...
85
  {
be568d6d5   Joerg Roedel   iommu/renesas: Us...
86
  	return dev_iommu_priv_get(dev);
0fbc8b04c   Magnus Damm   iommu/ipmmu-vmsa:...
87
  }
d25a2a16f   Laurent Pinchart   iommu: Add driver...
88
89
90
91
92
  #define TLB_LOOP_TIMEOUT		100	/* 100us */
  
  /* -----------------------------------------------------------------------------
   * Registers Definition
   */
275f5053c   Laurent Pinchart   iommu/ipmmu-vmsa:...
93
  #define IM_NS_ALIAS_OFFSET		0x800
df9828aaa   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
94
95
96
97
98
99
100
101
  /* MMU "context" registers */
  #define IMCTR				0x0000		/* R-Car Gen2/3 */
  #define IMCTR_INTEN			(1 << 2)	/* R-Car Gen2/3 */
  #define IMCTR_FLUSH			(1 << 1)	/* R-Car Gen2/3 */
  #define IMCTR_MMUEN			(1 << 0)	/* R-Car Gen2/3 */
  
  #define IMTTBCR				0x0008		/* R-Car Gen2/3 */
  #define IMTTBCR_EAE			(1 << 31)	/* R-Car Gen2/3 */
3623002f0   Hai Nguyen Pham   iommu/ipmmu-vmsa:...
102
  #define IMTTBCR_SH0_INNER_SHAREABLE	(3 << 12)	/* R-Car Gen2 only */
3623002f0   Hai Nguyen Pham   iommu/ipmmu-vmsa:...
103
  #define IMTTBCR_ORGN0_WB_WA		(1 << 10)	/* R-Car Gen2 only */
3623002f0   Hai Nguyen Pham   iommu/ipmmu-vmsa:...
104
  #define IMTTBCR_IRGN0_WB_WA		(1 << 8)	/* R-Car Gen2 only */
5ca54fdc9   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
105
  #define IMTTBCR_SL0_TWOBIT_LVL_1	(2 << 6)	/* R-Car Gen3 only */
df9828aaa   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
106
  #define IMTTBCR_SL0_LVL_1		(1 << 4)	/* R-Car Gen2 only */
d25a2a16f   Laurent Pinchart   iommu: Add driver...
107

df9828aaa   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
108
109
110
  #define IMBUSCR				0x000c		/* R-Car Gen2 only */
  #define IMBUSCR_DVM			(1 << 2)	/* R-Car Gen2 only */
  #define IMBUSCR_BUSSEL_MASK		(3 << 0)	/* R-Car Gen2 only */
d25a2a16f   Laurent Pinchart   iommu: Add driver...
111

df9828aaa   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
112
113
  #define IMTTLBR0			0x0010		/* R-Car Gen2/3 */
  #define IMTTUBR0			0x0014		/* R-Car Gen2/3 */
d25a2a16f   Laurent Pinchart   iommu: Add driver...
114

df9828aaa   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
115
116
117
118
119
  #define IMSTR				0x0020		/* R-Car Gen2/3 */
  #define IMSTR_MHIT			(1 << 4)	/* R-Car Gen2/3 */
  #define IMSTR_ABORT			(1 << 2)	/* R-Car Gen2/3 */
  #define IMSTR_PF			(1 << 1)	/* R-Car Gen2/3 */
  #define IMSTR_TF			(1 << 0)	/* R-Car Gen2/3 */
d25a2a16f   Laurent Pinchart   iommu: Add driver...
120

df9828aaa   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
121
  #define IMMAIR0				0x0028		/* R-Car Gen2/3 */
d25a2a16f   Laurent Pinchart   iommu: Add driver...
122

df9828aaa   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
123
124
  #define IMELAR				0x0030		/* R-Car Gen2/3, IMEAR on R-Car Gen2 */
  #define IMEUAR				0x0034		/* R-Car Gen3 only */
d25a2a16f   Laurent Pinchart   iommu: Add driver...
125

df9828aaa   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
126
  /* uTLB registers */
ddbbddd76   Magnus Damm   iommu/ipmmu-vmsa:...
127
  #define IMUCTR(n)			((n) < 32 ? IMUCTR0(n) : IMUCTR32(n))
df9828aaa   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
128
129
130
131
132
  #define IMUCTR0(n)			(0x0300 + ((n) * 16))		/* R-Car Gen2/3 */
  #define IMUCTR32(n)			(0x0600 + (((n) - 32) * 16))	/* R-Car Gen3 only */
  #define IMUCTR_TTSEL_MMU(n)		((n) << 4)	/* R-Car Gen2/3 */
  #define IMUCTR_FLUSH			(1 << 1)	/* R-Car Gen2/3 */
  #define IMUCTR_MMUEN			(1 << 0)	/* R-Car Gen2/3 */
d25a2a16f   Laurent Pinchart   iommu: Add driver...
133

ddbbddd76   Magnus Damm   iommu/ipmmu-vmsa:...
134
  #define IMUASID(n)			((n) < 32 ? IMUASID0(n) : IMUASID32(n))
df9828aaa   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
135
136
  #define IMUASID0(n)			(0x0308 + ((n) * 16))		/* R-Car Gen2/3 */
  #define IMUASID32(n)			(0x0608 + (((n) - 32) * 16))	/* R-Car Gen3 only */
d25a2a16f   Laurent Pinchart   iommu: Add driver...
137
138
  
  /* -----------------------------------------------------------------------------
fd5140e29   Magnus Damm   iommu/ipmmu-vmsa:...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
   * Root device handling
   */
  
  static struct platform_driver ipmmu_driver;
  
  static bool ipmmu_is_root(struct ipmmu_vmsa_device *mmu)
  {
  	return mmu->root == mmu;
  }
  
  static int __ipmmu_check_device(struct device *dev, void *data)
  {
  	struct ipmmu_vmsa_device *mmu = dev_get_drvdata(dev);
  	struct ipmmu_vmsa_device **rootp = data;
  
  	if (ipmmu_is_root(mmu))
  		*rootp = mmu;
  
  	return 0;
  }
  
  static struct ipmmu_vmsa_device *ipmmu_find_root(void)
  {
  	struct ipmmu_vmsa_device *root = NULL;
  
  	return driver_for_each_device(&ipmmu_driver.driver, NULL, &root,
  				      __ipmmu_check_device) == 0 ? root : NULL;
  }
  
  /* -----------------------------------------------------------------------------
d25a2a16f   Laurent Pinchart   iommu: Add driver...
169
170
171
172
173
174
175
176
177
178
179
180
181
   * Read/Write Access
   */
  
  static u32 ipmmu_read(struct ipmmu_vmsa_device *mmu, unsigned int offset)
  {
  	return ioread32(mmu->base + offset);
  }
  
  static void ipmmu_write(struct ipmmu_vmsa_device *mmu, unsigned int offset,
  			u32 data)
  {
  	iowrite32(data, mmu->base + offset);
  }
16d9454f5   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
182
183
184
  static unsigned int ipmmu_ctx_reg(struct ipmmu_vmsa_device *mmu,
  				  unsigned int context_id, unsigned int reg)
  {
3dc28d9f5   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
185
186
  	return mmu->features->ctx_offset_base +
  	       context_id * mmu->features->ctx_offset_stride + reg;
16d9454f5   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
187
188
189
190
191
192
193
194
195
196
197
198
199
  }
  
  static u32 ipmmu_ctx_read(struct ipmmu_vmsa_device *mmu,
  			  unsigned int context_id, unsigned int reg)
  {
  	return ipmmu_read(mmu, ipmmu_ctx_reg(mmu, context_id, reg));
  }
  
  static void ipmmu_ctx_write(struct ipmmu_vmsa_device *mmu,
  			    unsigned int context_id, unsigned int reg, u32 data)
  {
  	ipmmu_write(mmu, ipmmu_ctx_reg(mmu, context_id, reg), data);
  }
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
200
201
  static u32 ipmmu_ctx_read_root(struct ipmmu_vmsa_domain *domain,
  			       unsigned int reg)
d25a2a16f   Laurent Pinchart   iommu: Add driver...
202
  {
16d9454f5   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
203
  	return ipmmu_ctx_read(domain->mmu->root, domain->context_id, reg);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
204
  }
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
205
206
  static void ipmmu_ctx_write_root(struct ipmmu_vmsa_domain *domain,
  				 unsigned int reg, u32 data)
d25a2a16f   Laurent Pinchart   iommu: Add driver...
207
  {
16d9454f5   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
208
  	ipmmu_ctx_write(domain->mmu->root, domain->context_id, reg, data);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
209
  }
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
210
211
212
213
  static void ipmmu_ctx_write_all(struct ipmmu_vmsa_domain *domain,
  				unsigned int reg, u32 data)
  {
  	if (domain->mmu != domain->mmu->root)
16d9454f5   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
214
  		ipmmu_ctx_write(domain->mmu, domain->context_id, reg, data);
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
215

16d9454f5   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
216
  	ipmmu_ctx_write(domain->mmu->root, domain->context_id, reg, data);
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
217
  }
3667c9978   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
218
219
  static u32 ipmmu_utlb_reg(struct ipmmu_vmsa_device *mmu, unsigned int reg)
  {
1289f7f15   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
220
  	return mmu->features->utlb_offset_base + reg;
3667c9978   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
221
222
223
224
225
226
227
  }
  
  static void ipmmu_imuasid_write(struct ipmmu_vmsa_device *mmu,
  				unsigned int utlb, u32 data)
  {
  	ipmmu_write(mmu, ipmmu_utlb_reg(mmu, IMUASID(utlb)), data);
  }
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
228

3667c9978   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
229
230
231
232
  static void ipmmu_imuctr_write(struct ipmmu_vmsa_device *mmu,
  			       unsigned int utlb, u32 data)
  {
  	ipmmu_write(mmu, ipmmu_utlb_reg(mmu, IMUCTR(utlb)), data);
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
233
  }
d25a2a16f   Laurent Pinchart   iommu: Add driver...
234
235
236
237
238
239
240
241
  /* -----------------------------------------------------------------------------
   * TLB and microTLB Management
   */
  
  /* Wait for any pending TLB invalidations to complete */
  static void ipmmu_tlb_sync(struct ipmmu_vmsa_domain *domain)
  {
  	unsigned int count = 0;
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
242
  	while (ipmmu_ctx_read_root(domain, IMCTR) & IMCTR_FLUSH) {
d25a2a16f   Laurent Pinchart   iommu: Add driver...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
  		cpu_relax();
  		if (++count == TLB_LOOP_TIMEOUT) {
  			dev_err_ratelimited(domain->mmu->dev,
  			"TLB sync timed out -- MMU may be deadlocked
  ");
  			return;
  		}
  		udelay(1);
  	}
  }
  
  static void ipmmu_tlb_invalidate(struct ipmmu_vmsa_domain *domain)
  {
  	u32 reg;
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
257
  	reg = ipmmu_ctx_read_root(domain, IMCTR);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
258
  	reg |= IMCTR_FLUSH;
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
259
  	ipmmu_ctx_write_all(domain, IMCTR, reg);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
260
261
262
263
264
265
266
267
  
  	ipmmu_tlb_sync(domain);
  }
  
  /*
   * Enable MMU translation for the microTLB.
   */
  static void ipmmu_utlb_enable(struct ipmmu_vmsa_domain *domain,
192d20457   Laurent Pinchart   iommu/ipmmu-vmsa:...
268
  			      unsigned int utlb)
d25a2a16f   Laurent Pinchart   iommu: Add driver...
269
270
  {
  	struct ipmmu_vmsa_device *mmu = domain->mmu;
192d20457   Laurent Pinchart   iommu/ipmmu-vmsa:...
271
272
273
274
  	/*
  	 * TODO: Reference-count the microTLB as several bus masters can be
  	 * connected to the same microTLB.
  	 */
d25a2a16f   Laurent Pinchart   iommu: Add driver...
275
  	/* TODO: What should we set the ASID to ? */
3667c9978   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
276
  	ipmmu_imuasid_write(mmu, utlb, 0);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
277
  	/* TODO: Do we need to flush the microTLB ? */
3667c9978   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
278
279
  	ipmmu_imuctr_write(mmu, utlb, IMUCTR_TTSEL_MMU(domain->context_id) |
  				      IMUCTR_FLUSH | IMUCTR_MMUEN);
da38e9ec9   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
280
  	mmu->utlb_ctx[utlb] = domain->context_id;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
281
282
283
284
285
286
  }
  
  /*
   * Disable MMU translation for the microTLB.
   */
  static void ipmmu_utlb_disable(struct ipmmu_vmsa_domain *domain,
192d20457   Laurent Pinchart   iommu/ipmmu-vmsa:...
287
  			       unsigned int utlb)
d25a2a16f   Laurent Pinchart   iommu: Add driver...
288
289
  {
  	struct ipmmu_vmsa_device *mmu = domain->mmu;
3667c9978   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
290
  	ipmmu_imuctr_write(mmu, utlb, 0);
da38e9ec9   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
291
  	mmu->utlb_ctx[utlb] = IPMMU_CTX_INVALID;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
292
  }
f20ed39f5   Laurent Pinchart   iommu/ipmmu-vmsa:...
293
  static void ipmmu_tlb_flush_all(void *cookie)
d25a2a16f   Laurent Pinchart   iommu: Add driver...
294
  {
f20ed39f5   Laurent Pinchart   iommu/ipmmu-vmsa:...
295
296
297
298
  	struct ipmmu_vmsa_domain *domain = cookie;
  
  	ipmmu_tlb_invalidate(domain);
  }
05aed9412   Will Deacon   iommu/io-pgtable:...
299
300
  static void ipmmu_tlb_flush(unsigned long iova, size_t size,
  				size_t granule, void *cookie)
f20ed39f5   Laurent Pinchart   iommu/ipmmu-vmsa:...
301
  {
05aed9412   Will Deacon   iommu/io-pgtable:...
302
  	ipmmu_tlb_flush_all(cookie);
f20ed39f5   Laurent Pinchart   iommu/ipmmu-vmsa:...
303
  }
298f78895   Will Deacon   iommu/io-pgtable:...
304
  static const struct iommu_flush_ops ipmmu_flush_ops = {
f20ed39f5   Laurent Pinchart   iommu/ipmmu-vmsa:...
305
  	.tlb_flush_all = ipmmu_tlb_flush_all,
05aed9412   Will Deacon   iommu/io-pgtable:...
306
307
  	.tlb_flush_walk = ipmmu_tlb_flush,
  	.tlb_flush_leaf = ipmmu_tlb_flush,
f20ed39f5   Laurent Pinchart   iommu/ipmmu-vmsa:...
308
  };
d25a2a16f   Laurent Pinchart   iommu: Add driver...
309
310
311
  /* -----------------------------------------------------------------------------
   * Domain/Context Management
   */
dbb706922   Magnus Damm   iommu/ipmmu-vmsa:...
312
313
314
315
316
317
318
  static int ipmmu_domain_allocate_context(struct ipmmu_vmsa_device *mmu,
  					 struct ipmmu_vmsa_domain *domain)
  {
  	unsigned long flags;
  	int ret;
  
  	spin_lock_irqsave(&mmu->lock, flags);
5fd163416   Magnus Damm   iommu/ipmmu-vmsa:...
319
320
  	ret = find_first_zero_bit(mmu->ctx, mmu->num_ctx);
  	if (ret != mmu->num_ctx) {
dbb706922   Magnus Damm   iommu/ipmmu-vmsa:...
321
322
  		mmu->domains[ret] = domain;
  		set_bit(ret, mmu->ctx);
5fd163416   Magnus Damm   iommu/ipmmu-vmsa:...
323
324
  	} else
  		ret = -EBUSY;
dbb706922   Magnus Damm   iommu/ipmmu-vmsa:...
325
326
327
328
329
  
  	spin_unlock_irqrestore(&mmu->lock, flags);
  
  	return ret;
  }
a175a67d3   Oleksandr Tyshchenko   iommu/ipmmu-vmsa:...
330
331
332
333
334
335
336
337
338
339
340
341
  static void ipmmu_domain_free_context(struct ipmmu_vmsa_device *mmu,
  				      unsigned int context_id)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&mmu->lock, flags);
  
  	clear_bit(context_id, mmu->ctx);
  	mmu->domains[context_id] = NULL;
  
  	spin_unlock_irqrestore(&mmu->lock, flags);
  }
892db541c   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
342
  static void ipmmu_domain_setup_context(struct ipmmu_vmsa_domain *domain)
d25a2a16f   Laurent Pinchart   iommu: Add driver...
343
  {
f64232eee   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
344
  	u64 ttbr;
c295f504f   Magnus Damm   iommu/ipmmu-vmsa:...
345
  	u32 tmp;
a175a67d3   Oleksandr Tyshchenko   iommu/ipmmu-vmsa:...
346

d25a2a16f   Laurent Pinchart   iommu: Add driver...
347
  	/* TTBR0 */
d1e5f26f1   Robin Murphy   iommu/io-pgtable-...
348
  	ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr;
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
349
350
  	ipmmu_ctx_write_root(domain, IMTTLBR0, ttbr);
  	ipmmu_ctx_write_root(domain, IMTTUBR0, ttbr >> 32);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
351
352
353
  
  	/*
  	 * TTBCR
3623002f0   Hai Nguyen Pham   iommu/ipmmu-vmsa:...
354
355
  	 * We use long descriptors and allocate the whole 32-bit VA space to
  	 * TTBR0.
d25a2a16f   Laurent Pinchart   iommu: Add driver...
356
  	 */
c295f504f   Magnus Damm   iommu/ipmmu-vmsa:...
357
358
359
360
  	if (domain->mmu->features->twobit_imttbcr_sl0)
  		tmp = IMTTBCR_SL0_TWOBIT_LVL_1;
  	else
  		tmp = IMTTBCR_SL0_LVL_1;
3623002f0   Hai Nguyen Pham   iommu/ipmmu-vmsa:...
361
362
363
364
365
  	if (domain->mmu->features->cache_snoop)
  		tmp |= IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA |
  		       IMTTBCR_IRGN0_WB_WA;
  
  	ipmmu_ctx_write_root(domain, IMTTBCR, IMTTBCR_EAE | tmp);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
366

f20ed39f5   Laurent Pinchart   iommu/ipmmu-vmsa:...
367
  	/* MAIR0 */
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
368
  	ipmmu_ctx_write_root(domain, IMMAIR0,
205577ab6   Robin Murphy   iommu/io-pgtable-...
369
  			     domain->cfg.arm_lpae_s1_cfg.mair);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
370
371
  
  	/* IMBUSCR */
f5c858912   Magnus Damm   iommu/ipmmu-vmsa:...
372
373
374
375
  	if (domain->mmu->features->setup_imbuscr)
  		ipmmu_ctx_write_root(domain, IMBUSCR,
  				     ipmmu_ctx_read_root(domain, IMBUSCR) &
  				     ~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK));
d25a2a16f   Laurent Pinchart   iommu: Add driver...
376
377
378
379
380
  
  	/*
  	 * IMSTR
  	 * Clear all interrupt flags.
  	 */
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
381
  	ipmmu_ctx_write_root(domain, IMSTR, ipmmu_ctx_read_root(domain, IMSTR));
d25a2a16f   Laurent Pinchart   iommu: Add driver...
382
383
384
385
386
387
388
389
  
  	/*
  	 * IMCTR
  	 * Enable the MMU and interrupt generation. The long-descriptor
  	 * translation table format doesn't use TEX remapping. Don't enable AF
  	 * software management as we have no use for it. Flush the TLB as
  	 * required when modifying the context registers.
  	 */
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
390
391
  	ipmmu_ctx_write_all(domain, IMCTR,
  			    IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN);
892db541c   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
  }
  
  static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
  {
  	int ret;
  
  	/*
  	 * Allocate the page table operations.
  	 *
  	 * VMSA states in section B3.6.3 "Control of Secure or Non-secure memory
  	 * access, Long-descriptor format" that the NStable bit being set in a
  	 * table descriptor will result in the NStable and NS bits of all child
  	 * entries being ignored and considered as being set. The IPMMU seems
  	 * not to comply with this, as it generates a secure access page fault
  	 * if any of the NStable and NS bits isn't set when running in
  	 * non-secure mode.
  	 */
  	domain->cfg.quirks = IO_PGTABLE_QUIRK_ARM_NS;
  	domain->cfg.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K;
  	domain->cfg.ias = 32;
  	domain->cfg.oas = 40;
298f78895   Will Deacon   iommu/io-pgtable:...
413
  	domain->cfg.tlb = &ipmmu_flush_ops;
892db541c   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
414
415
416
417
418
419
  	domain->io_domain.geometry.aperture_end = DMA_BIT_MASK(32);
  	domain->io_domain.geometry.force_aperture = true;
  	/*
  	 * TODO: Add support for coherent walk through CCI with DVM and remove
  	 * cache handling. For now, delegate it to the io-pgtable code.
  	 */
3430abd6f   Joerg Roedel   Merge branch 'arm...
420
  	domain->cfg.coherent_walk = false;
892db541c   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  	domain->cfg.iommu_dev = domain->mmu->root->dev;
  
  	/*
  	 * Find an unused context.
  	 */
  	ret = ipmmu_domain_allocate_context(domain->mmu->root, domain);
  	if (ret < 0)
  		return ret;
  
  	domain->context_id = ret;
  
  	domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &domain->cfg,
  					   domain);
  	if (!domain->iop) {
  		ipmmu_domain_free_context(domain->mmu->root,
  					  domain->context_id);
  		return -EINVAL;
  	}
d25a2a16f   Laurent Pinchart   iommu: Add driver...
439

892db541c   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
440
  	ipmmu_domain_setup_context(domain);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
441
442
443
444
445
  	return 0;
  }
  
  static void ipmmu_domain_destroy_context(struct ipmmu_vmsa_domain *domain)
  {
e5b78f2e3   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
446
447
  	if (!domain->mmu)
  		return;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
448
449
450
451
452
453
  	/*
  	 * Disable the context. Flush the TLB as required when modifying the
  	 * context registers.
  	 *
  	 * TODO: Is TLB flush really needed ?
  	 */
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
454
  	ipmmu_ctx_write_all(domain, IMCTR, IMCTR_FLUSH);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
455
  	ipmmu_tlb_sync(domain);
fd5140e29   Magnus Damm   iommu/ipmmu-vmsa:...
456
  	ipmmu_domain_free_context(domain->mmu->root, domain->context_id);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
457
458
459
460
461
462
463
464
465
466
  }
  
  /* -----------------------------------------------------------------------------
   * Fault Handling
   */
  
  static irqreturn_t ipmmu_domain_irq(struct ipmmu_vmsa_domain *domain)
  {
  	const u32 err_mask = IMSTR_MHIT | IMSTR_ABORT | IMSTR_PF | IMSTR_TF;
  	struct ipmmu_vmsa_device *mmu = domain->mmu;
82576aa8a   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
467
  	unsigned long iova;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
468
  	u32 status;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
469

d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
470
  	status = ipmmu_ctx_read_root(domain, IMSTR);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
471
472
  	if (!(status & err_mask))
  		return IRQ_NONE;
82576aa8a   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
473
474
475
  	iova = ipmmu_ctx_read_root(domain, IMELAR);
  	if (IS_ENABLED(CONFIG_64BIT))
  		iova |= (u64)ipmmu_ctx_read_root(domain, IMEUAR) << 32;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
476
477
478
479
480
481
482
  
  	/*
  	 * Clear the error status flags. Unlike traditional interrupt flag
  	 * registers that must be cleared by writing 1, this status register
  	 * seems to require 0. The error address register must be read before,
  	 * otherwise its value will be 0.
  	 */
d574893ae   Magnus Damm   iommu/ipmmu-vmsa:...
483
  	ipmmu_ctx_write_root(domain, IMSTR, 0);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
484
485
486
  
  	/* Log fatal errors. */
  	if (status & IMSTR_MHIT)
82576aa8a   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
487
488
  		dev_err_ratelimited(mmu->dev, "Multiple TLB hits @0x%lx
  ",
d25a2a16f   Laurent Pinchart   iommu: Add driver...
489
490
  				    iova);
  	if (status & IMSTR_ABORT)
82576aa8a   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
491
492
  		dev_err_ratelimited(mmu->dev, "Page Table Walk Abort @0x%lx
  ",
d25a2a16f   Laurent Pinchart   iommu: Add driver...
493
494
495
496
497
498
499
500
501
502
503
  				    iova);
  
  	if (!(status & (IMSTR_PF | IMSTR_TF)))
  		return IRQ_NONE;
  
  	/*
  	 * Try to handle page faults and translation faults.
  	 *
  	 * TODO: We need to look up the faulty device based on the I/O VA. Use
  	 * the IOMMU device for now.
  	 */
5914c5fdd   Joerg Roedel   iommu/ipmmu-vmsa:...
504
  	if (!report_iommu_fault(&domain->io_domain, mmu->dev, iova, 0))
d25a2a16f   Laurent Pinchart   iommu: Add driver...
505
506
507
  		return IRQ_HANDLED;
  
  	dev_err_ratelimited(mmu->dev,
82576aa8a   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
508
509
  			    "Unhandled fault: status 0x%08x iova 0x%lx
  ",
d25a2a16f   Laurent Pinchart   iommu: Add driver...
510
511
512
513
514
515
516
517
  			    status, iova);
  
  	return IRQ_HANDLED;
  }
  
  static irqreturn_t ipmmu_irq(int irq, void *dev)
  {
  	struct ipmmu_vmsa_device *mmu = dev;
dbb706922   Magnus Damm   iommu/ipmmu-vmsa:...
518
519
520
  	irqreturn_t status = IRQ_NONE;
  	unsigned int i;
  	unsigned long flags;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
521

dbb706922   Magnus Damm   iommu/ipmmu-vmsa:...
522
523
524
525
526
  	spin_lock_irqsave(&mmu->lock, flags);
  
  	/*
  	 * Check interrupts for all active contexts.
  	 */
5fd163416   Magnus Damm   iommu/ipmmu-vmsa:...
527
  	for (i = 0; i < mmu->num_ctx; i++) {
dbb706922   Magnus Damm   iommu/ipmmu-vmsa:...
528
529
530
531
532
  		if (!mmu->domains[i])
  			continue;
  		if (ipmmu_domain_irq(mmu->domains[i]) == IRQ_HANDLED)
  			status = IRQ_HANDLED;
  	}
d25a2a16f   Laurent Pinchart   iommu: Add driver...
533

dbb706922   Magnus Damm   iommu/ipmmu-vmsa:...
534
  	spin_unlock_irqrestore(&mmu->lock, flags);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
535

dbb706922   Magnus Damm   iommu/ipmmu-vmsa:...
536
  	return status;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
537
538
539
  }
  
  /* -----------------------------------------------------------------------------
d25a2a16f   Laurent Pinchart   iommu: Add driver...
540
541
   * IOMMU Operations
   */
8e73bf659   Magnus Damm   iommu/ipmmu-vmsa:...
542
  static struct iommu_domain *__ipmmu_domain_alloc(unsigned type)
d25a2a16f   Laurent Pinchart   iommu: Add driver...
543
544
545
546
547
  {
  	struct ipmmu_vmsa_domain *domain;
  
  	domain = kzalloc(sizeof(*domain), GFP_KERNEL);
  	if (!domain)
5914c5fdd   Joerg Roedel   iommu/ipmmu-vmsa:...
548
  		return NULL;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
549

46583e8c4   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
550
  	mutex_init(&domain->mutex);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
551

5914c5fdd   Joerg Roedel   iommu/ipmmu-vmsa:...
552
  	return &domain->io_domain;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
553
  }
1c7e7c027   Robin Murphy   iommu/ipmmu-vmsa:...
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
  static struct iommu_domain *ipmmu_domain_alloc(unsigned type)
  {
  	struct iommu_domain *io_domain = NULL;
  
  	switch (type) {
  	case IOMMU_DOMAIN_UNMANAGED:
  		io_domain = __ipmmu_domain_alloc(type);
  		break;
  
  	case IOMMU_DOMAIN_DMA:
  		io_domain = __ipmmu_domain_alloc(type);
  		if (io_domain && iommu_get_dma_cookie(io_domain)) {
  			kfree(io_domain);
  			io_domain = NULL;
  		}
  		break;
  	}
  
  	return io_domain;
  }
5914c5fdd   Joerg Roedel   iommu/ipmmu-vmsa:...
574
  static void ipmmu_domain_free(struct iommu_domain *io_domain)
d25a2a16f   Laurent Pinchart   iommu: Add driver...
575
  {
5914c5fdd   Joerg Roedel   iommu/ipmmu-vmsa:...
576
  	struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
577
578
579
580
581
  
  	/*
  	 * Free the domain resources. We assume that all devices have already
  	 * been detached.
  	 */
1c7e7c027   Robin Murphy   iommu/ipmmu-vmsa:...
582
  	iommu_put_dma_cookie(io_domain);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
583
  	ipmmu_domain_destroy_context(domain);
f20ed39f5   Laurent Pinchart   iommu/ipmmu-vmsa:...
584
  	free_io_pgtable_ops(domain->iop);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
585
586
587
588
589
590
  	kfree(domain);
  }
  
  static int ipmmu_attach_device(struct iommu_domain *io_domain,
  			       struct device *dev)
  {
df9036558   Joerg Roedel   iommu/ipmmu-vmsa:...
591
  	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
e4efe4a9a   Robin Murphy   iommu/ipmmu-vmsa:...
592
  	struct ipmmu_vmsa_device *mmu = to_ipmmu(dev);
5914c5fdd   Joerg Roedel   iommu/ipmmu-vmsa:...
593
  	struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
a166d31ee   Laurent Pinchart   iommu/ipmmu-vmsa:...
594
  	unsigned int i;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
595
  	int ret = 0;
e4efe4a9a   Robin Murphy   iommu/ipmmu-vmsa:...
596
  	if (!mmu) {
d25a2a16f   Laurent Pinchart   iommu: Add driver...
597
598
599
600
  		dev_err(dev, "Cannot attach to IPMMU
  ");
  		return -ENXIO;
  	}
46583e8c4   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
601
  	mutex_lock(&domain->mutex);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
602
603
604
605
606
  
  	if (!domain->mmu) {
  		/* The domain hasn't been used yet, initialize it. */
  		domain->mmu = mmu;
  		ret = ipmmu_domain_init_context(domain);
5fd163416   Magnus Damm   iommu/ipmmu-vmsa:...
607
608
609
610
611
612
613
614
615
  		if (ret < 0) {
  			dev_err(dev, "Unable to initialize IPMMU context
  ");
  			domain->mmu = NULL;
  		} else {
  			dev_info(dev, "Using IPMMU context %u
  ",
  				 domain->context_id);
  		}
d25a2a16f   Laurent Pinchart   iommu: Add driver...
616
617
618
619
620
621
622
623
624
  	} else if (domain->mmu != mmu) {
  		/*
  		 * Something is wrong, we can't attach two devices using
  		 * different IOMMUs to the same domain.
  		 */
  		dev_err(dev, "Can't attach IPMMU %s to domain on IPMMU %s
  ",
  			dev_name(mmu->dev), dev_name(domain->mmu->dev));
  		ret = -EINVAL;
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
625
626
627
  	} else
  		dev_info(dev, "Reusing IPMMU context %u
  ", domain->context_id);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
628

46583e8c4   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
629
  	mutex_unlock(&domain->mutex);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
630
631
632
  
  	if (ret < 0)
  		return ret;
7b2d59611   Magnus Damm   iommu/ipmmu-vmsa:...
633
634
  	for (i = 0; i < fwspec->num_ids; ++i)
  		ipmmu_utlb_enable(domain, fwspec->ids[i]);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
635
636
637
638
639
640
641
  
  	return 0;
  }
  
  static void ipmmu_detach_device(struct iommu_domain *io_domain,
  				struct device *dev)
  {
df9036558   Joerg Roedel   iommu/ipmmu-vmsa:...
642
  	struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
5914c5fdd   Joerg Roedel   iommu/ipmmu-vmsa:...
643
  	struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
a166d31ee   Laurent Pinchart   iommu/ipmmu-vmsa:...
644
  	unsigned int i;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
645

7b2d59611   Magnus Damm   iommu/ipmmu-vmsa:...
646
647
  	for (i = 0; i < fwspec->num_ids; ++i)
  		ipmmu_utlb_disable(domain, fwspec->ids[i]);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
648
649
650
651
652
653
654
  
  	/*
  	 * TODO: Optimize by disabling the context when no device is attached.
  	 */
  }
  
  static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova,
781ca2de8   Tom Murphy   iommu: Add gfp pa...
655
  		     phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
d25a2a16f   Laurent Pinchart   iommu: Add driver...
656
  {
5914c5fdd   Joerg Roedel   iommu/ipmmu-vmsa:...
657
  	struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
658
659
660
  
  	if (!domain)
  		return -ENODEV;
f34ce7a70   Baolin Wang   iommu: Add gfp pa...
661
  	return domain->iop->map(domain->iop, iova, paddr, size, prot, gfp);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
662
663
664
  }
  
  static size_t ipmmu_unmap(struct iommu_domain *io_domain, unsigned long iova,
56f8af5e9   Will Deacon   iommu: Pass struc...
665
  			  size_t size, struct iommu_iotlb_gather *gather)
d25a2a16f   Laurent Pinchart   iommu: Add driver...
666
  {
5914c5fdd   Joerg Roedel   iommu/ipmmu-vmsa:...
667
  	struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
668

a2d3a382d   Will Deacon   iommu/io-pgtable:...
669
  	return domain->iop->unmap(domain->iop, iova, size, gather);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
670
  }
56f8af5e9   Will Deacon   iommu: Pass struc...
671
  static void ipmmu_flush_iotlb_all(struct iommu_domain *io_domain)
32b124492   Robin Murphy   iommu/io-pgtable-...
672
673
674
675
676
677
  {
  	struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
  
  	if (domain->mmu)
  		ipmmu_tlb_flush_all(domain);
  }
56f8af5e9   Will Deacon   iommu: Pass struc...
678
679
680
681
682
  static void ipmmu_iotlb_sync(struct iommu_domain *io_domain,
  			     struct iommu_iotlb_gather *gather)
  {
  	ipmmu_flush_iotlb_all(io_domain);
  }
d25a2a16f   Laurent Pinchart   iommu: Add driver...
683
684
685
  static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain,
  				      dma_addr_t iova)
  {
5914c5fdd   Joerg Roedel   iommu/ipmmu-vmsa:...
686
  	struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
687
688
  
  	/* TODO: Is locking needed ? */
f20ed39f5   Laurent Pinchart   iommu/ipmmu-vmsa:...
689
  	return domain->iop->iova_to_phys(domain->iop, iova);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
690
  }
7b2d59611   Magnus Damm   iommu/ipmmu-vmsa:...
691
692
  static int ipmmu_init_platform_device(struct device *dev,
  				      struct of_phandle_args *args)
d25a2a16f   Laurent Pinchart   iommu: Add driver...
693
  {
7b2d59611   Magnus Damm   iommu/ipmmu-vmsa:...
694
  	struct platform_device *ipmmu_pdev;
bb590c901   Laurent Pinchart   iommu/ipmmu-vmsa:...
695

7b2d59611   Magnus Damm   iommu/ipmmu-vmsa:...
696
697
  	ipmmu_pdev = of_find_device_by_node(args->np);
  	if (!ipmmu_pdev)
bb590c901   Laurent Pinchart   iommu/ipmmu-vmsa:...
698
  		return -ENODEV;
be568d6d5   Joerg Roedel   iommu/renesas: Us...
699
  	dev_iommu_priv_set(dev, platform_get_drvdata(ipmmu_pdev));
383fef5f4   Magnus Damm   iommu/ipmmu-vmsa:...
700

383fef5f4   Magnus Damm   iommu/ipmmu-vmsa:...
701
  	return 0;
58b8e8bf4   Magnus Damm   iommu/ipmmu-vmsa:...
702
  }
0b8ac1409   Magnus Damm   iommu/ipmmu-vmsa:...
703
  static const struct soc_device_attribute soc_rcar_gen3[] = {
60fb0083c   Fabrizio Castro   iommu/ipmmu-vmsa:...
704
  	{ .soc_id = "r8a774a1", },
757f26a3a   Biju Das   iommu/ipmmu-vmsa:...
705
  	{ .soc_id = "r8a774b1", },
b6d39cd82   Fabrizio Castro   iommu/ipmmu-vmsa:...
706
  	{ .soc_id = "r8a774c0", },
4b2aa7a6f   Marian-Cristian Rotariu   iommu/ipmmu-vmsa:...
707
  	{ .soc_id = "r8a774e1", },
58b8e8bf4   Magnus Damm   iommu/ipmmu-vmsa:...
708
  	{ .soc_id = "r8a7795", },
f3e048b78   Lad Prabhakar   iommu/ipmmu-vmsa:...
709
  	{ .soc_id = "r8a77961", },
0b8ac1409   Magnus Damm   iommu/ipmmu-vmsa:...
710
  	{ .soc_id = "r8a7796", },
98dbffd39   Jacopo Mondi   iommu/ipmmu-vmsa:...
711
  	{ .soc_id = "r8a77965", },
3701c123e   Simon Horman   iommu/ipmmu-vmsa:...
712
  	{ .soc_id = "r8a77970", },
b0c329121   Hai Nguyen Pham   iommu/ipmmu-vmsa:...
713
  	{ .soc_id = "r8a77990", },
3701c123e   Simon Horman   iommu/ipmmu-vmsa:...
714
  	{ .soc_id = "r8a77995", },
58b8e8bf4   Magnus Damm   iommu/ipmmu-vmsa:...
715
716
  	{ /* sentinel */ }
  };
b7ee92c6f   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
717
  static const struct soc_device_attribute soc_rcar_gen3_whitelist[] = {
757f26a3a   Biju Das   iommu/ipmmu-vmsa:...
718
  	{ .soc_id = "r8a774b1", },
b6d39cd82   Fabrizio Castro   iommu/ipmmu-vmsa:...
719
  	{ .soc_id = "r8a774c0", },
4b2aa7a6f   Marian-Cristian Rotariu   iommu/ipmmu-vmsa:...
720
  	{ .soc_id = "r8a774e1", },
b7ee92c6f   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
721
  	{ .soc_id = "r8a7795", .revision = "ES3.*" },
17fe16181   Yoshihiro Shimoda   iommu/renesas: Ad...
722
  	{ .soc_id = "r8a77961", },
b7ee92c6f   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
723
724
  	{ .soc_id = "r8a77965", },
  	{ .soc_id = "r8a77990", },
3701c123e   Simon Horman   iommu/ipmmu-vmsa:...
725
  	{ .soc_id = "r8a77995", },
58b8e8bf4   Magnus Damm   iommu/ipmmu-vmsa:...
726
727
  	{ /* sentinel */ }
  };
807596491   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
728
729
  static const char * const rcar_gen3_slave_whitelist[] = {
  };
b7ee92c6f   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
730
731
  static bool ipmmu_slave_whitelist(struct device *dev)
  {
807596491   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
732
  	unsigned int i;
b7ee92c6f   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
733
734
735
736
737
738
739
740
741
742
  	/*
  	 * For R-Car Gen3 use a white list to opt-in slave devices.
  	 * For Other SoCs, this returns true anyway.
  	 */
  	if (!soc_device_match(soc_rcar_gen3))
  		return true;
  
  	/* Check whether this R-Car Gen3 can use the IPMMU correctly or not */
  	if (!soc_device_match(soc_rcar_gen3_whitelist))
  		return false;
807596491   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
743
744
745
746
747
748
749
  	/* Check whether this slave device can work with the IPMMU */
  	for (i = 0; i < ARRAY_SIZE(rcar_gen3_slave_whitelist); i++) {
  		if (!strcmp(dev_name(dev), rcar_gen3_slave_whitelist[i]))
  			return true;
  	}
  
  	/* Otherwise, do not allow use of IPMMU */
b7ee92c6f   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
750
751
  	return false;
  }
49558da03   Magnus Damm   iommu/ipmmu-vmsa:...
752
753
754
  static int ipmmu_of_xlate(struct device *dev,
  			  struct of_phandle_args *spec)
  {
b7ee92c6f   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
755
  	if (!ipmmu_slave_whitelist(dev))
58b8e8bf4   Magnus Damm   iommu/ipmmu-vmsa:...
756
  		return -ENODEV;
7b2d59611   Magnus Damm   iommu/ipmmu-vmsa:...
757
  	iommu_fwspec_add_ids(dev, spec->args, 1);
49558da03   Magnus Damm   iommu/ipmmu-vmsa:...
758
  	/* Initialize once - xlate() will call multiple times */
e4efe4a9a   Robin Murphy   iommu/ipmmu-vmsa:...
759
  	if (to_ipmmu(dev))
49558da03   Magnus Damm   iommu/ipmmu-vmsa:...
760
  		return 0;
7b2d59611   Magnus Damm   iommu/ipmmu-vmsa:...
761
  	return ipmmu_init_platform_device(dev, spec);
49558da03   Magnus Damm   iommu/ipmmu-vmsa:...
762
  }
49c875f03   Robin Murphy   iommu/ipmmu-vmsa:...
763
  static int ipmmu_init_arm_mapping(struct device *dev)
383fef5f4   Magnus Damm   iommu/ipmmu-vmsa:...
764
  {
e4efe4a9a   Robin Murphy   iommu/ipmmu-vmsa:...
765
  	struct ipmmu_vmsa_device *mmu = to_ipmmu(dev);
383fef5f4   Magnus Damm   iommu/ipmmu-vmsa:...
766
  	int ret;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
767
768
769
770
771
772
773
774
775
776
777
778
779
  	/*
  	 * Create the ARM mapping, used by the ARM DMA mapping core to allocate
  	 * VAs. This will allocate a corresponding IOMMU domain.
  	 *
  	 * TODO:
  	 * - Create one mapping per context (TLB).
  	 * - Make the mapping size configurable ? We currently use a 2GB mapping
  	 *   at a 1GB offset to ensure that NULL VAs will fault.
  	 */
  	if (!mmu->mapping) {
  		struct dma_iommu_mapping *mapping;
  
  		mapping = arm_iommu_create_mapping(&platform_bus_type,
720b0cef7   Joerg Roedel   arm/ipmmu-vmsa: F...
780
  						   SZ_1G, SZ_2G);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
781
782
783
  		if (IS_ERR(mapping)) {
  			dev_err(mmu->dev, "failed to create ARM IOMMU mapping
  ");
b8f80bffd   Laurent Pinchart   iommu/ipmmu-vmsa:...
784
785
  			ret = PTR_ERR(mapping);
  			goto error;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
  		}
  
  		mmu->mapping = mapping;
  	}
  
  	/* Attach the ARM VA mapping to the device. */
  	ret = arm_iommu_attach_device(dev, mmu->mapping);
  	if (ret < 0) {
  		dev_err(dev, "Failed to attach device to VA mapping
  ");
  		goto error;
  	}
  
  	return 0;
  
  error:
49c875f03   Robin Murphy   iommu/ipmmu-vmsa:...
802
  	if (mmu->mapping)
383fef5f4   Magnus Damm   iommu/ipmmu-vmsa:...
803
  		arm_iommu_release_mapping(mmu->mapping);
a166d31ee   Laurent Pinchart   iommu/ipmmu-vmsa:...
804

d25a2a16f   Laurent Pinchart   iommu: Add driver...
805
806
  	return ret;
  }
6580c8a78   Joerg Roedel   iommu/renesas: Co...
807
  static struct iommu_device *ipmmu_probe_device(struct device *dev)
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
808
  {
80eaa9f55   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
809
  	struct ipmmu_vmsa_device *mmu = to_ipmmu(dev);
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
810

0fbc8b04c   Magnus Damm   iommu/ipmmu-vmsa:...
811
812
  	/*
  	 * Only let through devices that have been verified in xlate()
0fbc8b04c   Magnus Damm   iommu/ipmmu-vmsa:...
813
  	 */
80eaa9f55   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
814
  	if (!mmu)
6580c8a78   Joerg Roedel   iommu/renesas: Co...
815
  		return ERR_PTR(-ENODEV);
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
816

6580c8a78   Joerg Roedel   iommu/renesas: Co...
817
818
819
820
821
822
823
824
  	return &mmu->iommu;
  }
  
  static void ipmmu_probe_finalize(struct device *dev)
  {
  	int ret = 0;
  
  	if (IS_ENABLED(CONFIG_ARM) && !IS_ENABLED(CONFIG_IOMMU_DMA))
80eaa9f55   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
825
  		ret = ipmmu_init_arm_mapping(dev);
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
826

6580c8a78   Joerg Roedel   iommu/renesas: Co...
827
828
829
  	if (ret)
  		dev_err(dev, "Can't create IOMMU mapping - DMA-OPS will not work
  ");
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
830
  }
6580c8a78   Joerg Roedel   iommu/renesas: Co...
831
  static void ipmmu_release_device(struct device *dev)
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
832
  {
49c875f03   Robin Murphy   iommu/ipmmu-vmsa:...
833
  	arm_iommu_detach_device(dev);
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
834
  }
b354c73ed   Robin Murphy   iommu/ipmmu-vmsa:...
835
  static struct iommu_group *ipmmu_find_group(struct device *dev)
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
836
  {
e4efe4a9a   Robin Murphy   iommu/ipmmu-vmsa:...
837
  	struct ipmmu_vmsa_device *mmu = to_ipmmu(dev);
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
838
  	struct iommu_group *group;
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
839

e4efe4a9a   Robin Murphy   iommu/ipmmu-vmsa:...
840
841
  	if (mmu->group)
  		return iommu_group_ref_get(mmu->group);
b354c73ed   Robin Murphy   iommu/ipmmu-vmsa:...
842
843
844
  
  	group = iommu_group_alloc();
  	if (!IS_ERR(group))
e4efe4a9a   Robin Murphy   iommu/ipmmu-vmsa:...
845
  		mmu->group = group;
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
846
847
848
  
  	return group;
  }
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
849
  static const struct iommu_ops ipmmu_ops = {
1c7e7c027   Robin Murphy   iommu/ipmmu-vmsa:...
850
851
  	.domain_alloc = ipmmu_domain_alloc,
  	.domain_free = ipmmu_domain_free,
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
852
853
854
855
  	.attach_dev = ipmmu_attach_device,
  	.detach_dev = ipmmu_detach_device,
  	.map = ipmmu_map,
  	.unmap = ipmmu_unmap,
56f8af5e9   Will Deacon   iommu: Pass struc...
856
  	.flush_iotlb_all = ipmmu_flush_iotlb_all,
32b124492   Robin Murphy   iommu/io-pgtable-...
857
  	.iotlb_sync = ipmmu_iotlb_sync,
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
858
  	.iova_to_phys = ipmmu_iova_to_phys,
6580c8a78   Joerg Roedel   iommu/renesas: Co...
859
860
861
  	.probe_device = ipmmu_probe_device,
  	.release_device = ipmmu_release_device,
  	.probe_finalize = ipmmu_probe_finalize,
2ba20b5a5   Arnd Bergmann   iommu/renesas: Fi...
862
863
  	.device_group = IS_ENABLED(CONFIG_ARM) && !IS_ENABLED(CONFIG_IOMMU_DMA)
  			? generic_device_group : ipmmu_find_group,
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
864
  	.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K,
49558da03   Magnus Damm   iommu/ipmmu-vmsa:...
865
  	.of_xlate = ipmmu_of_xlate,
3ae472920   Magnus Damm   iommu/ipmmu-vmsa:...
866
  };
d25a2a16f   Laurent Pinchart   iommu: Add driver...
867
868
869
870
871
872
873
874
875
  /* -----------------------------------------------------------------------------
   * Probe/remove and init
   */
  
  static void ipmmu_device_reset(struct ipmmu_vmsa_device *mmu)
  {
  	unsigned int i;
  
  	/* Disable all contexts. */
5fd163416   Magnus Damm   iommu/ipmmu-vmsa:...
876
  	for (i = 0; i < mmu->num_ctx; ++i)
16d9454f5   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
877
  		ipmmu_ctx_write(mmu, i, IMCTR, 0);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
878
  }
33f3ac9b5   Magnus Damm   iommu/ipmmu-vmsa:...
879
880
  static const struct ipmmu_features ipmmu_features_default = {
  	.use_ns_alias_offset = true,
fd5140e29   Magnus Damm   iommu/ipmmu-vmsa:...
881
  	.has_cache_leaf_nodes = false,
5fd163416   Magnus Damm   iommu/ipmmu-vmsa:...
882
  	.number_of_contexts = 1, /* software only tested with one context */
b7f3f047a   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
883
  	.num_utlbs = 32,
f5c858912   Magnus Damm   iommu/ipmmu-vmsa:...
884
  	.setup_imbuscr = true,
c295f504f   Magnus Damm   iommu/ipmmu-vmsa:...
885
  	.twobit_imttbcr_sl0 = false,
2ae869557   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
886
  	.reserved_context = false,
3623002f0   Hai Nguyen Pham   iommu/ipmmu-vmsa:...
887
  	.cache_snoop = true,
3dc28d9f5   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
888
889
  	.ctx_offset_base = 0,
  	.ctx_offset_stride = 0x40,
1289f7f15   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
890
  	.utlb_offset_base = 0,
33f3ac9b5   Magnus Damm   iommu/ipmmu-vmsa:...
891
  };
0b8ac1409   Magnus Damm   iommu/ipmmu-vmsa:...
892
  static const struct ipmmu_features ipmmu_features_rcar_gen3 = {
58b8e8bf4   Magnus Damm   iommu/ipmmu-vmsa:...
893
894
895
  	.use_ns_alias_offset = false,
  	.has_cache_leaf_nodes = true,
  	.number_of_contexts = 8,
b7f3f047a   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
896
  	.num_utlbs = 48,
58b8e8bf4   Magnus Damm   iommu/ipmmu-vmsa:...
897
898
  	.setup_imbuscr = false,
  	.twobit_imttbcr_sl0 = true,
2ae869557   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
899
  	.reserved_context = true,
3623002f0   Hai Nguyen Pham   iommu/ipmmu-vmsa:...
900
  	.cache_snoop = false,
3dc28d9f5   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
901
902
  	.ctx_offset_base = 0,
  	.ctx_offset_stride = 0x40,
1289f7f15   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
903
  	.utlb_offset_base = 0,
58b8e8bf4   Magnus Damm   iommu/ipmmu-vmsa:...
904
  };
33f3ac9b5   Magnus Damm   iommu/ipmmu-vmsa:...
905
906
907
908
909
  static const struct of_device_id ipmmu_of_ids[] = {
  	{
  		.compatible = "renesas,ipmmu-vmsa",
  		.data = &ipmmu_features_default,
  	}, {
60fb0083c   Fabrizio Castro   iommu/ipmmu-vmsa:...
910
911
912
  		.compatible = "renesas,ipmmu-r8a774a1",
  		.data = &ipmmu_features_rcar_gen3,
  	}, {
757f26a3a   Biju Das   iommu/ipmmu-vmsa:...
913
914
915
  		.compatible = "renesas,ipmmu-r8a774b1",
  		.data = &ipmmu_features_rcar_gen3,
  	}, {
b6d39cd82   Fabrizio Castro   iommu/ipmmu-vmsa:...
916
917
918
  		.compatible = "renesas,ipmmu-r8a774c0",
  		.data = &ipmmu_features_rcar_gen3,
  	}, {
4b2aa7a6f   Marian-Cristian Rotariu   iommu/ipmmu-vmsa:...
919
920
921
  		.compatible = "renesas,ipmmu-r8a774e1",
  		.data = &ipmmu_features_rcar_gen3,
  	}, {
58b8e8bf4   Magnus Damm   iommu/ipmmu-vmsa:...
922
  		.compatible = "renesas,ipmmu-r8a7795",
0b8ac1409   Magnus Damm   iommu/ipmmu-vmsa:...
923
924
925
926
  		.data = &ipmmu_features_rcar_gen3,
  	}, {
  		.compatible = "renesas,ipmmu-r8a7796",
  		.data = &ipmmu_features_rcar_gen3,
58b8e8bf4   Magnus Damm   iommu/ipmmu-vmsa:...
927
  	}, {
17fe16181   Yoshihiro Shimoda   iommu/renesas: Ad...
928
929
930
  		.compatible = "renesas,ipmmu-r8a77961",
  		.data = &ipmmu_features_rcar_gen3,
  	}, {
98dbffd39   Jacopo Mondi   iommu/ipmmu-vmsa:...
931
932
933
  		.compatible = "renesas,ipmmu-r8a77965",
  		.data = &ipmmu_features_rcar_gen3,
  	}, {
3701c123e   Simon Horman   iommu/ipmmu-vmsa:...
934
935
936
  		.compatible = "renesas,ipmmu-r8a77970",
  		.data = &ipmmu_features_rcar_gen3,
  	}, {
b0c329121   Hai Nguyen Pham   iommu/ipmmu-vmsa:...
937
938
939
  		.compatible = "renesas,ipmmu-r8a77990",
  		.data = &ipmmu_features_rcar_gen3,
  	}, {
3701c123e   Simon Horman   iommu/ipmmu-vmsa:...
940
941
  		.compatible = "renesas,ipmmu-r8a77995",
  		.data = &ipmmu_features_rcar_gen3,
58b8e8bf4   Magnus Damm   iommu/ipmmu-vmsa:...
942
  	}, {
33f3ac9b5   Magnus Damm   iommu/ipmmu-vmsa:...
943
944
945
  		/* Terminator */
  	},
  };
d25a2a16f   Laurent Pinchart   iommu: Add driver...
946
947
948
949
950
951
  static int ipmmu_probe(struct platform_device *pdev)
  {
  	struct ipmmu_vmsa_device *mmu;
  	struct resource *res;
  	int irq;
  	int ret;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
952
953
954
955
956
957
958
959
  	mmu = devm_kzalloc(&pdev->dev, sizeof(*mmu), GFP_KERNEL);
  	if (!mmu) {
  		dev_err(&pdev->dev, "cannot allocate device data
  ");
  		return -ENOMEM;
  	}
  
  	mmu->dev = &pdev->dev;
dbb706922   Magnus Damm   iommu/ipmmu-vmsa:...
960
961
  	spin_lock_init(&mmu->lock);
  	bitmap_zero(mmu->ctx, IPMMU_CTX_MAX);
33f3ac9b5   Magnus Damm   iommu/ipmmu-vmsa:...
962
  	mmu->features = of_device_get_match_data(&pdev->dev);
da38e9ec9   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
963
  	memset(mmu->utlb_ctx, IPMMU_CTX_INVALID, mmu->features->num_utlbs);
1c894225b   Magnus Damm   iommu/ipmmu-vmsa:...
964
  	dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
d25a2a16f   Laurent Pinchart   iommu: Add driver...
965
966
967
968
969
970
  
  	/* Map I/O memory and request IRQ. */
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	mmu->base = devm_ioremap_resource(&pdev->dev, res);
  	if (IS_ERR(mmu->base))
  		return PTR_ERR(mmu->base);
275f5053c   Laurent Pinchart   iommu/ipmmu-vmsa:...
971
972
973
974
975
976
977
978
979
980
981
982
  	/*
  	 * The IPMMU has two register banks, for secure and non-secure modes.
  	 * The bank mapped at the beginning of the IPMMU address space
  	 * corresponds to the running mode of the CPU. When running in secure
  	 * mode the non-secure register bank is also available at an offset.
  	 *
  	 * Secure mode operation isn't clearly documented and is thus currently
  	 * not implemented in the driver. Furthermore, preliminary tests of
  	 * non-secure operation with the main register bank were not successful.
  	 * Offset the registers base unconditionally to point to the non-secure
  	 * alias space for now.
  	 */
33f3ac9b5   Magnus Damm   iommu/ipmmu-vmsa:...
983
984
  	if (mmu->features->use_ns_alias_offset)
  		mmu->base += IM_NS_ALIAS_OFFSET;
275f5053c   Laurent Pinchart   iommu/ipmmu-vmsa:...
985

b43e0d8a4   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
986
  	mmu->num_ctx = min(IPMMU_CTX_MAX, mmu->features->number_of_contexts);
5fd163416   Magnus Damm   iommu/ipmmu-vmsa:...
987

fd5140e29   Magnus Damm   iommu/ipmmu-vmsa:...
988
989
990
991
992
993
994
995
996
  	/*
  	 * Determine if this IPMMU instance is a root device by checking for
  	 * the lack of has_cache_leaf_nodes flag or renesas,ipmmu-main property.
  	 */
  	if (!mmu->features->has_cache_leaf_nodes ||
  	    !of_find_property(pdev->dev.of_node, "renesas,ipmmu-main", NULL))
  		mmu->root = mmu;
  	else
  		mmu->root = ipmmu_find_root();
d25a2a16f   Laurent Pinchart   iommu: Add driver...
997

fd5140e29   Magnus Damm   iommu/ipmmu-vmsa:...
998
999
1000
1001
1002
1003
1004
1005
  	/*
  	 * Wait until the root device has been registered for sure.
  	 */
  	if (!mmu->root)
  		return -EPROBE_DEFER;
  
  	/* Root devices have mandatory IRQs */
  	if (ipmmu_is_root(mmu)) {
ec37d4e99   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
1006
  		irq = platform_get_irq(pdev, 0);
565d45428   YueHaibing   iommu/ipmmu-vmsa:...
1007
  		if (irq < 0)
fd5140e29   Magnus Damm   iommu/ipmmu-vmsa:...
1008
  			return irq;
fd5140e29   Magnus Damm   iommu/ipmmu-vmsa:...
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
  
  		ret = devm_request_irq(&pdev->dev, irq, ipmmu_irq, 0,
  				       dev_name(&pdev->dev), mmu);
  		if (ret < 0) {
  			dev_err(&pdev->dev, "failed to request IRQ %d
  ", irq);
  			return ret;
  		}
  
  		ipmmu_device_reset(mmu);
2ae869557   Yoshihiro Shimoda   iommu/ipmmu-vmsa:...
1019
1020
1021
1022
1023
1024
  
  		if (mmu->features->reserved_context) {
  			dev_info(&pdev->dev, "IPMMU context 0 is reserved
  ");
  			set_bit(0, mmu->ctx);
  		}
fd5140e29   Magnus Damm   iommu/ipmmu-vmsa:...
1025
  	}
d25a2a16f   Laurent Pinchart   iommu: Add driver...
1026

cda52fcd9   Magnus Damm   iommu/ipmmu-vmsa:...
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
  	/*
  	 * Register the IPMMU to the IOMMU subsystem in the following cases:
  	 * - R-Car Gen2 IPMMU (all devices registered)
  	 * - R-Car Gen3 IPMMU (leaf devices only - skip root IPMMU-MM device)
  	 */
  	if (!mmu->features->has_cache_leaf_nodes || !ipmmu_is_root(mmu)) {
  		ret = iommu_device_sysfs_add(&mmu->iommu, &pdev->dev, NULL,
  					     dev_name(&pdev->dev));
  		if (ret)
  			return ret;
7af9a5fdb   Magnus Damm   iommu/ipmmu-vmsa:...
1037

cda52fcd9   Magnus Damm   iommu/ipmmu-vmsa:...
1038
1039
1040
  		iommu_device_set_ops(&mmu->iommu, &ipmmu_ops);
  		iommu_device_set_fwnode(&mmu->iommu,
  					&pdev->dev.of_node->fwnode);
01da21e56   Magnus Damm   iommu/ipmmu-vmsa:...
1041

cda52fcd9   Magnus Damm   iommu/ipmmu-vmsa:...
1042
1043
1044
1045
1046
1047
1048
1049
1050
  		ret = iommu_device_register(&mmu->iommu);
  		if (ret)
  			return ret;
  
  #if defined(CONFIG_IOMMU_DMA)
  		if (!iommu_present(&platform_bus_type))
  			bus_set_iommu(&platform_bus_type, &ipmmu_ops);
  #endif
  	}
01da21e56   Magnus Damm   iommu/ipmmu-vmsa:...
1051

d25a2a16f   Laurent Pinchart   iommu: Add driver...
1052
1053
1054
1055
1056
  	/*
  	 * We can't create the ARM mapping here as it requires the bus to have
  	 * an IOMMU, which only happens when bus_set_iommu() is called in
  	 * ipmmu_init() after the probe function returns.
  	 */
d25a2a16f   Laurent Pinchart   iommu: Add driver...
1057
1058
1059
1060
1061
1062
1063
1064
  	platform_set_drvdata(pdev, mmu);
  
  	return 0;
  }
  
  static int ipmmu_remove(struct platform_device *pdev)
  {
  	struct ipmmu_vmsa_device *mmu = platform_get_drvdata(pdev);
7af9a5fdb   Magnus Damm   iommu/ipmmu-vmsa:...
1065
  	iommu_device_sysfs_remove(&mmu->iommu);
01da21e56   Magnus Damm   iommu/ipmmu-vmsa:...
1066
  	iommu_device_unregister(&mmu->iommu);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
1067
1068
1069
1070
1071
1072
  	arm_iommu_release_mapping(mmu->mapping);
  
  	ipmmu_device_reset(mmu);
  
  	return 0;
  }
da38e9ec9   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
  #ifdef CONFIG_PM_SLEEP
  static int ipmmu_resume_noirq(struct device *dev)
  {
  	struct ipmmu_vmsa_device *mmu = dev_get_drvdata(dev);
  	unsigned int i;
  
  	/* Reset root MMU and restore contexts */
  	if (ipmmu_is_root(mmu)) {
  		ipmmu_device_reset(mmu);
  
  		for (i = 0; i < mmu->num_ctx; i++) {
  			if (!mmu->domains[i])
  				continue;
  
  			ipmmu_domain_setup_context(mmu->domains[i]);
  		}
  	}
  
  	/* Re-enable active micro-TLBs */
  	for (i = 0; i < mmu->features->num_utlbs; i++) {
  		if (mmu->utlb_ctx[i] == IPMMU_CTX_INVALID)
  			continue;
  
  		ipmmu_utlb_enable(mmu->root->domains[mmu->utlb_ctx[i]], i);
  	}
  
  	return 0;
  }
  
  static const struct dev_pm_ops ipmmu_pm  = {
  	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, ipmmu_resume_noirq)
  };
  #define DEV_PM_OPS	&ipmmu_pm
  #else
  #define DEV_PM_OPS	NULL
  #endif /* CONFIG_PM_SLEEP */
d25a2a16f   Laurent Pinchart   iommu: Add driver...
1109
1110
  static struct platform_driver ipmmu_driver = {
  	.driver = {
d25a2a16f   Laurent Pinchart   iommu: Add driver...
1111
  		.name = "ipmmu-vmsa",
275f5053c   Laurent Pinchart   iommu/ipmmu-vmsa:...
1112
  		.of_match_table = of_match_ptr(ipmmu_of_ids),
da38e9ec9   Geert Uytterhoeven   iommu/ipmmu-vmsa:...
1113
  		.pm = DEV_PM_OPS,
d25a2a16f   Laurent Pinchart   iommu: Add driver...
1114
1115
1116
1117
1118
1119
1120
  	},
  	.probe = ipmmu_probe,
  	.remove	= ipmmu_remove,
  };
  
  static int __init ipmmu_init(void)
  {
5c5c87411   Dmitry Osipenko   iommu/ipmmu-vmsa:...
1121
  	struct device_node *np;
cda52fcd9   Magnus Damm   iommu/ipmmu-vmsa:...
1122
  	static bool setup_done;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
1123
  	int ret;
cda52fcd9   Magnus Damm   iommu/ipmmu-vmsa:...
1124
1125
  	if (setup_done)
  		return 0;
5c5c87411   Dmitry Osipenko   iommu/ipmmu-vmsa:...
1126
1127
1128
1129
1130
  	np = of_find_matching_node(NULL, ipmmu_of_ids);
  	if (!np)
  		return 0;
  
  	of_node_put(np);
d25a2a16f   Laurent Pinchart   iommu: Add driver...
1131
1132
1133
  	ret = platform_driver_register(&ipmmu_driver);
  	if (ret < 0)
  		return ret;
cda52fcd9   Magnus Damm   iommu/ipmmu-vmsa:...
1134
  #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA)
d25a2a16f   Laurent Pinchart   iommu: Add driver...
1135
1136
  	if (!iommu_present(&platform_bus_type))
  		bus_set_iommu(&platform_bus_type, &ipmmu_ops);
cda52fcd9   Magnus Damm   iommu/ipmmu-vmsa:...
1137
  #endif
d25a2a16f   Laurent Pinchart   iommu: Add driver...
1138

cda52fcd9   Magnus Damm   iommu/ipmmu-vmsa:...
1139
  	setup_done = true;
d25a2a16f   Laurent Pinchart   iommu: Add driver...
1140
1141
  	return 0;
  }
d25a2a16f   Laurent Pinchart   iommu: Add driver...
1142
  subsys_initcall(ipmmu_init);