]>
Commit | Line | Data |
---|---|---|
10a83cb9 PM |
1 | /* |
2 | * ARM SMMUv3 support - Internal API | |
3 | * | |
4 | * Copyright (C) 2014-2016 Broadcom Corporation | |
5 | * Copyright (c) 2017 Red Hat, Inc. | |
6 | * Written by Prem Mallappa, Eric Auger | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License along | |
18 | * with this program; if not, see <http://www.gnu.org/licenses/>. | |
19 | */ | |
20 | ||
58ea30f5 MA |
21 | #ifndef HW_ARM_SMMUV3_INTERNAL_H |
22 | #define HW_ARM_SMMUV3_INTERNAL_H | |
10a83cb9 | 23 | |
7b31c2db | 24 | #include "hw/registerfields.h" |
10a83cb9 PM |
25 | #include "hw/arm/smmu-common.h" |
26 | ||
9122bea9 JH |
27 | typedef enum SMMUTranslationStatus { |
28 | SMMU_TRANS_DISABLE, | |
29 | SMMU_TRANS_ABORT, | |
30 | SMMU_TRANS_BYPASS, | |
31 | SMMU_TRANS_ERROR, | |
32 | SMMU_TRANS_SUCCESS, | |
33 | } SMMUTranslationStatus; | |
34 | ||
10a83cb9 PM |
35 | /* MMIO Registers */ |
36 | ||
37 | REG32(IDR0, 0x0) | |
263d0e48 | 38 | FIELD(IDR0, S2P, 0 , 1) |
10a83cb9 PM |
39 | FIELD(IDR0, S1P, 1 , 1) |
40 | FIELD(IDR0, TTF, 2 , 2) | |
41 | FIELD(IDR0, COHACC, 4 , 1) | |
cbaf9404 PM |
42 | FIELD(IDR0, BTM, 5 , 1) |
43 | FIELD(IDR0, HTTU, 6 , 2) | |
44 | FIELD(IDR0, DORMHINT, 8 , 1) | |
45 | FIELD(IDR0, HYP, 9 , 1) | |
46 | FIELD(IDR0, ATS, 10, 1) | |
47 | FIELD(IDR0, NS1ATS, 11, 1) | |
10a83cb9 | 48 | FIELD(IDR0, ASID16, 12, 1) |
cbaf9404 PM |
49 | FIELD(IDR0, MSI, 13, 1) |
50 | FIELD(IDR0, SEV, 14, 1) | |
51 | FIELD(IDR0, ATOS, 15, 1) | |
52 | FIELD(IDR0, PRI, 16, 1) | |
53 | FIELD(IDR0, VMW, 17, 1) | |
263d0e48 | 54 | FIELD(IDR0, VMID16, 18, 1) |
cbaf9404 PM |
55 | FIELD(IDR0, CD2L, 19, 1) |
56 | FIELD(IDR0, VATOS, 20, 1) | |
10a83cb9 | 57 | FIELD(IDR0, TTENDIAN, 21, 2) |
cbaf9404 | 58 | FIELD(IDR0, ATSRECERR, 23, 1) |
10a83cb9 PM |
59 | FIELD(IDR0, STALL_MODEL, 24, 2) |
60 | FIELD(IDR0, TERM_MODEL, 26, 1) | |
61 | FIELD(IDR0, STLEVEL, 27, 2) | |
cbaf9404 | 62 | FIELD(IDR0, RME_IMPL, 30, 1) |
10a83cb9 PM |
63 | |
64 | REG32(IDR1, 0x4) | |
65 | FIELD(IDR1, SIDSIZE, 0 , 6) | |
cbaf9404 PM |
66 | FIELD(IDR1, SSIDSIZE, 6 , 5) |
67 | FIELD(IDR1, PRIQS, 11, 5) | |
10a83cb9 PM |
68 | FIELD(IDR1, EVENTQS, 16, 5) |
69 | FIELD(IDR1, CMDQS, 21, 5) | |
cbaf9404 PM |
70 | FIELD(IDR1, ATTR_PERMS_OVR, 26, 1) |
71 | FIELD(IDR1, ATTR_TYPES_OVR, 27, 1) | |
72 | FIELD(IDR1, REL, 28, 1) | |
73 | FIELD(IDR1, QUEUES_PRESET, 29, 1) | |
74 | FIELD(IDR1, TABLES_PRESET, 30, 1) | |
75 | FIELD(IDR1, ECMDQ, 31, 1) | |
10a83cb9 PM |
76 | |
77 | #define SMMU_IDR1_SIDSIZE 16 | |
78 | #define SMMU_CMDQS 19 | |
79 | #define SMMU_EVENTQS 19 | |
80 | ||
81 | REG32(IDR2, 0x8) | |
cbaf9404 PM |
82 | FIELD(IDR2, BA_VATOS, 0, 10) |
83 | ||
10a83cb9 | 84 | REG32(IDR3, 0xc) |
e7c3b9d9 | 85 | FIELD(IDR3, HAD, 2, 1); |
cbaf9404 PM |
86 | FIELD(IDR3, PBHA, 3, 1); |
87 | FIELD(IDR3, XNX, 4, 1); | |
88 | FIELD(IDR3, PPS, 5, 1); | |
89 | FIELD(IDR3, MPAM, 7, 1); | |
90 | FIELD(IDR3, FWB, 8, 1); | |
91 | FIELD(IDR3, STT, 9, 1); | |
de206dfd | 92 | FIELD(IDR3, RIL, 10, 1); |
f8e7163d | 93 | FIELD(IDR3, BBML, 11, 2); |
cbaf9404 PM |
94 | FIELD(IDR3, E0PD, 13, 1); |
95 | FIELD(IDR3, PTWNNC, 14, 1); | |
96 | FIELD(IDR3, DPT, 15, 1); | |
97 | ||
10a83cb9 | 98 | REG32(IDR4, 0x10) |
cbaf9404 | 99 | |
10a83cb9 PM |
100 | REG32(IDR5, 0x14) |
101 | FIELD(IDR5, OAS, 0, 3); | |
102 | FIELD(IDR5, GRAN4K, 4, 1); | |
103 | FIELD(IDR5, GRAN16K, 5, 1); | |
104 | FIELD(IDR5, GRAN64K, 6, 1); | |
cbaf9404 PM |
105 | FIELD(IDR5, VAX, 10, 2); |
106 | FIELD(IDR5, STALL_MAX, 16, 16); | |
10a83cb9 PM |
107 | |
108 | #define SMMU_IDR5_OAS 4 | |
109 | ||
f0ec277c | 110 | REG32(IIDR, 0x18) |
5888f0ad | 111 | REG32(AIDR, 0x1c) |
10a83cb9 PM |
112 | REG32(CR0, 0x20) |
113 | FIELD(CR0, SMMU_ENABLE, 0, 1) | |
114 | FIELD(CR0, EVENTQEN, 2, 1) | |
115 | FIELD(CR0, CMDQEN, 3, 1) | |
116 | ||
fae4be38 EA |
117 | #define SMMU_CR0_RESERVED 0xFFFFFC20 |
118 | ||
10a83cb9 PM |
119 | REG32(CR0ACK, 0x24) |
120 | REG32(CR1, 0x28) | |
121 | REG32(CR2, 0x2c) | |
122 | REG32(STATUSR, 0x40) | |
c2ecb424 MS |
123 | REG32(GBPA, 0x44) |
124 | FIELD(GBPA, ABORT, 20, 1) | |
125 | FIELD(GBPA, UPDATE, 31, 1) | |
126 | ||
127 | /* Use incoming. */ | |
128 | #define SMMU_GBPA_RESET_VAL 0x1000 | |
129 | ||
10a83cb9 PM |
130 | REG32(IRQ_CTRL, 0x50) |
131 | FIELD(IRQ_CTRL, GERROR_IRQEN, 0, 1) | |
132 | FIELD(IRQ_CTRL, PRI_IRQEN, 1, 1) | |
133 | FIELD(IRQ_CTRL, EVENTQ_IRQEN, 2, 1) | |
134 | ||
135 | REG32(IRQ_CTRL_ACK, 0x54) | |
136 | REG32(GERROR, 0x60) | |
137 | FIELD(GERROR, CMDQ_ERR, 0, 1) | |
138 | FIELD(GERROR, EVENTQ_ABT_ERR, 2, 1) | |
139 | FIELD(GERROR, PRIQ_ABT_ERR, 3, 1) | |
140 | FIELD(GERROR, MSI_CMDQ_ABT_ERR, 4, 1) | |
141 | FIELD(GERROR, MSI_EVENTQ_ABT_ERR, 5, 1) | |
142 | FIELD(GERROR, MSI_PRIQ_ABT_ERR, 6, 1) | |
143 | FIELD(GERROR, MSI_GERROR_ABT_ERR, 7, 1) | |
144 | FIELD(GERROR, MSI_SFM_ERR, 8, 1) | |
145 | ||
146 | REG32(GERRORN, 0x64) | |
147 | ||
148 | #define A_GERROR_IRQ_CFG0 0x68 /* 64b */ | |
149 | REG32(GERROR_IRQ_CFG1, 0x70) | |
150 | REG32(GERROR_IRQ_CFG2, 0x74) | |
151 | ||
152 | #define A_STRTAB_BASE 0x80 /* 64b */ | |
153 | ||
3293b9f5 | 154 | #define SMMU_BASE_ADDR_MASK 0xfffffffffffc0 |
10a83cb9 PM |
155 | |
156 | REG32(STRTAB_BASE_CFG, 0x88) | |
157 | FIELD(STRTAB_BASE_CFG, FMT, 16, 2) | |
158 | FIELD(STRTAB_BASE_CFG, SPLIT, 6 , 5) | |
159 | FIELD(STRTAB_BASE_CFG, LOG2SIZE, 0 , 6) | |
160 | ||
161 | #define A_CMDQ_BASE 0x90 /* 64b */ | |
162 | REG32(CMDQ_PROD, 0x98) | |
163 | REG32(CMDQ_CONS, 0x9c) | |
164 | FIELD(CMDQ_CONS, ERR, 24, 7) | |
165 | ||
166 | #define A_EVENTQ_BASE 0xa0 /* 64b */ | |
167 | REG32(EVENTQ_PROD, 0xa8) | |
168 | REG32(EVENTQ_CONS, 0xac) | |
169 | ||
170 | #define A_EVENTQ_IRQ_CFG0 0xb0 /* 64b */ | |
171 | REG32(EVENTQ_IRQ_CFG1, 0xb8) | |
172 | REG32(EVENTQ_IRQ_CFG2, 0xbc) | |
173 | ||
174 | #define A_IDREGS 0xfd0 | |
175 | ||
176 | static inline int smmu_enabled(SMMUv3State *s) | |
177 | { | |
178 | return FIELD_EX32(s->cr[0], CR0, SMMU_ENABLE); | |
179 | } | |
180 | ||
181 | /* Command Queue Entry */ | |
182 | typedef struct Cmd { | |
183 | uint32_t word[4]; | |
184 | } Cmd; | |
185 | ||
186 | /* Event Queue Entry */ | |
187 | typedef struct Evt { | |
188 | uint32_t word[8]; | |
189 | } Evt; | |
190 | ||
191 | static inline uint32_t smmuv3_idreg(int regoffset) | |
192 | { | |
193 | /* | |
194 | * Return the value of the Primecell/Corelink ID registers at the | |
195 | * specified offset from the first ID register. | |
196 | * These value indicate an ARM implementation of MMU600 p1 | |
197 | */ | |
198 | static const uint8_t smmuv3_ids[] = { | |
199 | 0x04, 0, 0, 0, 0x84, 0xB4, 0xF0, 0x10, 0x0D, 0xF0, 0x05, 0xB1 | |
200 | }; | |
201 | return smmuv3_ids[regoffset / 4]; | |
202 | } | |
203 | ||
6a736033 EA |
204 | static inline bool smmuv3_eventq_irq_enabled(SMMUv3State *s) |
205 | { | |
206 | return FIELD_EX32(s->irq_ctrl, IRQ_CTRL, EVENTQ_IRQEN); | |
207 | } | |
208 | ||
209 | static inline bool smmuv3_gerror_irq_enabled(SMMUv3State *s) | |
210 | { | |
211 | return FIELD_EX32(s->irq_ctrl, IRQ_CTRL, GERROR_IRQEN); | |
212 | } | |
213 | ||
dadd1a08 EA |
214 | /* Queue Handling */ |
215 | ||
216 | #define Q_BASE(q) ((q)->base & SMMU_BASE_ADDR_MASK) | |
217 | #define WRAP_MASK(q) (1 << (q)->log2size) | |
218 | #define INDEX_MASK(q) (((1 << (q)->log2size)) - 1) | |
219 | #define WRAP_INDEX_MASK(q) ((1 << ((q)->log2size + 1)) - 1) | |
220 | ||
221 | #define Q_CONS(q) ((q)->cons & INDEX_MASK(q)) | |
222 | #define Q_PROD(q) ((q)->prod & INDEX_MASK(q)) | |
223 | ||
224 | #define Q_CONS_ENTRY(q) (Q_BASE(q) + (q)->entry_size * Q_CONS(q)) | |
225 | #define Q_PROD_ENTRY(q) (Q_BASE(q) + (q)->entry_size * Q_PROD(q)) | |
226 | ||
227 | #define Q_CONS_WRAP(q) (((q)->cons & WRAP_MASK(q)) >> (q)->log2size) | |
228 | #define Q_PROD_WRAP(q) (((q)->prod & WRAP_MASK(q)) >> (q)->log2size) | |
229 | ||
230 | static inline bool smmuv3_q_full(SMMUQueue *q) | |
231 | { | |
232 | return ((q->cons ^ q->prod) & WRAP_INDEX_MASK(q)) == WRAP_MASK(q); | |
233 | } | |
234 | ||
235 | static inline bool smmuv3_q_empty(SMMUQueue *q) | |
236 | { | |
237 | return (q->cons & WRAP_INDEX_MASK(q)) == (q->prod & WRAP_INDEX_MASK(q)); | |
238 | } | |
239 | ||
240 | static inline void queue_prod_incr(SMMUQueue *q) | |
241 | { | |
242 | q->prod = (q->prod + 1) & WRAP_INDEX_MASK(q); | |
243 | } | |
244 | ||
245 | static inline void queue_cons_incr(SMMUQueue *q) | |
246 | { | |
247 | /* | |
248 | * We have to use deposit for the CONS registers to preserve | |
249 | * the ERR field in the high bits. | |
250 | */ | |
251 | q->cons = deposit32(q->cons, 0, q->log2size + 1, q->cons + 1); | |
252 | } | |
253 | ||
254 | static inline bool smmuv3_cmdq_enabled(SMMUv3State *s) | |
255 | { | |
256 | return FIELD_EX32(s->cr[0], CR0, CMDQEN); | |
257 | } | |
258 | ||
259 | static inline bool smmuv3_eventq_enabled(SMMUv3State *s) | |
260 | { | |
261 | return FIELD_EX32(s->cr[0], CR0, EVENTQEN); | |
262 | } | |
263 | ||
264 | static inline void smmu_write_cmdq_err(SMMUv3State *s, uint32_t err_type) | |
265 | { | |
266 | s->cmdq.cons = FIELD_DP32(s->cmdq.cons, CMDQ_CONS, ERR, err_type); | |
267 | } | |
268 | ||
dadd1a08 EA |
269 | /* Commands */ |
270 | ||
271 | typedef enum SMMUCommandType { | |
272 | SMMU_CMD_NONE = 0x00, | |
273 | SMMU_CMD_PREFETCH_CONFIG , | |
274 | SMMU_CMD_PREFETCH_ADDR, | |
275 | SMMU_CMD_CFGI_STE, | |
276 | SMMU_CMD_CFGI_STE_RANGE, | |
277 | SMMU_CMD_CFGI_CD, | |
278 | SMMU_CMD_CFGI_CD_ALL, | |
279 | SMMU_CMD_CFGI_ALL, | |
280 | SMMU_CMD_TLBI_NH_ALL = 0x10, | |
281 | SMMU_CMD_TLBI_NH_ASID, | |
282 | SMMU_CMD_TLBI_NH_VA, | |
283 | SMMU_CMD_TLBI_NH_VAA, | |
284 | SMMU_CMD_TLBI_EL3_ALL = 0x18, | |
285 | SMMU_CMD_TLBI_EL3_VA = 0x1a, | |
286 | SMMU_CMD_TLBI_EL2_ALL = 0x20, | |
287 | SMMU_CMD_TLBI_EL2_ASID, | |
288 | SMMU_CMD_TLBI_EL2_VA, | |
289 | SMMU_CMD_TLBI_EL2_VAA, | |
290 | SMMU_CMD_TLBI_S12_VMALL = 0x28, | |
291 | SMMU_CMD_TLBI_S2_IPA = 0x2a, | |
292 | SMMU_CMD_TLBI_NSNH_ALL = 0x30, | |
293 | SMMU_CMD_ATC_INV = 0x40, | |
294 | SMMU_CMD_PRI_RESP, | |
295 | SMMU_CMD_RESUME = 0x44, | |
296 | SMMU_CMD_STALL_TERM, | |
297 | SMMU_CMD_SYNC, | |
298 | } SMMUCommandType; | |
299 | ||
300 | static const char *cmd_stringify[] = { | |
301 | [SMMU_CMD_PREFETCH_CONFIG] = "SMMU_CMD_PREFETCH_CONFIG", | |
302 | [SMMU_CMD_PREFETCH_ADDR] = "SMMU_CMD_PREFETCH_ADDR", | |
303 | [SMMU_CMD_CFGI_STE] = "SMMU_CMD_CFGI_STE", | |
304 | [SMMU_CMD_CFGI_STE_RANGE] = "SMMU_CMD_CFGI_STE_RANGE", | |
305 | [SMMU_CMD_CFGI_CD] = "SMMU_CMD_CFGI_CD", | |
306 | [SMMU_CMD_CFGI_CD_ALL] = "SMMU_CMD_CFGI_CD_ALL", | |
307 | [SMMU_CMD_CFGI_ALL] = "SMMU_CMD_CFGI_ALL", | |
308 | [SMMU_CMD_TLBI_NH_ALL] = "SMMU_CMD_TLBI_NH_ALL", | |
309 | [SMMU_CMD_TLBI_NH_ASID] = "SMMU_CMD_TLBI_NH_ASID", | |
310 | [SMMU_CMD_TLBI_NH_VA] = "SMMU_CMD_TLBI_NH_VA", | |
311 | [SMMU_CMD_TLBI_NH_VAA] = "SMMU_CMD_TLBI_NH_VAA", | |
312 | [SMMU_CMD_TLBI_EL3_ALL] = "SMMU_CMD_TLBI_EL3_ALL", | |
313 | [SMMU_CMD_TLBI_EL3_VA] = "SMMU_CMD_TLBI_EL3_VA", | |
314 | [SMMU_CMD_TLBI_EL2_ALL] = "SMMU_CMD_TLBI_EL2_ALL", | |
315 | [SMMU_CMD_TLBI_EL2_ASID] = "SMMU_CMD_TLBI_EL2_ASID", | |
316 | [SMMU_CMD_TLBI_EL2_VA] = "SMMU_CMD_TLBI_EL2_VA", | |
317 | [SMMU_CMD_TLBI_EL2_VAA] = "SMMU_CMD_TLBI_EL2_VAA", | |
318 | [SMMU_CMD_TLBI_S12_VMALL] = "SMMU_CMD_TLBI_S12_VMALL", | |
319 | [SMMU_CMD_TLBI_S2_IPA] = "SMMU_CMD_TLBI_S2_IPA", | |
320 | [SMMU_CMD_TLBI_NSNH_ALL] = "SMMU_CMD_TLBI_NSNH_ALL", | |
321 | [SMMU_CMD_ATC_INV] = "SMMU_CMD_ATC_INV", | |
322 | [SMMU_CMD_PRI_RESP] = "SMMU_CMD_PRI_RESP", | |
323 | [SMMU_CMD_RESUME] = "SMMU_CMD_RESUME", | |
324 | [SMMU_CMD_STALL_TERM] = "SMMU_CMD_STALL_TERM", | |
325 | [SMMU_CMD_SYNC] = "SMMU_CMD_SYNC", | |
326 | }; | |
327 | ||
328 | static inline const char *smmu_cmd_string(SMMUCommandType type) | |
329 | { | |
330 | if (type > SMMU_CMD_NONE && type < ARRAY_SIZE(cmd_stringify)) { | |
331 | return cmd_stringify[type] ? cmd_stringify[type] : "UNKNOWN"; | |
332 | } else { | |
333 | return "INVALID"; | |
334 | } | |
335 | } | |
336 | ||
337 | /* CMDQ fields */ | |
338 | ||
339 | typedef enum { | |
340 | SMMU_CERROR_NONE = 0, | |
341 | SMMU_CERROR_ILL, | |
342 | SMMU_CERROR_ABT, | |
343 | SMMU_CERROR_ATC_INV_SYNC, | |
344 | } SMMUCmdError; | |
345 | ||
346 | enum { /* Command completion notification */ | |
347 | CMD_SYNC_SIG_NONE, | |
348 | CMD_SYNC_SIG_IRQ, | |
349 | CMD_SYNC_SIG_SEV, | |
350 | }; | |
351 | ||
352 | #define CMD_TYPE(x) extract32((x)->word[0], 0 , 8) | |
d5291561 EA |
353 | #define CMD_NUM(x) extract32((x)->word[0], 12 , 5) |
354 | #define CMD_SCALE(x) extract32((x)->word[0], 20 , 5) | |
dadd1a08 EA |
355 | #define CMD_SSEC(x) extract32((x)->word[0], 10, 1) |
356 | #define CMD_SSV(x) extract32((x)->word[0], 11, 1) | |
357 | #define CMD_RESUME_AC(x) extract32((x)->word[0], 12, 1) | |
358 | #define CMD_RESUME_AB(x) extract32((x)->word[0], 13, 1) | |
359 | #define CMD_SYNC_CS(x) extract32((x)->word[0], 12, 2) | |
360 | #define CMD_SSID(x) extract32((x)->word[0], 12, 20) | |
361 | #define CMD_SID(x) ((x)->word[1]) | |
362 | #define CMD_VMID(x) extract32((x)->word[1], 0 , 16) | |
363 | #define CMD_ASID(x) extract32((x)->word[1], 16, 16) | |
364 | #define CMD_RESUME_STAG(x) extract32((x)->word[2], 0 , 16) | |
365 | #define CMD_RESP(x) extract32((x)->word[2], 11, 2) | |
366 | #define CMD_LEAF(x) extract32((x)->word[2], 0 , 1) | |
d5291561 EA |
367 | #define CMD_TTL(x) extract32((x)->word[2], 8 , 2) |
368 | #define CMD_TG(x) extract32((x)->word[2], 10, 2) | |
dadd1a08 | 369 | #define CMD_STE_RANGE(x) extract32((x)->word[2], 0 , 5) |
84abccdd PM |
370 | #define CMD_ADDR(x) \ |
371 | (((uint64_t)((x)->word[3]) << 32) | \ | |
372 | ((extract64((x)->word[2], 12, 20)) << 12)) | |
dadd1a08 | 373 | |
fae4be38 | 374 | #define SMMU_FEATURE_2LVL_STE (1 << 0) |
dadd1a08 | 375 | |
bb981004 EA |
376 | /* Events */ |
377 | ||
378 | typedef enum SMMUEventType { | |
9122bea9 | 379 | SMMU_EVT_NONE = 0x00, |
bb981004 EA |
380 | SMMU_EVT_F_UUT , |
381 | SMMU_EVT_C_BAD_STREAMID , | |
382 | SMMU_EVT_F_STE_FETCH , | |
383 | SMMU_EVT_C_BAD_STE , | |
384 | SMMU_EVT_F_BAD_ATS_TREQ , | |
385 | SMMU_EVT_F_STREAM_DISABLED , | |
386 | SMMU_EVT_F_TRANS_FORBIDDEN , | |
387 | SMMU_EVT_C_BAD_SUBSTREAMID , | |
388 | SMMU_EVT_F_CD_FETCH , | |
389 | SMMU_EVT_C_BAD_CD , | |
390 | SMMU_EVT_F_WALK_EABT , | |
391 | SMMU_EVT_F_TRANSLATION = 0x10, | |
392 | SMMU_EVT_F_ADDR_SIZE , | |
393 | SMMU_EVT_F_ACCESS , | |
394 | SMMU_EVT_F_PERMISSION , | |
395 | SMMU_EVT_F_TLB_CONFLICT = 0x20, | |
396 | SMMU_EVT_F_CFG_CONFLICT , | |
397 | SMMU_EVT_E_PAGE_REQ = 0x24, | |
398 | } SMMUEventType; | |
399 | ||
400 | static const char *event_stringify[] = { | |
9122bea9 | 401 | [SMMU_EVT_NONE] = "no recorded event", |
bb981004 EA |
402 | [SMMU_EVT_F_UUT] = "SMMU_EVT_F_UUT", |
403 | [SMMU_EVT_C_BAD_STREAMID] = "SMMU_EVT_C_BAD_STREAMID", | |
404 | [SMMU_EVT_F_STE_FETCH] = "SMMU_EVT_F_STE_FETCH", | |
405 | [SMMU_EVT_C_BAD_STE] = "SMMU_EVT_C_BAD_STE", | |
406 | [SMMU_EVT_F_BAD_ATS_TREQ] = "SMMU_EVT_F_BAD_ATS_TREQ", | |
407 | [SMMU_EVT_F_STREAM_DISABLED] = "SMMU_EVT_F_STREAM_DISABLED", | |
408 | [SMMU_EVT_F_TRANS_FORBIDDEN] = "SMMU_EVT_F_TRANS_FORBIDDEN", | |
409 | [SMMU_EVT_C_BAD_SUBSTREAMID] = "SMMU_EVT_C_BAD_SUBSTREAMID", | |
410 | [SMMU_EVT_F_CD_FETCH] = "SMMU_EVT_F_CD_FETCH", | |
411 | [SMMU_EVT_C_BAD_CD] = "SMMU_EVT_C_BAD_CD", | |
412 | [SMMU_EVT_F_WALK_EABT] = "SMMU_EVT_F_WALK_EABT", | |
413 | [SMMU_EVT_F_TRANSLATION] = "SMMU_EVT_F_TRANSLATION", | |
414 | [SMMU_EVT_F_ADDR_SIZE] = "SMMU_EVT_F_ADDR_SIZE", | |
415 | [SMMU_EVT_F_ACCESS] = "SMMU_EVT_F_ACCESS", | |
416 | [SMMU_EVT_F_PERMISSION] = "SMMU_EVT_F_PERMISSION", | |
417 | [SMMU_EVT_F_TLB_CONFLICT] = "SMMU_EVT_F_TLB_CONFLICT", | |
418 | [SMMU_EVT_F_CFG_CONFLICT] = "SMMU_EVT_F_CFG_CONFLICT", | |
419 | [SMMU_EVT_E_PAGE_REQ] = "SMMU_EVT_E_PAGE_REQ", | |
420 | }; | |
421 | ||
422 | static inline const char *smmu_event_string(SMMUEventType type) | |
423 | { | |
424 | if (type < ARRAY_SIZE(event_stringify)) { | |
425 | return event_stringify[type] ? event_stringify[type] : "UNKNOWN"; | |
426 | } else { | |
427 | return "INVALID"; | |
428 | } | |
429 | } | |
430 | ||
431 | /* Encode an event record */ | |
432 | typedef struct SMMUEventInfo { | |
433 | SMMUEventType type; | |
434 | uint32_t sid; | |
435 | bool recorded; | |
3499ec08 | 436 | bool inval_ste_allowed; |
bb981004 EA |
437 | union { |
438 | struct { | |
439 | uint32_t ssid; | |
440 | bool ssv; | |
441 | dma_addr_t addr; | |
442 | bool rnw; | |
443 | bool pnu; | |
444 | bool ind; | |
445 | } f_uut; | |
446 | struct SSIDInfo { | |
447 | uint32_t ssid; | |
448 | bool ssv; | |
449 | } c_bad_streamid; | |
450 | struct SSIDAddrInfo { | |
451 | uint32_t ssid; | |
452 | bool ssv; | |
453 | dma_addr_t addr; | |
454 | } f_ste_fetch; | |
455 | struct SSIDInfo c_bad_ste; | |
456 | struct { | |
457 | dma_addr_t addr; | |
458 | bool rnw; | |
459 | } f_transl_forbidden; | |
460 | struct { | |
461 | uint32_t ssid; | |
462 | } c_bad_substream; | |
463 | struct SSIDAddrInfo f_cd_fetch; | |
464 | struct SSIDInfo c_bad_cd; | |
465 | struct FullInfo { | |
466 | bool stall; | |
467 | uint16_t stag; | |
468 | uint32_t ssid; | |
469 | bool ssv; | |
470 | bool s2; | |
471 | dma_addr_t addr; | |
472 | bool rnw; | |
473 | bool pnu; | |
474 | bool ind; | |
475 | uint8_t class; | |
476 | dma_addr_t addr2; | |
477 | } f_walk_eabt; | |
478 | struct FullInfo f_translation; | |
479 | struct FullInfo f_addr_size; | |
480 | struct FullInfo f_access; | |
481 | struct FullInfo f_permission; | |
482 | struct SSIDInfo f_cfg_conflict; | |
483 | /** | |
484 | * not supported yet: | |
485 | * F_BAD_ATS_TREQ | |
486 | * F_BAD_ATS_TREQ | |
487 | * F_TLB_CONFLICT | |
488 | * E_PAGE_REQUEST | |
489 | * IMPDEF_EVENTn | |
490 | */ | |
491 | } u; | |
492 | } SMMUEventInfo; | |
493 | ||
494 | /* EVTQ fields */ | |
495 | ||
496 | #define EVT_Q_OVERFLOW (1 << 31) | |
497 | ||
9f4d2a13 EA |
498 | #define EVT_SET_TYPE(x, v) ((x)->word[0] = deposit32((x)->word[0], 0 , 8 , v)) |
499 | #define EVT_SET_SSV(x, v) ((x)->word[0] = deposit32((x)->word[0], 11, 1 , v)) | |
500 | #define EVT_SET_SSID(x, v) ((x)->word[0] = deposit32((x)->word[0], 12, 20, v)) | |
501 | #define EVT_SET_SID(x, v) ((x)->word[1] = v) | |
502 | #define EVT_SET_STAG(x, v) ((x)->word[2] = deposit32((x)->word[2], 0 , 16, v)) | |
503 | #define EVT_SET_STALL(x, v) ((x)->word[2] = deposit32((x)->word[2], 31, 1 , v)) | |
504 | #define EVT_SET_PNU(x, v) ((x)->word[3] = deposit32((x)->word[3], 1 , 1 , v)) | |
505 | #define EVT_SET_IND(x, v) ((x)->word[3] = deposit32((x)->word[3], 2 , 1 , v)) | |
506 | #define EVT_SET_RNW(x, v) ((x)->word[3] = deposit32((x)->word[3], 3 , 1 , v)) | |
507 | #define EVT_SET_S2(x, v) ((x)->word[3] = deposit32((x)->word[3], 7 , 1 , v)) | |
508 | #define EVT_SET_CLASS(x, v) ((x)->word[3] = deposit32((x)->word[3], 8 , 2 , v)) | |
bb981004 EA |
509 | #define EVT_SET_ADDR(x, addr) \ |
510 | do { \ | |
511 | (x)->word[5] = (uint32_t)(addr >> 32); \ | |
512 | (x)->word[4] = (uint32_t)(addr & 0xffffffff); \ | |
513 | } while (0) | |
514 | #define EVT_SET_ADDR2(x, addr) \ | |
515 | do { \ | |
a7f65ceb SV |
516 | (x)->word[7] = (uint32_t)(addr >> 32); \ |
517 | (x)->word[6] = (uint32_t)(addr & 0xffffffff); \ | |
bb981004 EA |
518 | } while (0) |
519 | ||
520 | void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *event); | |
521 | ||
9bde7f06 EA |
522 | /* Configuration Data */ |
523 | ||
524 | /* STE Level 1 Descriptor */ | |
525 | typedef struct STEDesc { | |
526 | uint32_t word[2]; | |
527 | } STEDesc; | |
528 | ||
529 | /* CD Level 1 Descriptor */ | |
530 | typedef struct CDDesc { | |
531 | uint32_t word[2]; | |
532 | } CDDesc; | |
533 | ||
534 | /* Stream Table Entry(STE) */ | |
535 | typedef struct STE { | |
536 | uint32_t word[16]; | |
537 | } STE; | |
538 | ||
539 | /* Context Descriptor(CD) */ | |
540 | typedef struct CD { | |
541 | uint32_t word[16]; | |
542 | } CD; | |
543 | ||
544 | /* STE fields */ | |
545 | ||
546 | #define STE_VALID(x) extract32((x)->word[0], 0, 1) | |
547 | ||
548 | #define STE_CONFIG(x) extract32((x)->word[0], 1, 3) | |
549 | #define STE_CFG_S1_ENABLED(config) (config & 0x1) | |
550 | #define STE_CFG_S2_ENABLED(config) (config & 0x2) | |
551 | #define STE_CFG_ABORT(config) (!(config & 0x4)) | |
552 | #define STE_CFG_BYPASS(config) (config == 0x4) | |
553 | ||
554 | #define STE_S1FMT(x) extract32((x)->word[0], 4 , 2) | |
555 | #define STE_S1CDMAX(x) extract32((x)->word[1], 27, 5) | |
556 | #define STE_S1STALLD(x) extract32((x)->word[2], 27, 1) | |
557 | #define STE_EATS(x) extract32((x)->word[2], 28, 2) | |
558 | #define STE_STRW(x) extract32((x)->word[2], 30, 2) | |
559 | #define STE_S2VMID(x) extract32((x)->word[4], 0 , 16) | |
560 | #define STE_S2T0SZ(x) extract32((x)->word[5], 0 , 6) | |
561 | #define STE_S2SL0(x) extract32((x)->word[5], 6 , 2) | |
562 | #define STE_S2TG(x) extract32((x)->word[5], 14, 2) | |
563 | #define STE_S2PS(x) extract32((x)->word[5], 16, 3) | |
564 | #define STE_S2AA64(x) extract32((x)->word[5], 19, 1) | |
21eb5b5c MS |
565 | #define STE_S2ENDI(x) extract32((x)->word[5], 20, 1) |
566 | #define STE_S2AFFD(x) extract32((x)->word[5], 21, 1) | |
567 | #define STE_S2HD(x) extract32((x)->word[5], 23, 1) | |
568 | #define STE_S2HA(x) extract32((x)->word[5], 24, 1) | |
569 | #define STE_S2S(x) extract32((x)->word[5], 25, 1) | |
570 | #define STE_S2R(x) extract32((x)->word[5], 26, 1) | |
571 | ||
84abccdd PM |
572 | #define STE_CTXPTR(x) \ |
573 | ((extract64((x)->word[1], 0, 16) << 32) | \ | |
574 | ((x)->word[0] & 0xffffffc0)) | |
575 | ||
576 | #define STE_S2TTB(x) \ | |
577 | ((extract64((x)->word[7], 0, 16) << 32) | \ | |
578 | ((x)->word[6] & 0xfffffff0)) | |
9bde7f06 EA |
579 | |
580 | static inline int oas2bits(int oas_field) | |
581 | { | |
582 | switch (oas_field) { | |
583 | case 0: | |
584 | return 32; | |
585 | case 1: | |
586 | return 36; | |
587 | case 2: | |
588 | return 40; | |
589 | case 3: | |
590 | return 42; | |
591 | case 4: | |
592 | return 44; | |
593 | case 5: | |
594 | return 48; | |
595 | } | |
596 | return -1; | |
597 | } | |
598 | ||
599 | static inline int pa_range(STE *ste) | |
600 | { | |
601 | int oas_field = MIN(STE_S2PS(ste), SMMU_IDR5_OAS); | |
602 | ||
603 | if (!STE_S2AA64(ste)) { | |
604 | return 40; | |
605 | } | |
606 | ||
607 | return oas2bits(oas_field); | |
608 | } | |
609 | ||
610 | #define MAX_PA(ste) ((1 << pa_range(ste)) - 1) | |
611 | ||
612 | /* CD fields */ | |
613 | ||
1b41847a | 614 | #define CD_VALID(x) extract32((x)->word[0], 31, 1) |
9bde7f06 | 615 | #define CD_ASID(x) extract32((x)->word[1], 16, 16) |
84abccdd PM |
616 | #define CD_TTB(x, sel) \ |
617 | ((extract64((x)->word[(sel) * 2 + 3], 0, 19) << 32) | \ | |
618 | ((x)->word[(sel) * 2 + 2] & ~0xfULL)) | |
619 | ||
e7c3b9d9 | 620 | #define CD_HAD(x, sel) extract32((x)->word[(sel) * 2 + 2], 1, 1) |
9bde7f06 EA |
621 | |
622 | #define CD_TSZ(x, sel) extract32((x)->word[0], (16 * (sel)) + 0, 6) | |
623 | #define CD_TG(x, sel) extract32((x)->word[0], (16 * (sel)) + 6, 2) | |
624 | #define CD_EPD(x, sel) extract32((x)->word[0], (16 * (sel)) + 14, 1) | |
625 | #define CD_ENDI(x) extract32((x)->word[0], 15, 1) | |
626 | #define CD_IPS(x) extract32((x)->word[1], 0 , 3) | |
627 | #define CD_TBI(x) extract32((x)->word[1], 6 , 2) | |
628 | #define CD_HD(x) extract32((x)->word[1], 10 , 1) | |
629 | #define CD_HA(x) extract32((x)->word[1], 11 , 1) | |
630 | #define CD_S(x) extract32((x)->word[1], 12, 1) | |
631 | #define CD_R(x) extract32((x)->word[1], 13, 1) | |
632 | #define CD_A(x) extract32((x)->word[1], 14, 1) | |
633 | #define CD_AARCH64(x) extract32((x)->word[1], 9 , 1) | |
634 | ||
9bde7f06 EA |
635 | /** |
636 | * tg2granule - Decodes the CD translation granule size field according | |
637 | * to the ttbr in use | |
638 | * @bits: TG0/1 fields | |
639 | * @ttbr: ttbr index in use | |
640 | */ | |
641 | static inline int tg2granule(int bits, int ttbr) | |
642 | { | |
643 | switch (bits) { | |
644 | case 0: | |
645 | return ttbr ? 0 : 12; | |
646 | case 1: | |
647 | return ttbr ? 14 : 16; | |
648 | case 2: | |
649 | return ttbr ? 12 : 14; | |
650 | case 3: | |
651 | return ttbr ? 16 : 0; | |
652 | default: | |
653 | return 0; | |
654 | } | |
655 | } | |
656 | ||
657 | static inline uint64_t l1std_l2ptr(STEDesc *desc) | |
658 | { | |
659 | uint64_t hi, lo; | |
660 | ||
661 | hi = desc->word[1]; | |
662 | lo = desc->word[0] & ~0x1fULL; | |
663 | return hi << 32 | lo; | |
664 | } | |
665 | ||
d9aad887 | 666 | #define L1STD_SPAN(stm) (extract32((stm)->word[0], 0, 5)) |
9bde7f06 | 667 | |
10a83cb9 | 668 | #endif |