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