xref: /qemu/hw/arm/smmuv3-internal.h (revision e7c3b9d9a0ddee7daa9b08bd14bd3ebbcf5f5cd3)
110a83cb9SPrem Mallappa /*
210a83cb9SPrem Mallappa  * ARM SMMUv3 support - Internal API
310a83cb9SPrem Mallappa  *
410a83cb9SPrem Mallappa  * Copyright (C) 2014-2016 Broadcom Corporation
510a83cb9SPrem Mallappa  * Copyright (c) 2017 Red Hat, Inc.
610a83cb9SPrem Mallappa  * Written by Prem Mallappa, Eric Auger
710a83cb9SPrem Mallappa  *
810a83cb9SPrem Mallappa  * This program is free software; you can redistribute it and/or modify
910a83cb9SPrem Mallappa  * it under the terms of the GNU General Public License version 2 as
1010a83cb9SPrem Mallappa  * published by the Free Software Foundation.
1110a83cb9SPrem Mallappa  *
1210a83cb9SPrem Mallappa  * This program is distributed in the hope that it will be useful,
1310a83cb9SPrem Mallappa  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1410a83cb9SPrem Mallappa  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1510a83cb9SPrem Mallappa  * GNU General Public License for more details.
1610a83cb9SPrem Mallappa  *
1710a83cb9SPrem Mallappa  * You should have received a copy of the GNU General Public License along
1810a83cb9SPrem Mallappa  * with this program; if not, see <http://www.gnu.org/licenses/>.
1910a83cb9SPrem Mallappa  */
2010a83cb9SPrem Mallappa 
2158ea30f5SMarkus Armbruster #ifndef HW_ARM_SMMUV3_INTERNAL_H
2258ea30f5SMarkus Armbruster #define HW_ARM_SMMUV3_INTERNAL_H
2310a83cb9SPrem Mallappa 
2410a83cb9SPrem Mallappa #include "hw/arm/smmu-common.h"
2510a83cb9SPrem Mallappa 
269122bea9SJia He typedef enum SMMUTranslationStatus {
279122bea9SJia He     SMMU_TRANS_DISABLE,
289122bea9SJia He     SMMU_TRANS_ABORT,
299122bea9SJia He     SMMU_TRANS_BYPASS,
309122bea9SJia He     SMMU_TRANS_ERROR,
319122bea9SJia He     SMMU_TRANS_SUCCESS,
329122bea9SJia He } SMMUTranslationStatus;
339122bea9SJia He 
3410a83cb9SPrem Mallappa /* MMIO Registers */
3510a83cb9SPrem Mallappa 
3610a83cb9SPrem Mallappa REG32(IDR0,                0x0)
3710a83cb9SPrem Mallappa     FIELD(IDR0, S1P,         1 , 1)
3810a83cb9SPrem Mallappa     FIELD(IDR0, TTF,         2 , 2)
3910a83cb9SPrem Mallappa     FIELD(IDR0, COHACC,      4 , 1)
4010a83cb9SPrem Mallappa     FIELD(IDR0, ASID16,      12, 1)
4110a83cb9SPrem Mallappa     FIELD(IDR0, TTENDIAN,    21, 2)
4210a83cb9SPrem Mallappa     FIELD(IDR0, STALL_MODEL, 24, 2)
4310a83cb9SPrem Mallappa     FIELD(IDR0, TERM_MODEL,  26, 1)
4410a83cb9SPrem Mallappa     FIELD(IDR0, STLEVEL,     27, 2)
4510a83cb9SPrem Mallappa 
4610a83cb9SPrem Mallappa REG32(IDR1,                0x4)
4710a83cb9SPrem Mallappa     FIELD(IDR1, SIDSIZE,      0 , 6)
4810a83cb9SPrem Mallappa     FIELD(IDR1, EVENTQS,      16, 5)
4910a83cb9SPrem Mallappa     FIELD(IDR1, CMDQS,        21, 5)
5010a83cb9SPrem Mallappa 
5110a83cb9SPrem Mallappa #define SMMU_IDR1_SIDSIZE 16
5210a83cb9SPrem Mallappa #define SMMU_CMDQS   19
5310a83cb9SPrem Mallappa #define SMMU_EVENTQS 19
5410a83cb9SPrem Mallappa 
5510a83cb9SPrem Mallappa REG32(IDR2,                0x8)
5610a83cb9SPrem Mallappa REG32(IDR3,                0xc)
57*e7c3b9d9SEric Auger      FIELD(IDR3, HAD,         2, 1);
5810a83cb9SPrem Mallappa REG32(IDR4,                0x10)
5910a83cb9SPrem Mallappa REG32(IDR5,                0x14)
6010a83cb9SPrem Mallappa      FIELD(IDR5, OAS,         0, 3);
6110a83cb9SPrem Mallappa      FIELD(IDR5, GRAN4K,      4, 1);
6210a83cb9SPrem Mallappa      FIELD(IDR5, GRAN16K,     5, 1);
6310a83cb9SPrem Mallappa      FIELD(IDR5, GRAN64K,     6, 1);
6410a83cb9SPrem Mallappa 
6510a83cb9SPrem Mallappa #define SMMU_IDR5_OAS 4
6610a83cb9SPrem Mallappa 
67f0ec277cSEric Auger REG32(IIDR,                0x18)
685888f0adSEric Auger REG32(AIDR,                0x1c)
6910a83cb9SPrem Mallappa REG32(CR0,                 0x20)
7010a83cb9SPrem Mallappa     FIELD(CR0, SMMU_ENABLE,   0, 1)
7110a83cb9SPrem Mallappa     FIELD(CR0, EVENTQEN,      2, 1)
7210a83cb9SPrem Mallappa     FIELD(CR0, CMDQEN,        3, 1)
7310a83cb9SPrem Mallappa 
74fae4be38SEric Auger #define SMMU_CR0_RESERVED 0xFFFFFC20
75fae4be38SEric Auger 
7610a83cb9SPrem Mallappa REG32(CR0ACK,              0x24)
7710a83cb9SPrem Mallappa REG32(CR1,                 0x28)
7810a83cb9SPrem Mallappa REG32(CR2,                 0x2c)
7910a83cb9SPrem Mallappa REG32(STATUSR,             0x40)
8010a83cb9SPrem Mallappa REG32(IRQ_CTRL,            0x50)
8110a83cb9SPrem Mallappa     FIELD(IRQ_CTRL, GERROR_IRQEN,        0, 1)
8210a83cb9SPrem Mallappa     FIELD(IRQ_CTRL, PRI_IRQEN,           1, 1)
8310a83cb9SPrem Mallappa     FIELD(IRQ_CTRL, EVENTQ_IRQEN,        2, 1)
8410a83cb9SPrem Mallappa 
8510a83cb9SPrem Mallappa REG32(IRQ_CTRL_ACK,        0x54)
8610a83cb9SPrem Mallappa REG32(GERROR,              0x60)
8710a83cb9SPrem Mallappa     FIELD(GERROR, CMDQ_ERR,           0, 1)
8810a83cb9SPrem Mallappa     FIELD(GERROR, EVENTQ_ABT_ERR,     2, 1)
8910a83cb9SPrem Mallappa     FIELD(GERROR, PRIQ_ABT_ERR,       3, 1)
9010a83cb9SPrem Mallappa     FIELD(GERROR, MSI_CMDQ_ABT_ERR,   4, 1)
9110a83cb9SPrem Mallappa     FIELD(GERROR, MSI_EVENTQ_ABT_ERR, 5, 1)
9210a83cb9SPrem Mallappa     FIELD(GERROR, MSI_PRIQ_ABT_ERR,   6, 1)
9310a83cb9SPrem Mallappa     FIELD(GERROR, MSI_GERROR_ABT_ERR, 7, 1)
9410a83cb9SPrem Mallappa     FIELD(GERROR, MSI_SFM_ERR,        8, 1)
9510a83cb9SPrem Mallappa 
9610a83cb9SPrem Mallappa REG32(GERRORN,             0x64)
9710a83cb9SPrem Mallappa 
9810a83cb9SPrem Mallappa #define A_GERROR_IRQ_CFG0  0x68 /* 64b */
9910a83cb9SPrem Mallappa REG32(GERROR_IRQ_CFG1, 0x70)
10010a83cb9SPrem Mallappa REG32(GERROR_IRQ_CFG2, 0x74)
10110a83cb9SPrem Mallappa 
10210a83cb9SPrem Mallappa #define A_STRTAB_BASE      0x80 /* 64b */
10310a83cb9SPrem Mallappa 
1043293b9f5SSimon Veith #define SMMU_BASE_ADDR_MASK 0xfffffffffffc0
10510a83cb9SPrem Mallappa 
10610a83cb9SPrem Mallappa REG32(STRTAB_BASE_CFG,     0x88)
10710a83cb9SPrem Mallappa     FIELD(STRTAB_BASE_CFG, FMT,      16, 2)
10810a83cb9SPrem Mallappa     FIELD(STRTAB_BASE_CFG, SPLIT,    6 , 5)
10910a83cb9SPrem Mallappa     FIELD(STRTAB_BASE_CFG, LOG2SIZE, 0 , 6)
11010a83cb9SPrem Mallappa 
11110a83cb9SPrem Mallappa #define A_CMDQ_BASE        0x90 /* 64b */
11210a83cb9SPrem Mallappa REG32(CMDQ_PROD,           0x98)
11310a83cb9SPrem Mallappa REG32(CMDQ_CONS,           0x9c)
11410a83cb9SPrem Mallappa     FIELD(CMDQ_CONS, ERR, 24, 7)
11510a83cb9SPrem Mallappa 
11610a83cb9SPrem Mallappa #define A_EVENTQ_BASE      0xa0 /* 64b */
11710a83cb9SPrem Mallappa REG32(EVENTQ_PROD,         0xa8)
11810a83cb9SPrem Mallappa REG32(EVENTQ_CONS,         0xac)
11910a83cb9SPrem Mallappa 
12010a83cb9SPrem Mallappa #define A_EVENTQ_IRQ_CFG0  0xb0 /* 64b */
12110a83cb9SPrem Mallappa REG32(EVENTQ_IRQ_CFG1,     0xb8)
12210a83cb9SPrem Mallappa REG32(EVENTQ_IRQ_CFG2,     0xbc)
12310a83cb9SPrem Mallappa 
12410a83cb9SPrem Mallappa #define A_IDREGS           0xfd0
12510a83cb9SPrem Mallappa 
12610a83cb9SPrem Mallappa static inline int smmu_enabled(SMMUv3State *s)
12710a83cb9SPrem Mallappa {
12810a83cb9SPrem Mallappa     return FIELD_EX32(s->cr[0], CR0, SMMU_ENABLE);
12910a83cb9SPrem Mallappa }
13010a83cb9SPrem Mallappa 
13110a83cb9SPrem Mallappa /* Command Queue Entry */
13210a83cb9SPrem Mallappa typedef struct Cmd {
13310a83cb9SPrem Mallappa     uint32_t word[4];
13410a83cb9SPrem Mallappa } Cmd;
13510a83cb9SPrem Mallappa 
13610a83cb9SPrem Mallappa /* Event Queue Entry */
13710a83cb9SPrem Mallappa typedef struct Evt  {
13810a83cb9SPrem Mallappa     uint32_t word[8];
13910a83cb9SPrem Mallappa } Evt;
14010a83cb9SPrem Mallappa 
14110a83cb9SPrem Mallappa static inline uint32_t smmuv3_idreg(int regoffset)
14210a83cb9SPrem Mallappa {
14310a83cb9SPrem Mallappa     /*
14410a83cb9SPrem Mallappa      * Return the value of the Primecell/Corelink ID registers at the
14510a83cb9SPrem Mallappa      * specified offset from the first ID register.
14610a83cb9SPrem Mallappa      * These value indicate an ARM implementation of MMU600 p1
14710a83cb9SPrem Mallappa      */
14810a83cb9SPrem Mallappa     static const uint8_t smmuv3_ids[] = {
14910a83cb9SPrem Mallappa         0x04, 0, 0, 0, 0x84, 0xB4, 0xF0, 0x10, 0x0D, 0xF0, 0x05, 0xB1
15010a83cb9SPrem Mallappa     };
15110a83cb9SPrem Mallappa     return smmuv3_ids[regoffset / 4];
15210a83cb9SPrem Mallappa }
15310a83cb9SPrem Mallappa 
1546a736033SEric Auger static inline bool smmuv3_eventq_irq_enabled(SMMUv3State *s)
1556a736033SEric Auger {
1566a736033SEric Auger     return FIELD_EX32(s->irq_ctrl, IRQ_CTRL, EVENTQ_IRQEN);
1576a736033SEric Auger }
1586a736033SEric Auger 
1596a736033SEric Auger static inline bool smmuv3_gerror_irq_enabled(SMMUv3State *s)
1606a736033SEric Auger {
1616a736033SEric Auger     return FIELD_EX32(s->irq_ctrl, IRQ_CTRL, GERROR_IRQEN);
1626a736033SEric Auger }
1636a736033SEric Auger 
164dadd1a08SEric Auger /* Queue Handling */
165dadd1a08SEric Auger 
166dadd1a08SEric Auger #define Q_BASE(q)          ((q)->base & SMMU_BASE_ADDR_MASK)
167dadd1a08SEric Auger #define WRAP_MASK(q)       (1 << (q)->log2size)
168dadd1a08SEric Auger #define INDEX_MASK(q)      (((1 << (q)->log2size)) - 1)
169dadd1a08SEric Auger #define WRAP_INDEX_MASK(q) ((1 << ((q)->log2size + 1)) - 1)
170dadd1a08SEric Auger 
171dadd1a08SEric Auger #define Q_CONS(q) ((q)->cons & INDEX_MASK(q))
172dadd1a08SEric Auger #define Q_PROD(q) ((q)->prod & INDEX_MASK(q))
173dadd1a08SEric Auger 
174dadd1a08SEric Auger #define Q_CONS_ENTRY(q)  (Q_BASE(q) + (q)->entry_size * Q_CONS(q))
175dadd1a08SEric Auger #define Q_PROD_ENTRY(q)  (Q_BASE(q) + (q)->entry_size * Q_PROD(q))
176dadd1a08SEric Auger 
177dadd1a08SEric Auger #define Q_CONS_WRAP(q) (((q)->cons & WRAP_MASK(q)) >> (q)->log2size)
178dadd1a08SEric Auger #define Q_PROD_WRAP(q) (((q)->prod & WRAP_MASK(q)) >> (q)->log2size)
179dadd1a08SEric Auger 
180dadd1a08SEric Auger static inline bool smmuv3_q_full(SMMUQueue *q)
181dadd1a08SEric Auger {
182dadd1a08SEric Auger     return ((q->cons ^ q->prod) & WRAP_INDEX_MASK(q)) == WRAP_MASK(q);
183dadd1a08SEric Auger }
184dadd1a08SEric Auger 
185dadd1a08SEric Auger static inline bool smmuv3_q_empty(SMMUQueue *q)
186dadd1a08SEric Auger {
187dadd1a08SEric Auger     return (q->cons & WRAP_INDEX_MASK(q)) == (q->prod & WRAP_INDEX_MASK(q));
188dadd1a08SEric Auger }
189dadd1a08SEric Auger 
190dadd1a08SEric Auger static inline void queue_prod_incr(SMMUQueue *q)
191dadd1a08SEric Auger {
192dadd1a08SEric Auger     q->prod = (q->prod + 1) & WRAP_INDEX_MASK(q);
193dadd1a08SEric Auger }
194dadd1a08SEric Auger 
195dadd1a08SEric Auger static inline void queue_cons_incr(SMMUQueue *q)
196dadd1a08SEric Auger {
197dadd1a08SEric Auger     /*
198dadd1a08SEric Auger      * We have to use deposit for the CONS registers to preserve
199dadd1a08SEric Auger      * the ERR field in the high bits.
200dadd1a08SEric Auger      */
201dadd1a08SEric Auger     q->cons = deposit32(q->cons, 0, q->log2size + 1, q->cons + 1);
202dadd1a08SEric Auger }
203dadd1a08SEric Auger 
204dadd1a08SEric Auger static inline bool smmuv3_cmdq_enabled(SMMUv3State *s)
205dadd1a08SEric Auger {
206dadd1a08SEric Auger     return FIELD_EX32(s->cr[0], CR0, CMDQEN);
207dadd1a08SEric Auger }
208dadd1a08SEric Auger 
209dadd1a08SEric Auger static inline bool smmuv3_eventq_enabled(SMMUv3State *s)
210dadd1a08SEric Auger {
211dadd1a08SEric Auger     return FIELD_EX32(s->cr[0], CR0, EVENTQEN);
212dadd1a08SEric Auger }
213dadd1a08SEric Auger 
214dadd1a08SEric Auger static inline void smmu_write_cmdq_err(SMMUv3State *s, uint32_t err_type)
215dadd1a08SEric Auger {
216dadd1a08SEric Auger     s->cmdq.cons = FIELD_DP32(s->cmdq.cons, CMDQ_CONS, ERR, err_type);
217dadd1a08SEric Auger }
218dadd1a08SEric Auger 
219dadd1a08SEric Auger /* Commands */
220dadd1a08SEric Auger 
221dadd1a08SEric Auger typedef enum SMMUCommandType {
222dadd1a08SEric Auger     SMMU_CMD_NONE            = 0x00,
223dadd1a08SEric Auger     SMMU_CMD_PREFETCH_CONFIG       ,
224dadd1a08SEric Auger     SMMU_CMD_PREFETCH_ADDR,
225dadd1a08SEric Auger     SMMU_CMD_CFGI_STE,
226dadd1a08SEric Auger     SMMU_CMD_CFGI_STE_RANGE,
227dadd1a08SEric Auger     SMMU_CMD_CFGI_CD,
228dadd1a08SEric Auger     SMMU_CMD_CFGI_CD_ALL,
229dadd1a08SEric Auger     SMMU_CMD_CFGI_ALL,
230dadd1a08SEric Auger     SMMU_CMD_TLBI_NH_ALL     = 0x10,
231dadd1a08SEric Auger     SMMU_CMD_TLBI_NH_ASID,
232dadd1a08SEric Auger     SMMU_CMD_TLBI_NH_VA,
233dadd1a08SEric Auger     SMMU_CMD_TLBI_NH_VAA,
234dadd1a08SEric Auger     SMMU_CMD_TLBI_EL3_ALL    = 0x18,
235dadd1a08SEric Auger     SMMU_CMD_TLBI_EL3_VA     = 0x1a,
236dadd1a08SEric Auger     SMMU_CMD_TLBI_EL2_ALL    = 0x20,
237dadd1a08SEric Auger     SMMU_CMD_TLBI_EL2_ASID,
238dadd1a08SEric Auger     SMMU_CMD_TLBI_EL2_VA,
239dadd1a08SEric Auger     SMMU_CMD_TLBI_EL2_VAA,
240dadd1a08SEric Auger     SMMU_CMD_TLBI_S12_VMALL  = 0x28,
241dadd1a08SEric Auger     SMMU_CMD_TLBI_S2_IPA     = 0x2a,
242dadd1a08SEric Auger     SMMU_CMD_TLBI_NSNH_ALL   = 0x30,
243dadd1a08SEric Auger     SMMU_CMD_ATC_INV         = 0x40,
244dadd1a08SEric Auger     SMMU_CMD_PRI_RESP,
245dadd1a08SEric Auger     SMMU_CMD_RESUME          = 0x44,
246dadd1a08SEric Auger     SMMU_CMD_STALL_TERM,
247dadd1a08SEric Auger     SMMU_CMD_SYNC,
248dadd1a08SEric Auger } SMMUCommandType;
249dadd1a08SEric Auger 
250dadd1a08SEric Auger static const char *cmd_stringify[] = {
251dadd1a08SEric Auger     [SMMU_CMD_PREFETCH_CONFIG] = "SMMU_CMD_PREFETCH_CONFIG",
252dadd1a08SEric Auger     [SMMU_CMD_PREFETCH_ADDR]   = "SMMU_CMD_PREFETCH_ADDR",
253dadd1a08SEric Auger     [SMMU_CMD_CFGI_STE]        = "SMMU_CMD_CFGI_STE",
254dadd1a08SEric Auger     [SMMU_CMD_CFGI_STE_RANGE]  = "SMMU_CMD_CFGI_STE_RANGE",
255dadd1a08SEric Auger     [SMMU_CMD_CFGI_CD]         = "SMMU_CMD_CFGI_CD",
256dadd1a08SEric Auger     [SMMU_CMD_CFGI_CD_ALL]     = "SMMU_CMD_CFGI_CD_ALL",
257dadd1a08SEric Auger     [SMMU_CMD_CFGI_ALL]        = "SMMU_CMD_CFGI_ALL",
258dadd1a08SEric Auger     [SMMU_CMD_TLBI_NH_ALL]     = "SMMU_CMD_TLBI_NH_ALL",
259dadd1a08SEric Auger     [SMMU_CMD_TLBI_NH_ASID]    = "SMMU_CMD_TLBI_NH_ASID",
260dadd1a08SEric Auger     [SMMU_CMD_TLBI_NH_VA]      = "SMMU_CMD_TLBI_NH_VA",
261dadd1a08SEric Auger     [SMMU_CMD_TLBI_NH_VAA]     = "SMMU_CMD_TLBI_NH_VAA",
262dadd1a08SEric Auger     [SMMU_CMD_TLBI_EL3_ALL]    = "SMMU_CMD_TLBI_EL3_ALL",
263dadd1a08SEric Auger     [SMMU_CMD_TLBI_EL3_VA]     = "SMMU_CMD_TLBI_EL3_VA",
264dadd1a08SEric Auger     [SMMU_CMD_TLBI_EL2_ALL]    = "SMMU_CMD_TLBI_EL2_ALL",
265dadd1a08SEric Auger     [SMMU_CMD_TLBI_EL2_ASID]   = "SMMU_CMD_TLBI_EL2_ASID",
266dadd1a08SEric Auger     [SMMU_CMD_TLBI_EL2_VA]     = "SMMU_CMD_TLBI_EL2_VA",
267dadd1a08SEric Auger     [SMMU_CMD_TLBI_EL2_VAA]    = "SMMU_CMD_TLBI_EL2_VAA",
268dadd1a08SEric Auger     [SMMU_CMD_TLBI_S12_VMALL]  = "SMMU_CMD_TLBI_S12_VMALL",
269dadd1a08SEric Auger     [SMMU_CMD_TLBI_S2_IPA]     = "SMMU_CMD_TLBI_S2_IPA",
270dadd1a08SEric Auger     [SMMU_CMD_TLBI_NSNH_ALL]   = "SMMU_CMD_TLBI_NSNH_ALL",
271dadd1a08SEric Auger     [SMMU_CMD_ATC_INV]         = "SMMU_CMD_ATC_INV",
272dadd1a08SEric Auger     [SMMU_CMD_PRI_RESP]        = "SMMU_CMD_PRI_RESP",
273dadd1a08SEric Auger     [SMMU_CMD_RESUME]          = "SMMU_CMD_RESUME",
274dadd1a08SEric Auger     [SMMU_CMD_STALL_TERM]      = "SMMU_CMD_STALL_TERM",
275dadd1a08SEric Auger     [SMMU_CMD_SYNC]            = "SMMU_CMD_SYNC",
276dadd1a08SEric Auger };
277dadd1a08SEric Auger 
278dadd1a08SEric Auger static inline const char *smmu_cmd_string(SMMUCommandType type)
279dadd1a08SEric Auger {
280dadd1a08SEric Auger     if (type > SMMU_CMD_NONE && type < ARRAY_SIZE(cmd_stringify)) {
281dadd1a08SEric Auger         return cmd_stringify[type] ? cmd_stringify[type] : "UNKNOWN";
282dadd1a08SEric Auger     } else {
283dadd1a08SEric Auger         return "INVALID";
284dadd1a08SEric Auger     }
285dadd1a08SEric Auger }
286dadd1a08SEric Auger 
287dadd1a08SEric Auger /* CMDQ fields */
288dadd1a08SEric Auger 
289dadd1a08SEric Auger typedef enum {
290dadd1a08SEric Auger     SMMU_CERROR_NONE = 0,
291dadd1a08SEric Auger     SMMU_CERROR_ILL,
292dadd1a08SEric Auger     SMMU_CERROR_ABT,
293dadd1a08SEric Auger     SMMU_CERROR_ATC_INV_SYNC,
294dadd1a08SEric Auger } SMMUCmdError;
295dadd1a08SEric Auger 
296dadd1a08SEric Auger enum { /* Command completion notification */
297dadd1a08SEric Auger     CMD_SYNC_SIG_NONE,
298dadd1a08SEric Auger     CMD_SYNC_SIG_IRQ,
299dadd1a08SEric Auger     CMD_SYNC_SIG_SEV,
300dadd1a08SEric Auger };
301dadd1a08SEric Auger 
302dadd1a08SEric Auger #define CMD_TYPE(x)         extract32((x)->word[0], 0 , 8)
303d5291561SEric Auger #define CMD_NUM(x)          extract32((x)->word[0], 12 , 5)
304d5291561SEric Auger #define CMD_SCALE(x)        extract32((x)->word[0], 20 , 5)
305dadd1a08SEric Auger #define CMD_SSEC(x)         extract32((x)->word[0], 10, 1)
306dadd1a08SEric Auger #define CMD_SSV(x)          extract32((x)->word[0], 11, 1)
307dadd1a08SEric Auger #define CMD_RESUME_AC(x)    extract32((x)->word[0], 12, 1)
308dadd1a08SEric Auger #define CMD_RESUME_AB(x)    extract32((x)->word[0], 13, 1)
309dadd1a08SEric Auger #define CMD_SYNC_CS(x)      extract32((x)->word[0], 12, 2)
310dadd1a08SEric Auger #define CMD_SSID(x)         extract32((x)->word[0], 12, 20)
311dadd1a08SEric Auger #define CMD_SID(x)          ((x)->word[1])
312dadd1a08SEric Auger #define CMD_VMID(x)         extract32((x)->word[1], 0 , 16)
313dadd1a08SEric Auger #define CMD_ASID(x)         extract32((x)->word[1], 16, 16)
314dadd1a08SEric Auger #define CMD_RESUME_STAG(x)  extract32((x)->word[2], 0 , 16)
315dadd1a08SEric Auger #define CMD_RESP(x)         extract32((x)->word[2], 11, 2)
316dadd1a08SEric Auger #define CMD_LEAF(x)         extract32((x)->word[2], 0 , 1)
317d5291561SEric Auger #define CMD_TTL(x)          extract32((x)->word[2], 8 , 2)
318d5291561SEric Auger #define CMD_TG(x)           extract32((x)->word[2], 10, 2)
319dadd1a08SEric Auger #define CMD_STE_RANGE(x)    extract32((x)->word[2], 0 , 5)
320dadd1a08SEric Auger #define CMD_ADDR(x) ({                                        \
321dadd1a08SEric Auger             uint64_t high = (uint64_t)(x)->word[3];           \
322dadd1a08SEric Auger             uint64_t low = extract32((x)->word[2], 12, 20);    \
323dadd1a08SEric Auger             uint64_t addr = high << 32 | (low << 12);         \
324dadd1a08SEric Auger             addr;                                             \
325dadd1a08SEric Auger         })
326dadd1a08SEric Auger 
327fae4be38SEric Auger #define SMMU_FEATURE_2LVL_STE (1 << 0)
328dadd1a08SEric Auger 
329bb981004SEric Auger /* Events */
330bb981004SEric Auger 
331bb981004SEric Auger typedef enum SMMUEventType {
3329122bea9SJia He     SMMU_EVT_NONE               = 0x00,
333bb981004SEric Auger     SMMU_EVT_F_UUT                    ,
334bb981004SEric Auger     SMMU_EVT_C_BAD_STREAMID           ,
335bb981004SEric Auger     SMMU_EVT_F_STE_FETCH              ,
336bb981004SEric Auger     SMMU_EVT_C_BAD_STE                ,
337bb981004SEric Auger     SMMU_EVT_F_BAD_ATS_TREQ           ,
338bb981004SEric Auger     SMMU_EVT_F_STREAM_DISABLED        ,
339bb981004SEric Auger     SMMU_EVT_F_TRANS_FORBIDDEN        ,
340bb981004SEric Auger     SMMU_EVT_C_BAD_SUBSTREAMID        ,
341bb981004SEric Auger     SMMU_EVT_F_CD_FETCH               ,
342bb981004SEric Auger     SMMU_EVT_C_BAD_CD                 ,
343bb981004SEric Auger     SMMU_EVT_F_WALK_EABT              ,
344bb981004SEric Auger     SMMU_EVT_F_TRANSLATION      = 0x10,
345bb981004SEric Auger     SMMU_EVT_F_ADDR_SIZE              ,
346bb981004SEric Auger     SMMU_EVT_F_ACCESS                 ,
347bb981004SEric Auger     SMMU_EVT_F_PERMISSION             ,
348bb981004SEric Auger     SMMU_EVT_F_TLB_CONFLICT     = 0x20,
349bb981004SEric Auger     SMMU_EVT_F_CFG_CONFLICT           ,
350bb981004SEric Auger     SMMU_EVT_E_PAGE_REQ         = 0x24,
351bb981004SEric Auger } SMMUEventType;
352bb981004SEric Auger 
353bb981004SEric Auger static const char *event_stringify[] = {
3549122bea9SJia He     [SMMU_EVT_NONE]                     = "no recorded event",
355bb981004SEric Auger     [SMMU_EVT_F_UUT]                    = "SMMU_EVT_F_UUT",
356bb981004SEric Auger     [SMMU_EVT_C_BAD_STREAMID]           = "SMMU_EVT_C_BAD_STREAMID",
357bb981004SEric Auger     [SMMU_EVT_F_STE_FETCH]              = "SMMU_EVT_F_STE_FETCH",
358bb981004SEric Auger     [SMMU_EVT_C_BAD_STE]                = "SMMU_EVT_C_BAD_STE",
359bb981004SEric Auger     [SMMU_EVT_F_BAD_ATS_TREQ]           = "SMMU_EVT_F_BAD_ATS_TREQ",
360bb981004SEric Auger     [SMMU_EVT_F_STREAM_DISABLED]        = "SMMU_EVT_F_STREAM_DISABLED",
361bb981004SEric Auger     [SMMU_EVT_F_TRANS_FORBIDDEN]        = "SMMU_EVT_F_TRANS_FORBIDDEN",
362bb981004SEric Auger     [SMMU_EVT_C_BAD_SUBSTREAMID]        = "SMMU_EVT_C_BAD_SUBSTREAMID",
363bb981004SEric Auger     [SMMU_EVT_F_CD_FETCH]               = "SMMU_EVT_F_CD_FETCH",
364bb981004SEric Auger     [SMMU_EVT_C_BAD_CD]                 = "SMMU_EVT_C_BAD_CD",
365bb981004SEric Auger     [SMMU_EVT_F_WALK_EABT]              = "SMMU_EVT_F_WALK_EABT",
366bb981004SEric Auger     [SMMU_EVT_F_TRANSLATION]            = "SMMU_EVT_F_TRANSLATION",
367bb981004SEric Auger     [SMMU_EVT_F_ADDR_SIZE]              = "SMMU_EVT_F_ADDR_SIZE",
368bb981004SEric Auger     [SMMU_EVT_F_ACCESS]                 = "SMMU_EVT_F_ACCESS",
369bb981004SEric Auger     [SMMU_EVT_F_PERMISSION]             = "SMMU_EVT_F_PERMISSION",
370bb981004SEric Auger     [SMMU_EVT_F_TLB_CONFLICT]           = "SMMU_EVT_F_TLB_CONFLICT",
371bb981004SEric Auger     [SMMU_EVT_F_CFG_CONFLICT]           = "SMMU_EVT_F_CFG_CONFLICT",
372bb981004SEric Auger     [SMMU_EVT_E_PAGE_REQ]               = "SMMU_EVT_E_PAGE_REQ",
373bb981004SEric Auger };
374bb981004SEric Auger 
375bb981004SEric Auger static inline const char *smmu_event_string(SMMUEventType type)
376bb981004SEric Auger {
377bb981004SEric Auger     if (type < ARRAY_SIZE(event_stringify)) {
378bb981004SEric Auger         return event_stringify[type] ? event_stringify[type] : "UNKNOWN";
379bb981004SEric Auger     } else {
380bb981004SEric Auger         return "INVALID";
381bb981004SEric Auger     }
382bb981004SEric Auger }
383bb981004SEric Auger 
384bb981004SEric Auger /*  Encode an event record */
385bb981004SEric Auger typedef struct SMMUEventInfo {
386bb981004SEric Auger     SMMUEventType type;
387bb981004SEric Auger     uint32_t sid;
388bb981004SEric Auger     bool recorded;
389bb981004SEric Auger     bool record_trans_faults;
3903499ec08SEric Auger     bool inval_ste_allowed;
391bb981004SEric Auger     union {
392bb981004SEric Auger         struct {
393bb981004SEric Auger             uint32_t ssid;
394bb981004SEric Auger             bool ssv;
395bb981004SEric Auger             dma_addr_t addr;
396bb981004SEric Auger             bool rnw;
397bb981004SEric Auger             bool pnu;
398bb981004SEric Auger             bool ind;
399bb981004SEric Auger        } f_uut;
400bb981004SEric Auger        struct SSIDInfo {
401bb981004SEric Auger             uint32_t ssid;
402bb981004SEric Auger             bool ssv;
403bb981004SEric Auger        } c_bad_streamid;
404bb981004SEric Auger        struct SSIDAddrInfo {
405bb981004SEric Auger             uint32_t ssid;
406bb981004SEric Auger             bool ssv;
407bb981004SEric Auger             dma_addr_t addr;
408bb981004SEric Auger        } f_ste_fetch;
409bb981004SEric Auger        struct SSIDInfo c_bad_ste;
410bb981004SEric Auger        struct {
411bb981004SEric Auger             dma_addr_t addr;
412bb981004SEric Auger             bool rnw;
413bb981004SEric Auger        } f_transl_forbidden;
414bb981004SEric Auger        struct {
415bb981004SEric Auger             uint32_t ssid;
416bb981004SEric Auger        } c_bad_substream;
417bb981004SEric Auger        struct SSIDAddrInfo f_cd_fetch;
418bb981004SEric Auger        struct SSIDInfo c_bad_cd;
419bb981004SEric Auger        struct FullInfo {
420bb981004SEric Auger             bool stall;
421bb981004SEric Auger             uint16_t stag;
422bb981004SEric Auger             uint32_t ssid;
423bb981004SEric Auger             bool ssv;
424bb981004SEric Auger             bool s2;
425bb981004SEric Auger             dma_addr_t addr;
426bb981004SEric Auger             bool rnw;
427bb981004SEric Auger             bool pnu;
428bb981004SEric Auger             bool ind;
429bb981004SEric Auger             uint8_t class;
430bb981004SEric Auger             dma_addr_t addr2;
431bb981004SEric Auger        } f_walk_eabt;
432bb981004SEric Auger        struct FullInfo f_translation;
433bb981004SEric Auger        struct FullInfo f_addr_size;
434bb981004SEric Auger        struct FullInfo f_access;
435bb981004SEric Auger        struct FullInfo f_permission;
436bb981004SEric Auger        struct SSIDInfo f_cfg_conflict;
437bb981004SEric Auger        /**
438bb981004SEric Auger         * not supported yet:
439bb981004SEric Auger         * F_BAD_ATS_TREQ
440bb981004SEric Auger         * F_BAD_ATS_TREQ
441bb981004SEric Auger         * F_TLB_CONFLICT
442bb981004SEric Auger         * E_PAGE_REQUEST
443bb981004SEric Auger         * IMPDEF_EVENTn
444bb981004SEric Auger         */
445bb981004SEric Auger     } u;
446bb981004SEric Auger } SMMUEventInfo;
447bb981004SEric Auger 
448bb981004SEric Auger /* EVTQ fields */
449bb981004SEric Auger 
450bb981004SEric Auger #define EVT_Q_OVERFLOW        (1 << 31)
451bb981004SEric Auger 
4529f4d2a13SEric Auger #define EVT_SET_TYPE(x, v)  ((x)->word[0] = deposit32((x)->word[0], 0 , 8 , v))
4539f4d2a13SEric Auger #define EVT_SET_SSV(x, v)   ((x)->word[0] = deposit32((x)->word[0], 11, 1 , v))
4549f4d2a13SEric Auger #define EVT_SET_SSID(x, v)  ((x)->word[0] = deposit32((x)->word[0], 12, 20, v))
455bb981004SEric Auger #define EVT_SET_SID(x, v)   ((x)->word[1] = v)
4569f4d2a13SEric Auger #define EVT_SET_STAG(x, v)  ((x)->word[2] = deposit32((x)->word[2], 0 , 16, v))
4579f4d2a13SEric Auger #define EVT_SET_STALL(x, v) ((x)->word[2] = deposit32((x)->word[2], 31, 1 , v))
4589f4d2a13SEric Auger #define EVT_SET_PNU(x, v)   ((x)->word[3] = deposit32((x)->word[3], 1 , 1 , v))
4599f4d2a13SEric Auger #define EVT_SET_IND(x, v)   ((x)->word[3] = deposit32((x)->word[3], 2 , 1 , v))
4609f4d2a13SEric Auger #define EVT_SET_RNW(x, v)   ((x)->word[3] = deposit32((x)->word[3], 3 , 1 , v))
4619f4d2a13SEric Auger #define EVT_SET_S2(x, v)    ((x)->word[3] = deposit32((x)->word[3], 7 , 1 , v))
4629f4d2a13SEric Auger #define EVT_SET_CLASS(x, v) ((x)->word[3] = deposit32((x)->word[3], 8 , 2 , v))
463bb981004SEric Auger #define EVT_SET_ADDR(x, addr)                             \
464bb981004SEric Auger     do {                                                  \
465bb981004SEric Auger             (x)->word[5] = (uint32_t)(addr >> 32);        \
466bb981004SEric Auger             (x)->word[4] = (uint32_t)(addr & 0xffffffff); \
467bb981004SEric Auger     } while (0)
468bb981004SEric Auger #define EVT_SET_ADDR2(x, addr)                            \
469bb981004SEric Auger     do {                                                  \
470a7f65cebSSimon Veith             (x)->word[7] = (uint32_t)(addr >> 32);        \
471a7f65cebSSimon Veith             (x)->word[6] = (uint32_t)(addr & 0xffffffff); \
472bb981004SEric Auger     } while (0)
473bb981004SEric Auger 
474bb981004SEric Auger void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *event);
475bb981004SEric Auger 
4769bde7f06SEric Auger /* Configuration Data */
4779bde7f06SEric Auger 
4789bde7f06SEric Auger /* STE Level 1 Descriptor */
4799bde7f06SEric Auger typedef struct STEDesc {
4809bde7f06SEric Auger     uint32_t word[2];
4819bde7f06SEric Auger } STEDesc;
4829bde7f06SEric Auger 
4839bde7f06SEric Auger /* CD Level 1 Descriptor */
4849bde7f06SEric Auger typedef struct CDDesc {
4859bde7f06SEric Auger     uint32_t word[2];
4869bde7f06SEric Auger } CDDesc;
4879bde7f06SEric Auger 
4889bde7f06SEric Auger /* Stream Table Entry(STE) */
4899bde7f06SEric Auger typedef struct STE {
4909bde7f06SEric Auger     uint32_t word[16];
4919bde7f06SEric Auger } STE;
4929bde7f06SEric Auger 
4939bde7f06SEric Auger /* Context Descriptor(CD) */
4949bde7f06SEric Auger typedef struct CD {
4959bde7f06SEric Auger     uint32_t word[16];
4969bde7f06SEric Auger } CD;
4979bde7f06SEric Auger 
4989bde7f06SEric Auger /* STE fields */
4999bde7f06SEric Auger 
5009bde7f06SEric Auger #define STE_VALID(x)   extract32((x)->word[0], 0, 1)
5019bde7f06SEric Auger 
5029bde7f06SEric Auger #define STE_CONFIG(x)  extract32((x)->word[0], 1, 3)
5039bde7f06SEric Auger #define STE_CFG_S1_ENABLED(config) (config & 0x1)
5049bde7f06SEric Auger #define STE_CFG_S2_ENABLED(config) (config & 0x2)
5059bde7f06SEric Auger #define STE_CFG_ABORT(config)      (!(config & 0x4))
5069bde7f06SEric Auger #define STE_CFG_BYPASS(config)     (config == 0x4)
5079bde7f06SEric Auger 
5089bde7f06SEric Auger #define STE_S1FMT(x)       extract32((x)->word[0], 4 , 2)
5099bde7f06SEric Auger #define STE_S1CDMAX(x)     extract32((x)->word[1], 27, 5)
5109bde7f06SEric Auger #define STE_S1STALLD(x)    extract32((x)->word[2], 27, 1)
5119bde7f06SEric Auger #define STE_EATS(x)        extract32((x)->word[2], 28, 2)
5129bde7f06SEric Auger #define STE_STRW(x)        extract32((x)->word[2], 30, 2)
5139bde7f06SEric Auger #define STE_S2VMID(x)      extract32((x)->word[4], 0 , 16)
5149bde7f06SEric Auger #define STE_S2T0SZ(x)      extract32((x)->word[5], 0 , 6)
5159bde7f06SEric Auger #define STE_S2SL0(x)       extract32((x)->word[5], 6 , 2)
5169bde7f06SEric Auger #define STE_S2TG(x)        extract32((x)->word[5], 14, 2)
5179bde7f06SEric Auger #define STE_S2PS(x)        extract32((x)->word[5], 16, 3)
5189bde7f06SEric Auger #define STE_S2AA64(x)      extract32((x)->word[5], 19, 1)
5199bde7f06SEric Auger #define STE_S2HD(x)        extract32((x)->word[5], 24, 1)
5209bde7f06SEric Auger #define STE_S2HA(x)        extract32((x)->word[5], 25, 1)
5219bde7f06SEric Auger #define STE_S2S(x)         extract32((x)->word[5], 26, 1)
5229bde7f06SEric Auger #define STE_CTXPTR(x)                                           \
5239bde7f06SEric Auger     ({                                                          \
5249bde7f06SEric Auger         unsigned long addr;                                     \
5259bde7f06SEric Auger         addr = (uint64_t)extract32((x)->word[1], 0, 16) << 32;  \
5269bde7f06SEric Auger         addr |= (uint64_t)((x)->word[0] & 0xffffffc0);          \
5279bde7f06SEric Auger         addr;                                                   \
5289bde7f06SEric Auger     })
5299bde7f06SEric Auger 
5309bde7f06SEric Auger #define STE_S2TTB(x)                                            \
5319bde7f06SEric Auger     ({                                                          \
5329bde7f06SEric Auger         unsigned long addr;                                     \
5339bde7f06SEric Auger         addr = (uint64_t)extract32((x)->word[7], 0, 16) << 32;  \
5349bde7f06SEric Auger         addr |= (uint64_t)((x)->word[6] & 0xfffffff0);          \
5359bde7f06SEric Auger         addr;                                                   \
5369bde7f06SEric Auger     })
5379bde7f06SEric Auger 
5389bde7f06SEric Auger static inline int oas2bits(int oas_field)
5399bde7f06SEric Auger {
5409bde7f06SEric Auger     switch (oas_field) {
5419bde7f06SEric Auger     case 0:
5429bde7f06SEric Auger         return 32;
5439bde7f06SEric Auger     case 1:
5449bde7f06SEric Auger         return 36;
5459bde7f06SEric Auger     case 2:
5469bde7f06SEric Auger         return 40;
5479bde7f06SEric Auger     case 3:
5489bde7f06SEric Auger         return 42;
5499bde7f06SEric Auger     case 4:
5509bde7f06SEric Auger         return 44;
5519bde7f06SEric Auger     case 5:
5529bde7f06SEric Auger         return 48;
5539bde7f06SEric Auger     }
5549bde7f06SEric Auger     return -1;
5559bde7f06SEric Auger }
5569bde7f06SEric Auger 
5579bde7f06SEric Auger static inline int pa_range(STE *ste)
5589bde7f06SEric Auger {
5599bde7f06SEric Auger     int oas_field = MIN(STE_S2PS(ste), SMMU_IDR5_OAS);
5609bde7f06SEric Auger 
5619bde7f06SEric Auger     if (!STE_S2AA64(ste)) {
5629bde7f06SEric Auger         return 40;
5639bde7f06SEric Auger     }
5649bde7f06SEric Auger 
5659bde7f06SEric Auger     return oas2bits(oas_field);
5669bde7f06SEric Auger }
5679bde7f06SEric Auger 
5689bde7f06SEric Auger #define MAX_PA(ste) ((1 << pa_range(ste)) - 1)
5699bde7f06SEric Auger 
5709bde7f06SEric Auger /* CD fields */
5719bde7f06SEric Auger 
5729bde7f06SEric Auger #define CD_VALID(x)   extract32((x)->word[0], 30, 1)
5739bde7f06SEric Auger #define CD_ASID(x)    extract32((x)->word[1], 16, 16)
5749bde7f06SEric Auger #define CD_TTB(x, sel)                                      \
5759bde7f06SEric Auger     ({                                                      \
5769bde7f06SEric Auger         uint64_t hi, lo;                                    \
5779bde7f06SEric Auger         hi = extract32((x)->word[(sel) * 2 + 3], 0, 19);    \
5789bde7f06SEric Auger         hi <<= 32;                                          \
5799bde7f06SEric Auger         lo = (x)->word[(sel) * 2 + 2] & ~0xfULL;            \
5809bde7f06SEric Auger         hi | lo;                                            \
5819bde7f06SEric Auger     })
582*e7c3b9d9SEric Auger #define CD_HAD(x, sel)   extract32((x)->word[(sel) * 2 + 2], 1, 1)
5839bde7f06SEric Auger 
5849bde7f06SEric Auger #define CD_TSZ(x, sel)   extract32((x)->word[0], (16 * (sel)) + 0, 6)
5859bde7f06SEric Auger #define CD_TG(x, sel)    extract32((x)->word[0], (16 * (sel)) + 6, 2)
5869bde7f06SEric Auger #define CD_EPD(x, sel)   extract32((x)->word[0], (16 * (sel)) + 14, 1)
5879bde7f06SEric Auger #define CD_ENDI(x)       extract32((x)->word[0], 15, 1)
5889bde7f06SEric Auger #define CD_IPS(x)        extract32((x)->word[1], 0 , 3)
5899bde7f06SEric Auger #define CD_TBI(x)        extract32((x)->word[1], 6 , 2)
5909bde7f06SEric Auger #define CD_HD(x)         extract32((x)->word[1], 10 , 1)
5919bde7f06SEric Auger #define CD_HA(x)         extract32((x)->word[1], 11 , 1)
5929bde7f06SEric Auger #define CD_S(x)          extract32((x)->word[1], 12, 1)
5939bde7f06SEric Auger #define CD_R(x)          extract32((x)->word[1], 13, 1)
5949bde7f06SEric Auger #define CD_A(x)          extract32((x)->word[1], 14, 1)
5959bde7f06SEric Auger #define CD_AARCH64(x)    extract32((x)->word[1], 9 , 1)
5969bde7f06SEric Auger 
5979bde7f06SEric Auger #define CDM_VALID(x)    ((x)->word[0] & 0x1)
5989bde7f06SEric Auger 
5999bde7f06SEric Auger static inline int is_cd_valid(SMMUv3State *s, STE *ste, CD *cd)
6009bde7f06SEric Auger {
6019bde7f06SEric Auger     return CD_VALID(cd);
6029bde7f06SEric Auger }
6039bde7f06SEric Auger 
6049bde7f06SEric Auger /**
6059bde7f06SEric Auger  * tg2granule - Decodes the CD translation granule size field according
6069bde7f06SEric Auger  * to the ttbr in use
6079bde7f06SEric Auger  * @bits: TG0/1 fields
6089bde7f06SEric Auger  * @ttbr: ttbr index in use
6099bde7f06SEric Auger  */
6109bde7f06SEric Auger static inline int tg2granule(int bits, int ttbr)
6119bde7f06SEric Auger {
6129bde7f06SEric Auger     switch (bits) {
6139bde7f06SEric Auger     case 0:
6149bde7f06SEric Auger         return ttbr ? 0  : 12;
6159bde7f06SEric Auger     case 1:
6169bde7f06SEric Auger         return ttbr ? 14 : 16;
6179bde7f06SEric Auger     case 2:
6189bde7f06SEric Auger         return ttbr ? 12 : 14;
6199bde7f06SEric Auger     case 3:
6209bde7f06SEric Auger         return ttbr ? 16 :  0;
6219bde7f06SEric Auger     default:
6229bde7f06SEric Auger         return 0;
6239bde7f06SEric Auger     }
6249bde7f06SEric Auger }
6259bde7f06SEric Auger 
6269bde7f06SEric Auger static inline uint64_t l1std_l2ptr(STEDesc *desc)
6279bde7f06SEric Auger {
6289bde7f06SEric Auger     uint64_t hi, lo;
6299bde7f06SEric Auger 
6309bde7f06SEric Auger     hi = desc->word[1];
6319bde7f06SEric Auger     lo = desc->word[0] & ~0x1fULL;
6329bde7f06SEric Auger     return hi << 32 | lo;
6339bde7f06SEric Auger }
6349bde7f06SEric Auger 
6359bde7f06SEric Auger #define L1STD_SPAN(stm) (extract32((stm)->word[0], 0, 4))
6369bde7f06SEric Auger 
63710a83cb9SPrem Mallappa #endif
638