xref: /qemu/hw/intc/arm_gicv3_its.c (revision 7eca39e071fc026f06eb3bbe9257d686f1d7e2e1)
118f6290aSShashi Mallela /*
218f6290aSShashi Mallela  * ITS emulation for a GICv3-based system
318f6290aSShashi Mallela  *
418f6290aSShashi Mallela  * Copyright Linaro.org 2021
518f6290aSShashi Mallela  *
618f6290aSShashi Mallela  * Authors:
718f6290aSShashi Mallela  *  Shashi Mallela <shashi.mallela@linaro.org>
818f6290aSShashi Mallela  *
918f6290aSShashi Mallela  * This work is licensed under the terms of the GNU GPL, version 2 or (at your
1018f6290aSShashi Mallela  * option) any later version.  See the COPYING file in the top-level directory.
1118f6290aSShashi Mallela  *
1218f6290aSShashi Mallela  */
1318f6290aSShashi Mallela 
1418f6290aSShashi Mallela #include "qemu/osdep.h"
1518f6290aSShashi Mallela #include "qemu/log.h"
1618f6290aSShashi Mallela #include "hw/qdev-properties.h"
1718f6290aSShashi Mallela #include "hw/intc/arm_gicv3_its_common.h"
1818f6290aSShashi Mallela #include "gicv3_internal.h"
1918f6290aSShashi Mallela #include "qom/object.h"
2018f6290aSShashi Mallela #include "qapi/error.h"
2118f6290aSShashi Mallela 
2218f6290aSShashi Mallela typedef struct GICv3ITSClass GICv3ITSClass;
2318f6290aSShashi Mallela /* This is reusing the GICv3ITSState typedef from ARM_GICV3_ITS_COMMON */
2418f6290aSShashi Mallela DECLARE_OBJ_CHECKERS(GICv3ITSState, GICv3ITSClass,
2518f6290aSShashi Mallela                      ARM_GICV3_ITS, TYPE_ARM_GICV3_ITS)
2618f6290aSShashi Mallela 
2718f6290aSShashi Mallela struct GICv3ITSClass {
2818f6290aSShashi Mallela     GICv3ITSCommonClass parent_class;
2918f6290aSShashi Mallela     void (*parent_reset)(DeviceState *dev);
3018f6290aSShashi Mallela };
3118f6290aSShashi Mallela 
321b08e436SShashi Mallela static uint64_t baser_base_addr(uint64_t value, uint32_t page_sz)
331b08e436SShashi Mallela {
341b08e436SShashi Mallela     uint64_t result = 0;
351b08e436SShashi Mallela 
361b08e436SShashi Mallela     switch (page_sz) {
371b08e436SShashi Mallela     case GITS_PAGE_SIZE_4K:
381b08e436SShashi Mallela     case GITS_PAGE_SIZE_16K:
391b08e436SShashi Mallela         result = FIELD_EX64(value, GITS_BASER, PHYADDR) << 12;
401b08e436SShashi Mallela         break;
411b08e436SShashi Mallela 
421b08e436SShashi Mallela     case GITS_PAGE_SIZE_64K:
431b08e436SShashi Mallela         result = FIELD_EX64(value, GITS_BASER, PHYADDRL_64K) << 16;
441b08e436SShashi Mallela         result |= FIELD_EX64(value, GITS_BASER, PHYADDRH_64K) << 48;
451b08e436SShashi Mallela         break;
461b08e436SShashi Mallela 
471b08e436SShashi Mallela     default:
481b08e436SShashi Mallela         break;
491b08e436SShashi Mallela     }
501b08e436SShashi Mallela     return result;
511b08e436SShashi Mallela }
521b08e436SShashi Mallela 
53*7eca39e0SShashi Mallela static bool update_cte(GICv3ITSState *s, uint16_t icid, bool valid,
54*7eca39e0SShashi Mallela                        uint64_t rdbase)
55*7eca39e0SShashi Mallela {
56*7eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
57*7eca39e0SShashi Mallela     uint64_t value;
58*7eca39e0SShashi Mallela     uint64_t l2t_addr;
59*7eca39e0SShashi Mallela     bool valid_l2t;
60*7eca39e0SShashi Mallela     uint32_t l2t_id;
61*7eca39e0SShashi Mallela     uint32_t max_l2_entries;
62*7eca39e0SShashi Mallela     uint64_t cte = 0;
63*7eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
64*7eca39e0SShashi Mallela 
65*7eca39e0SShashi Mallela     if (!s->ct.valid) {
66*7eca39e0SShashi Mallela         return true;
67*7eca39e0SShashi Mallela     }
68*7eca39e0SShashi Mallela 
69*7eca39e0SShashi Mallela     if (valid) {
70*7eca39e0SShashi Mallela         /* add mapping entry to collection table */
71*7eca39e0SShashi Mallela         cte = (valid & TABLE_ENTRY_VALID_MASK) | (rdbase << 1ULL);
72*7eca39e0SShashi Mallela     }
73*7eca39e0SShashi Mallela 
74*7eca39e0SShashi Mallela     /*
75*7eca39e0SShashi Mallela      * The specification defines the format of level 1 entries of a
76*7eca39e0SShashi Mallela      * 2-level table, but the format of level 2 entries and the format
77*7eca39e0SShashi Mallela      * of flat-mapped tables is IMPDEF.
78*7eca39e0SShashi Mallela      */
79*7eca39e0SShashi Mallela     if (s->ct.indirect) {
80*7eca39e0SShashi Mallela         l2t_id = icid / (s->ct.page_sz / L1TABLE_ENTRY_SIZE);
81*7eca39e0SShashi Mallela 
82*7eca39e0SShashi Mallela         value = address_space_ldq_le(as,
83*7eca39e0SShashi Mallela                                      s->ct.base_addr +
84*7eca39e0SShashi Mallela                                      (l2t_id * L1TABLE_ENTRY_SIZE),
85*7eca39e0SShashi Mallela                                      MEMTXATTRS_UNSPECIFIED, &res);
86*7eca39e0SShashi Mallela 
87*7eca39e0SShashi Mallela         if (res != MEMTX_OK) {
88*7eca39e0SShashi Mallela             return false;
89*7eca39e0SShashi Mallela         }
90*7eca39e0SShashi Mallela 
91*7eca39e0SShashi Mallela         valid_l2t = (value & L2_TABLE_VALID_MASK) != 0;
92*7eca39e0SShashi Mallela 
93*7eca39e0SShashi Mallela         if (valid_l2t) {
94*7eca39e0SShashi Mallela             max_l2_entries = s->ct.page_sz / s->ct.entry_sz;
95*7eca39e0SShashi Mallela 
96*7eca39e0SShashi Mallela             l2t_addr = value & ((1ULL << 51) - 1);
97*7eca39e0SShashi Mallela 
98*7eca39e0SShashi Mallela             address_space_stq_le(as, l2t_addr +
99*7eca39e0SShashi Mallela                                  ((icid % max_l2_entries) * GITS_CTE_SIZE),
100*7eca39e0SShashi Mallela                                  cte, MEMTXATTRS_UNSPECIFIED, &res);
101*7eca39e0SShashi Mallela         }
102*7eca39e0SShashi Mallela     } else {
103*7eca39e0SShashi Mallela         /* Flat level table */
104*7eca39e0SShashi Mallela         address_space_stq_le(as, s->ct.base_addr + (icid * GITS_CTE_SIZE),
105*7eca39e0SShashi Mallela                              cte, MEMTXATTRS_UNSPECIFIED, &res);
106*7eca39e0SShashi Mallela     }
107*7eca39e0SShashi Mallela     if (res != MEMTX_OK) {
108*7eca39e0SShashi Mallela         return false;
109*7eca39e0SShashi Mallela     } else {
110*7eca39e0SShashi Mallela         return true;
111*7eca39e0SShashi Mallela     }
112*7eca39e0SShashi Mallela }
113*7eca39e0SShashi Mallela 
114*7eca39e0SShashi Mallela static bool process_mapc(GICv3ITSState *s, uint32_t offset)
115*7eca39e0SShashi Mallela {
116*7eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
117*7eca39e0SShashi Mallela     uint16_t icid;
118*7eca39e0SShashi Mallela     uint64_t rdbase;
119*7eca39e0SShashi Mallela     bool valid;
120*7eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
121*7eca39e0SShashi Mallela     bool result = false;
122*7eca39e0SShashi Mallela     uint64_t value;
123*7eca39e0SShashi Mallela 
124*7eca39e0SShashi Mallela     offset += NUM_BYTES_IN_DW;
125*7eca39e0SShashi Mallela     offset += NUM_BYTES_IN_DW;
126*7eca39e0SShashi Mallela 
127*7eca39e0SShashi Mallela     value = address_space_ldq_le(as, s->cq.base_addr + offset,
128*7eca39e0SShashi Mallela                                  MEMTXATTRS_UNSPECIFIED, &res);
129*7eca39e0SShashi Mallela 
130*7eca39e0SShashi Mallela     if (res != MEMTX_OK) {
131*7eca39e0SShashi Mallela         return result;
132*7eca39e0SShashi Mallela     }
133*7eca39e0SShashi Mallela 
134*7eca39e0SShashi Mallela     icid = value & ICID_MASK;
135*7eca39e0SShashi Mallela 
136*7eca39e0SShashi Mallela     rdbase = (value & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
137*7eca39e0SShashi Mallela     rdbase &= RDBASE_PROCNUM_MASK;
138*7eca39e0SShashi Mallela 
139*7eca39e0SShashi Mallela     valid = (value & CMD_FIELD_VALID_MASK);
140*7eca39e0SShashi Mallela 
141*7eca39e0SShashi Mallela     if ((icid > s->ct.maxids.max_collids) || (rdbase > s->gicv3->num_cpu)) {
142*7eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
143*7eca39e0SShashi Mallela                       "ITS MAPC: invalid collection table attributes "
144*7eca39e0SShashi Mallela                       "icid %d rdbase %" PRIu64 "\n",  icid, rdbase);
145*7eca39e0SShashi Mallela         /*
146*7eca39e0SShashi Mallela          * in this implementation, in case of error
147*7eca39e0SShashi Mallela          * we ignore this command and move onto the next
148*7eca39e0SShashi Mallela          * command in the queue
149*7eca39e0SShashi Mallela          */
150*7eca39e0SShashi Mallela     } else {
151*7eca39e0SShashi Mallela         result = update_cte(s, icid, valid, rdbase);
152*7eca39e0SShashi Mallela     }
153*7eca39e0SShashi Mallela 
154*7eca39e0SShashi Mallela     return result;
155*7eca39e0SShashi Mallela }
156*7eca39e0SShashi Mallela 
157*7eca39e0SShashi Mallela static bool update_dte(GICv3ITSState *s, uint32_t devid, bool valid,
158*7eca39e0SShashi Mallela                        uint8_t size, uint64_t itt_addr)
159*7eca39e0SShashi Mallela {
160*7eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
161*7eca39e0SShashi Mallela     uint64_t value;
162*7eca39e0SShashi Mallela     uint64_t l2t_addr;
163*7eca39e0SShashi Mallela     bool valid_l2t;
164*7eca39e0SShashi Mallela     uint32_t l2t_id;
165*7eca39e0SShashi Mallela     uint32_t max_l2_entries;
166*7eca39e0SShashi Mallela     uint64_t dte = 0;
167*7eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
168*7eca39e0SShashi Mallela 
169*7eca39e0SShashi Mallela     if (s->dt.valid) {
170*7eca39e0SShashi Mallela         if (valid) {
171*7eca39e0SShashi Mallela             /* add mapping entry to device table */
172*7eca39e0SShashi Mallela             dte = (valid & TABLE_ENTRY_VALID_MASK) |
173*7eca39e0SShashi Mallela                   ((size & SIZE_MASK) << 1U) |
174*7eca39e0SShashi Mallela                   (itt_addr << GITS_DTE_ITTADDR_SHIFT);
175*7eca39e0SShashi Mallela         }
176*7eca39e0SShashi Mallela     } else {
177*7eca39e0SShashi Mallela         return true;
178*7eca39e0SShashi Mallela     }
179*7eca39e0SShashi Mallela 
180*7eca39e0SShashi Mallela     /*
181*7eca39e0SShashi Mallela      * The specification defines the format of level 1 entries of a
182*7eca39e0SShashi Mallela      * 2-level table, but the format of level 2 entries and the format
183*7eca39e0SShashi Mallela      * of flat-mapped tables is IMPDEF.
184*7eca39e0SShashi Mallela      */
185*7eca39e0SShashi Mallela     if (s->dt.indirect) {
186*7eca39e0SShashi Mallela         l2t_id = devid / (s->dt.page_sz / L1TABLE_ENTRY_SIZE);
187*7eca39e0SShashi Mallela 
188*7eca39e0SShashi Mallela         value = address_space_ldq_le(as,
189*7eca39e0SShashi Mallela                                      s->dt.base_addr +
190*7eca39e0SShashi Mallela                                      (l2t_id * L1TABLE_ENTRY_SIZE),
191*7eca39e0SShashi Mallela                                      MEMTXATTRS_UNSPECIFIED, &res);
192*7eca39e0SShashi Mallela 
193*7eca39e0SShashi Mallela         if (res != MEMTX_OK) {
194*7eca39e0SShashi Mallela             return false;
195*7eca39e0SShashi Mallela         }
196*7eca39e0SShashi Mallela 
197*7eca39e0SShashi Mallela         valid_l2t = (value & L2_TABLE_VALID_MASK) != 0;
198*7eca39e0SShashi Mallela 
199*7eca39e0SShashi Mallela         if (valid_l2t) {
200*7eca39e0SShashi Mallela             max_l2_entries = s->dt.page_sz / s->dt.entry_sz;
201*7eca39e0SShashi Mallela 
202*7eca39e0SShashi Mallela             l2t_addr = value & ((1ULL << 51) - 1);
203*7eca39e0SShashi Mallela 
204*7eca39e0SShashi Mallela             address_space_stq_le(as, l2t_addr +
205*7eca39e0SShashi Mallela                                  ((devid % max_l2_entries) * GITS_DTE_SIZE),
206*7eca39e0SShashi Mallela                                  dte, MEMTXATTRS_UNSPECIFIED, &res);
207*7eca39e0SShashi Mallela         }
208*7eca39e0SShashi Mallela     } else {
209*7eca39e0SShashi Mallela         /* Flat level table */
210*7eca39e0SShashi Mallela         address_space_stq_le(as, s->dt.base_addr + (devid * GITS_DTE_SIZE),
211*7eca39e0SShashi Mallela                              dte, MEMTXATTRS_UNSPECIFIED, &res);
212*7eca39e0SShashi Mallela     }
213*7eca39e0SShashi Mallela     if (res != MEMTX_OK) {
214*7eca39e0SShashi Mallela         return false;
215*7eca39e0SShashi Mallela     } else {
216*7eca39e0SShashi Mallela         return true;
217*7eca39e0SShashi Mallela     }
218*7eca39e0SShashi Mallela }
219*7eca39e0SShashi Mallela 
220*7eca39e0SShashi Mallela static bool process_mapd(GICv3ITSState *s, uint64_t value, uint32_t offset)
221*7eca39e0SShashi Mallela {
222*7eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
223*7eca39e0SShashi Mallela     uint32_t devid;
224*7eca39e0SShashi Mallela     uint8_t size;
225*7eca39e0SShashi Mallela     uint64_t itt_addr;
226*7eca39e0SShashi Mallela     bool valid;
227*7eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
228*7eca39e0SShashi Mallela     bool result = false;
229*7eca39e0SShashi Mallela 
230*7eca39e0SShashi Mallela     devid = ((value & DEVID_MASK) >> DEVID_SHIFT);
231*7eca39e0SShashi Mallela 
232*7eca39e0SShashi Mallela     offset += NUM_BYTES_IN_DW;
233*7eca39e0SShashi Mallela     value = address_space_ldq_le(as, s->cq.base_addr + offset,
234*7eca39e0SShashi Mallela                                  MEMTXATTRS_UNSPECIFIED, &res);
235*7eca39e0SShashi Mallela 
236*7eca39e0SShashi Mallela     if (res != MEMTX_OK) {
237*7eca39e0SShashi Mallela         return result;
238*7eca39e0SShashi Mallela     }
239*7eca39e0SShashi Mallela 
240*7eca39e0SShashi Mallela     size = (value & SIZE_MASK);
241*7eca39e0SShashi Mallela 
242*7eca39e0SShashi Mallela     offset += NUM_BYTES_IN_DW;
243*7eca39e0SShashi Mallela     value = address_space_ldq_le(as, s->cq.base_addr + offset,
244*7eca39e0SShashi Mallela                                  MEMTXATTRS_UNSPECIFIED, &res);
245*7eca39e0SShashi Mallela 
246*7eca39e0SShashi Mallela     if (res != MEMTX_OK) {
247*7eca39e0SShashi Mallela         return result;
248*7eca39e0SShashi Mallela     }
249*7eca39e0SShashi Mallela 
250*7eca39e0SShashi Mallela     itt_addr = (value & ITTADDR_MASK) >> ITTADDR_SHIFT;
251*7eca39e0SShashi Mallela 
252*7eca39e0SShashi Mallela     valid = (value & CMD_FIELD_VALID_MASK);
253*7eca39e0SShashi Mallela 
254*7eca39e0SShashi Mallela     if ((devid > s->dt.maxids.max_devids) ||
255*7eca39e0SShashi Mallela         (size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS))) {
256*7eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
257*7eca39e0SShashi Mallela                       "ITS MAPD: invalid device table attributes "
258*7eca39e0SShashi Mallela                       "devid %d or size %d\n", devid, size);
259*7eca39e0SShashi Mallela         /*
260*7eca39e0SShashi Mallela          * in this implementation, in case of error
261*7eca39e0SShashi Mallela          * we ignore this command and move onto the next
262*7eca39e0SShashi Mallela          * command in the queue
263*7eca39e0SShashi Mallela          */
264*7eca39e0SShashi Mallela     } else {
265*7eca39e0SShashi Mallela         result = update_dte(s, devid, valid, size, itt_addr);
266*7eca39e0SShashi Mallela     }
267*7eca39e0SShashi Mallela 
268*7eca39e0SShashi Mallela     return result;
269*7eca39e0SShashi Mallela }
270*7eca39e0SShashi Mallela 
271*7eca39e0SShashi Mallela /*
272*7eca39e0SShashi Mallela  * Current implementation blocks until all
273*7eca39e0SShashi Mallela  * commands are processed
274*7eca39e0SShashi Mallela  */
275*7eca39e0SShashi Mallela static void process_cmdq(GICv3ITSState *s)
276*7eca39e0SShashi Mallela {
277*7eca39e0SShashi Mallela     uint32_t wr_offset = 0;
278*7eca39e0SShashi Mallela     uint32_t rd_offset = 0;
279*7eca39e0SShashi Mallela     uint32_t cq_offset = 0;
280*7eca39e0SShashi Mallela     uint64_t data;
281*7eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
282*7eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
283*7eca39e0SShashi Mallela     bool result = true;
284*7eca39e0SShashi Mallela     uint8_t cmd;
285*7eca39e0SShashi Mallela 
286*7eca39e0SShashi Mallela     if (!(s->ctlr & ITS_CTLR_ENABLED)) {
287*7eca39e0SShashi Mallela         return;
288*7eca39e0SShashi Mallela     }
289*7eca39e0SShashi Mallela 
290*7eca39e0SShashi Mallela     wr_offset = FIELD_EX64(s->cwriter, GITS_CWRITER, OFFSET);
291*7eca39e0SShashi Mallela 
292*7eca39e0SShashi Mallela     if (wr_offset > s->cq.max_entries) {
293*7eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
294*7eca39e0SShashi Mallela                       "%s: invalid write offset "
295*7eca39e0SShashi Mallela                       "%d\n", __func__, wr_offset);
296*7eca39e0SShashi Mallela         return;
297*7eca39e0SShashi Mallela     }
298*7eca39e0SShashi Mallela 
299*7eca39e0SShashi Mallela     rd_offset = FIELD_EX64(s->creadr, GITS_CREADR, OFFSET);
300*7eca39e0SShashi Mallela 
301*7eca39e0SShashi Mallela     if (rd_offset > s->cq.max_entries) {
302*7eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
303*7eca39e0SShashi Mallela                       "%s: invalid read offset "
304*7eca39e0SShashi Mallela                       "%d\n", __func__, rd_offset);
305*7eca39e0SShashi Mallela         return;
306*7eca39e0SShashi Mallela     }
307*7eca39e0SShashi Mallela 
308*7eca39e0SShashi Mallela     while (wr_offset != rd_offset) {
309*7eca39e0SShashi Mallela         cq_offset = (rd_offset * GITS_CMDQ_ENTRY_SIZE);
310*7eca39e0SShashi Mallela         data = address_space_ldq_le(as, s->cq.base_addr + cq_offset,
311*7eca39e0SShashi Mallela                                     MEMTXATTRS_UNSPECIFIED, &res);
312*7eca39e0SShashi Mallela         if (res != MEMTX_OK) {
313*7eca39e0SShashi Mallela             result = false;
314*7eca39e0SShashi Mallela         }
315*7eca39e0SShashi Mallela         cmd = (data & CMD_MASK);
316*7eca39e0SShashi Mallela 
317*7eca39e0SShashi Mallela         switch (cmd) {
318*7eca39e0SShashi Mallela         case GITS_CMD_INT:
319*7eca39e0SShashi Mallela             break;
320*7eca39e0SShashi Mallela         case GITS_CMD_CLEAR:
321*7eca39e0SShashi Mallela             break;
322*7eca39e0SShashi Mallela         case GITS_CMD_SYNC:
323*7eca39e0SShashi Mallela             /*
324*7eca39e0SShashi Mallela              * Current implementation makes a blocking synchronous call
325*7eca39e0SShashi Mallela              * for every command issued earlier, hence the internal state
326*7eca39e0SShashi Mallela              * is already consistent by the time SYNC command is executed.
327*7eca39e0SShashi Mallela              * Hence no further processing is required for SYNC command.
328*7eca39e0SShashi Mallela              */
329*7eca39e0SShashi Mallela             break;
330*7eca39e0SShashi Mallela         case GITS_CMD_MAPD:
331*7eca39e0SShashi Mallela             result = process_mapd(s, data, cq_offset);
332*7eca39e0SShashi Mallela             break;
333*7eca39e0SShashi Mallela         case GITS_CMD_MAPC:
334*7eca39e0SShashi Mallela             result = process_mapc(s, cq_offset);
335*7eca39e0SShashi Mallela             break;
336*7eca39e0SShashi Mallela         case GITS_CMD_MAPTI:
337*7eca39e0SShashi Mallela             break;
338*7eca39e0SShashi Mallela         case GITS_CMD_MAPI:
339*7eca39e0SShashi Mallela             break;
340*7eca39e0SShashi Mallela         case GITS_CMD_DISCARD:
341*7eca39e0SShashi Mallela             break;
342*7eca39e0SShashi Mallela         case GITS_CMD_INV:
343*7eca39e0SShashi Mallela         case GITS_CMD_INVALL:
344*7eca39e0SShashi Mallela             break;
345*7eca39e0SShashi Mallela         default:
346*7eca39e0SShashi Mallela             break;
347*7eca39e0SShashi Mallela         }
348*7eca39e0SShashi Mallela         if (result) {
349*7eca39e0SShashi Mallela             rd_offset++;
350*7eca39e0SShashi Mallela             rd_offset %= s->cq.max_entries;
351*7eca39e0SShashi Mallela             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, OFFSET, rd_offset);
352*7eca39e0SShashi Mallela         } else {
353*7eca39e0SShashi Mallela             /*
354*7eca39e0SShashi Mallela              * in this implementation, in case of dma read/write error
355*7eca39e0SShashi Mallela              * we stall the command processing
356*7eca39e0SShashi Mallela              */
357*7eca39e0SShashi Mallela             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
358*7eca39e0SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
359*7eca39e0SShashi Mallela                           "%s: %x cmd processing failed\n", __func__, cmd);
360*7eca39e0SShashi Mallela             break;
361*7eca39e0SShashi Mallela         }
362*7eca39e0SShashi Mallela     }
363*7eca39e0SShashi Mallela }
364*7eca39e0SShashi Mallela 
3651b08e436SShashi Mallela /*
3661b08e436SShashi Mallela  * This function extracts the ITS Device and Collection table specific
3671b08e436SShashi Mallela  * parameters (like base_addr, size etc) from GITS_BASER register.
3681b08e436SShashi Mallela  * It is called during ITS enable and also during post_load migration
3691b08e436SShashi Mallela  */
3701b08e436SShashi Mallela static void extract_table_params(GICv3ITSState *s)
3711b08e436SShashi Mallela {
3721b08e436SShashi Mallela     uint16_t num_pages = 0;
3731b08e436SShashi Mallela     uint8_t  page_sz_type;
3741b08e436SShashi Mallela     uint8_t type;
3751b08e436SShashi Mallela     uint32_t page_sz = 0;
3761b08e436SShashi Mallela     uint64_t value;
3771b08e436SShashi Mallela 
3781b08e436SShashi Mallela     for (int i = 0; i < 8; i++) {
3791b08e436SShashi Mallela         value = s->baser[i];
3801b08e436SShashi Mallela 
3811b08e436SShashi Mallela         if (!value) {
3821b08e436SShashi Mallela             continue;
3831b08e436SShashi Mallela         }
3841b08e436SShashi Mallela 
3851b08e436SShashi Mallela         page_sz_type = FIELD_EX64(value, GITS_BASER, PAGESIZE);
3861b08e436SShashi Mallela 
3871b08e436SShashi Mallela         switch (page_sz_type) {
3881b08e436SShashi Mallela         case 0:
3891b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_4K;
3901b08e436SShashi Mallela             break;
3911b08e436SShashi Mallela 
3921b08e436SShashi Mallela         case 1:
3931b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_16K;
3941b08e436SShashi Mallela             break;
3951b08e436SShashi Mallela 
3961b08e436SShashi Mallela         case 2:
3971b08e436SShashi Mallela         case 3:
3981b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_64K;
3991b08e436SShashi Mallela             break;
4001b08e436SShashi Mallela 
4011b08e436SShashi Mallela         default:
4021b08e436SShashi Mallela             g_assert_not_reached();
4031b08e436SShashi Mallela         }
4041b08e436SShashi Mallela 
4051b08e436SShashi Mallela         num_pages = FIELD_EX64(value, GITS_BASER, SIZE) + 1;
4061b08e436SShashi Mallela 
4071b08e436SShashi Mallela         type = FIELD_EX64(value, GITS_BASER, TYPE);
4081b08e436SShashi Mallela 
4091b08e436SShashi Mallela         switch (type) {
4101b08e436SShashi Mallela 
4111b08e436SShashi Mallela         case GITS_BASER_TYPE_DEVICE:
4121b08e436SShashi Mallela             memset(&s->dt, 0 , sizeof(s->dt));
4131b08e436SShashi Mallela             s->dt.valid = FIELD_EX64(value, GITS_BASER, VALID);
4141b08e436SShashi Mallela 
4151b08e436SShashi Mallela             if (!s->dt.valid) {
4161b08e436SShashi Mallela                 return;
4171b08e436SShashi Mallela             }
4181b08e436SShashi Mallela 
4191b08e436SShashi Mallela             s->dt.page_sz = page_sz;
4201b08e436SShashi Mallela             s->dt.indirect = FIELD_EX64(value, GITS_BASER, INDIRECT);
4211b08e436SShashi Mallela             s->dt.entry_sz = FIELD_EX64(value, GITS_BASER, ENTRYSIZE);
4221b08e436SShashi Mallela 
4231b08e436SShashi Mallela             if (!s->dt.indirect) {
4241b08e436SShashi Mallela                 s->dt.max_entries = (num_pages * page_sz) / s->dt.entry_sz;
4251b08e436SShashi Mallela             } else {
4261b08e436SShashi Mallela                 s->dt.max_entries = (((num_pages * page_sz) /
4271b08e436SShashi Mallela                                      L1TABLE_ENTRY_SIZE) *
4281b08e436SShashi Mallela                                      (page_sz / s->dt.entry_sz));
4291b08e436SShashi Mallela             }
4301b08e436SShashi Mallela 
4311b08e436SShashi Mallela             s->dt.maxids.max_devids = (1UL << (FIELD_EX64(s->typer, GITS_TYPER,
4321b08e436SShashi Mallela                                        DEVBITS) + 1));
4331b08e436SShashi Mallela 
4341b08e436SShashi Mallela             s->dt.base_addr = baser_base_addr(value, page_sz);
4351b08e436SShashi Mallela 
4361b08e436SShashi Mallela             break;
4371b08e436SShashi Mallela 
4381b08e436SShashi Mallela         case GITS_BASER_TYPE_COLLECTION:
4391b08e436SShashi Mallela             memset(&s->ct, 0 , sizeof(s->ct));
4401b08e436SShashi Mallela             s->ct.valid = FIELD_EX64(value, GITS_BASER, VALID);
4411b08e436SShashi Mallela 
4421b08e436SShashi Mallela             /*
4431b08e436SShashi Mallela              * GITS_TYPER.HCC is 0 for this implementation
4441b08e436SShashi Mallela              * hence writes are discarded if ct.valid is 0
4451b08e436SShashi Mallela              */
4461b08e436SShashi Mallela             if (!s->ct.valid) {
4471b08e436SShashi Mallela                 return;
4481b08e436SShashi Mallela             }
4491b08e436SShashi Mallela 
4501b08e436SShashi Mallela             s->ct.page_sz = page_sz;
4511b08e436SShashi Mallela             s->ct.indirect = FIELD_EX64(value, GITS_BASER, INDIRECT);
4521b08e436SShashi Mallela             s->ct.entry_sz = FIELD_EX64(value, GITS_BASER, ENTRYSIZE);
4531b08e436SShashi Mallela 
4541b08e436SShashi Mallela             if (!s->ct.indirect) {
4551b08e436SShashi Mallela                 s->ct.max_entries = (num_pages * page_sz) / s->ct.entry_sz;
4561b08e436SShashi Mallela             } else {
4571b08e436SShashi Mallela                 s->ct.max_entries = (((num_pages * page_sz) /
4581b08e436SShashi Mallela                                      L1TABLE_ENTRY_SIZE) *
4591b08e436SShashi Mallela                                      (page_sz / s->ct.entry_sz));
4601b08e436SShashi Mallela             }
4611b08e436SShashi Mallela 
4621b08e436SShashi Mallela             if (FIELD_EX64(s->typer, GITS_TYPER, CIL)) {
4631b08e436SShashi Mallela                 s->ct.maxids.max_collids = (1UL << (FIELD_EX64(s->typer,
4641b08e436SShashi Mallela                                             GITS_TYPER, CIDBITS) + 1));
4651b08e436SShashi Mallela             } else {
4661b08e436SShashi Mallela                 /* 16-bit CollectionId supported when CIL == 0 */
4671b08e436SShashi Mallela                 s->ct.maxids.max_collids = (1UL << 16);
4681b08e436SShashi Mallela             }
4691b08e436SShashi Mallela 
4701b08e436SShashi Mallela             s->ct.base_addr = baser_base_addr(value, page_sz);
4711b08e436SShashi Mallela 
4721b08e436SShashi Mallela             break;
4731b08e436SShashi Mallela 
4741b08e436SShashi Mallela         default:
4751b08e436SShashi Mallela             break;
4761b08e436SShashi Mallela         }
4771b08e436SShashi Mallela     }
4781b08e436SShashi Mallela }
4791b08e436SShashi Mallela 
4801b08e436SShashi Mallela static void extract_cmdq_params(GICv3ITSState *s)
4811b08e436SShashi Mallela {
4821b08e436SShashi Mallela     uint16_t num_pages = 0;
4831b08e436SShashi Mallela     uint64_t value = s->cbaser;
4841b08e436SShashi Mallela 
4851b08e436SShashi Mallela     num_pages = FIELD_EX64(value, GITS_CBASER, SIZE) + 1;
4861b08e436SShashi Mallela 
4871b08e436SShashi Mallela     memset(&s->cq, 0 , sizeof(s->cq));
4881b08e436SShashi Mallela     s->cq.valid = FIELD_EX64(value, GITS_CBASER, VALID);
4891b08e436SShashi Mallela 
4901b08e436SShashi Mallela     if (s->cq.valid) {
4911b08e436SShashi Mallela         s->cq.max_entries = (num_pages * GITS_PAGE_SIZE_4K) /
4921b08e436SShashi Mallela                              GITS_CMDQ_ENTRY_SIZE;
4931b08e436SShashi Mallela         s->cq.base_addr = FIELD_EX64(value, GITS_CBASER, PHYADDR);
4941b08e436SShashi Mallela         s->cq.base_addr <<= R_GITS_CBASER_PHYADDR_SHIFT;
4951b08e436SShashi Mallela     }
4961b08e436SShashi Mallela }
4971b08e436SShashi Mallela 
49818f6290aSShashi Mallela static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
49918f6290aSShashi Mallela                                                uint64_t data, unsigned size,
50018f6290aSShashi Mallela                                                MemTxAttrs attrs)
50118f6290aSShashi Mallela {
50218f6290aSShashi Mallela     return MEMTX_OK;
50318f6290aSShashi Mallela }
50418f6290aSShashi Mallela 
50518f6290aSShashi Mallela static bool its_writel(GICv3ITSState *s, hwaddr offset,
50618f6290aSShashi Mallela                               uint64_t value, MemTxAttrs attrs)
50718f6290aSShashi Mallela {
50818f6290aSShashi Mallela     bool result = true;
5091b08e436SShashi Mallela     int index;
51018f6290aSShashi Mallela 
5111b08e436SShashi Mallela     switch (offset) {
5121b08e436SShashi Mallela     case GITS_CTLR:
5131b08e436SShashi Mallela         s->ctlr |= (value & ~(s->ctlr));
5141b08e436SShashi Mallela 
5151b08e436SShashi Mallela         if (s->ctlr & ITS_CTLR_ENABLED) {
5161b08e436SShashi Mallela             extract_table_params(s);
5171b08e436SShashi Mallela             extract_cmdq_params(s);
5181b08e436SShashi Mallela             s->creadr = 0;
519*7eca39e0SShashi Mallela             process_cmdq(s);
5201b08e436SShashi Mallela         }
5211b08e436SShashi Mallela         break;
5221b08e436SShashi Mallela     case GITS_CBASER:
5231b08e436SShashi Mallela         /*
5241b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
5251b08e436SShashi Mallela          *                 already enabled
5261b08e436SShashi Mallela          */
5271b08e436SShashi Mallela         if (!(s->ctlr & ITS_CTLR_ENABLED)) {
5281b08e436SShashi Mallela             s->cbaser = deposit64(s->cbaser, 0, 32, value);
5291b08e436SShashi Mallela             s->creadr = 0;
5301b08e436SShashi Mallela             s->cwriter = s->creadr;
5311b08e436SShashi Mallela         }
5321b08e436SShashi Mallela         break;
5331b08e436SShashi Mallela     case GITS_CBASER + 4:
5341b08e436SShashi Mallela         /*
5351b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
5361b08e436SShashi Mallela          *                 already enabled
5371b08e436SShashi Mallela          */
5381b08e436SShashi Mallela         if (!(s->ctlr & ITS_CTLR_ENABLED)) {
5391b08e436SShashi Mallela             s->cbaser = deposit64(s->cbaser, 32, 32, value);
5401b08e436SShashi Mallela             s->creadr = 0;
5411b08e436SShashi Mallela             s->cwriter = s->creadr;
5421b08e436SShashi Mallela         }
5431b08e436SShashi Mallela         break;
5441b08e436SShashi Mallela     case GITS_CWRITER:
5451b08e436SShashi Mallela         s->cwriter = deposit64(s->cwriter, 0, 32,
5461b08e436SShashi Mallela                                (value & ~R_GITS_CWRITER_RETRY_MASK));
547*7eca39e0SShashi Mallela         if (s->cwriter != s->creadr) {
548*7eca39e0SShashi Mallela             process_cmdq(s);
549*7eca39e0SShashi Mallela         }
5501b08e436SShashi Mallela         break;
5511b08e436SShashi Mallela     case GITS_CWRITER + 4:
5521b08e436SShashi Mallela         s->cwriter = deposit64(s->cwriter, 32, 32, value);
5531b08e436SShashi Mallela         break;
5541b08e436SShashi Mallela     case GITS_CREADR:
5551b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
5561b08e436SShashi Mallela             s->creadr = deposit64(s->creadr, 0, 32,
5571b08e436SShashi Mallela                                   (value & ~R_GITS_CREADR_STALLED_MASK));
5581b08e436SShashi Mallela         } else {
5591b08e436SShashi Mallela             /* RO register, ignore the write */
5601b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
5611b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
5621b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
5631b08e436SShashi Mallela         }
5641b08e436SShashi Mallela         break;
5651b08e436SShashi Mallela     case GITS_CREADR + 4:
5661b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
5671b08e436SShashi Mallela             s->creadr = deposit64(s->creadr, 32, 32, value);
5681b08e436SShashi Mallela         } else {
5691b08e436SShashi Mallela             /* RO register, ignore the write */
5701b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
5711b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
5721b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
5731b08e436SShashi Mallela         }
5741b08e436SShashi Mallela         break;
5751b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
5761b08e436SShashi Mallela         /*
5771b08e436SShashi Mallela          * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
5781b08e436SShashi Mallela          *                 already enabled
5791b08e436SShashi Mallela          */
5801b08e436SShashi Mallela         if (!(s->ctlr & ITS_CTLR_ENABLED)) {
5811b08e436SShashi Mallela             index = (offset - GITS_BASER) / 8;
5821b08e436SShashi Mallela 
5831b08e436SShashi Mallela             if (offset & 7) {
5841b08e436SShashi Mallela                 value <<= 32;
5851b08e436SShashi Mallela                 value &= ~GITS_BASER_RO_MASK;
5861b08e436SShashi Mallela                 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(0, 32);
5871b08e436SShashi Mallela                 s->baser[index] |= value;
5881b08e436SShashi Mallela             } else {
5891b08e436SShashi Mallela                 value &= ~GITS_BASER_RO_MASK;
5901b08e436SShashi Mallela                 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(32, 32);
5911b08e436SShashi Mallela                 s->baser[index] |= value;
5921b08e436SShashi Mallela             }
5931b08e436SShashi Mallela         }
5941b08e436SShashi Mallela         break;
5951b08e436SShashi Mallela     case GITS_IIDR:
5961b08e436SShashi Mallela     case GITS_IDREGS ... GITS_IDREGS + 0x2f:
5971b08e436SShashi Mallela         /* RO registers, ignore the write */
5981b08e436SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
5991b08e436SShashi Mallela                       "%s: invalid guest write to RO register at offset "
6001b08e436SShashi Mallela                       TARGET_FMT_plx "\n", __func__, offset);
6011b08e436SShashi Mallela         break;
6021b08e436SShashi Mallela     default:
6031b08e436SShashi Mallela         result = false;
6041b08e436SShashi Mallela         break;
6051b08e436SShashi Mallela     }
60618f6290aSShashi Mallela     return result;
60718f6290aSShashi Mallela }
60818f6290aSShashi Mallela 
60918f6290aSShashi Mallela static bool its_readl(GICv3ITSState *s, hwaddr offset,
61018f6290aSShashi Mallela                              uint64_t *data, MemTxAttrs attrs)
61118f6290aSShashi Mallela {
61218f6290aSShashi Mallela     bool result = true;
6131b08e436SShashi Mallela     int index;
61418f6290aSShashi Mallela 
6151b08e436SShashi Mallela     switch (offset) {
6161b08e436SShashi Mallela     case GITS_CTLR:
6171b08e436SShashi Mallela         *data = s->ctlr;
6181b08e436SShashi Mallela         break;
6191b08e436SShashi Mallela     case GITS_IIDR:
6201b08e436SShashi Mallela         *data = gicv3_iidr();
6211b08e436SShashi Mallela         break;
6221b08e436SShashi Mallela     case GITS_IDREGS ... GITS_IDREGS + 0x2f:
6231b08e436SShashi Mallela         /* ID registers */
6241b08e436SShashi Mallela         *data = gicv3_idreg(offset - GITS_IDREGS);
6251b08e436SShashi Mallela         break;
6261b08e436SShashi Mallela     case GITS_TYPER:
6271b08e436SShashi Mallela         *data = extract64(s->typer, 0, 32);
6281b08e436SShashi Mallela         break;
6291b08e436SShashi Mallela     case GITS_TYPER + 4:
6301b08e436SShashi Mallela         *data = extract64(s->typer, 32, 32);
6311b08e436SShashi Mallela         break;
6321b08e436SShashi Mallela     case GITS_CBASER:
6331b08e436SShashi Mallela         *data = extract64(s->cbaser, 0, 32);
6341b08e436SShashi Mallela         break;
6351b08e436SShashi Mallela     case GITS_CBASER + 4:
6361b08e436SShashi Mallela         *data = extract64(s->cbaser, 32, 32);
6371b08e436SShashi Mallela         break;
6381b08e436SShashi Mallela     case GITS_CREADR:
6391b08e436SShashi Mallela         *data = extract64(s->creadr, 0, 32);
6401b08e436SShashi Mallela         break;
6411b08e436SShashi Mallela     case GITS_CREADR + 4:
6421b08e436SShashi Mallela         *data = extract64(s->creadr, 32, 32);
6431b08e436SShashi Mallela         break;
6441b08e436SShashi Mallela     case GITS_CWRITER:
6451b08e436SShashi Mallela         *data = extract64(s->cwriter, 0, 32);
6461b08e436SShashi Mallela         break;
6471b08e436SShashi Mallela     case GITS_CWRITER + 4:
6481b08e436SShashi Mallela         *data = extract64(s->cwriter, 32, 32);
6491b08e436SShashi Mallela         break;
6501b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
6511b08e436SShashi Mallela         index = (offset - GITS_BASER) / 8;
6521b08e436SShashi Mallela         if (offset & 7) {
6531b08e436SShashi Mallela             *data = extract64(s->baser[index], 32, 32);
6541b08e436SShashi Mallela         } else {
6551b08e436SShashi Mallela             *data = extract64(s->baser[index], 0, 32);
6561b08e436SShashi Mallela         }
6571b08e436SShashi Mallela         break;
6581b08e436SShashi Mallela     default:
6591b08e436SShashi Mallela         result = false;
6601b08e436SShashi Mallela         break;
6611b08e436SShashi Mallela     }
66218f6290aSShashi Mallela     return result;
66318f6290aSShashi Mallela }
66418f6290aSShashi Mallela 
66518f6290aSShashi Mallela static bool its_writell(GICv3ITSState *s, hwaddr offset,
66618f6290aSShashi Mallela                                uint64_t value, MemTxAttrs attrs)
66718f6290aSShashi Mallela {
66818f6290aSShashi Mallela     bool result = true;
6691b08e436SShashi Mallela     int index;
67018f6290aSShashi Mallela 
6711b08e436SShashi Mallela     switch (offset) {
6721b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
6731b08e436SShashi Mallela         /*
6741b08e436SShashi Mallela          * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
6751b08e436SShashi Mallela          *                 already enabled
6761b08e436SShashi Mallela          */
6771b08e436SShashi Mallela         if (!(s->ctlr & ITS_CTLR_ENABLED)) {
6781b08e436SShashi Mallela             index = (offset - GITS_BASER) / 8;
6791b08e436SShashi Mallela             s->baser[index] &= GITS_BASER_RO_MASK;
6801b08e436SShashi Mallela             s->baser[index] |= (value & ~GITS_BASER_RO_MASK);
6811b08e436SShashi Mallela         }
6821b08e436SShashi Mallela         break;
6831b08e436SShashi Mallela     case GITS_CBASER:
6841b08e436SShashi Mallela         /*
6851b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
6861b08e436SShashi Mallela          *                 already enabled
6871b08e436SShashi Mallela          */
6881b08e436SShashi Mallela         if (!(s->ctlr & ITS_CTLR_ENABLED)) {
6891b08e436SShashi Mallela             s->cbaser = value;
6901b08e436SShashi Mallela             s->creadr = 0;
6911b08e436SShashi Mallela             s->cwriter = s->creadr;
6921b08e436SShashi Mallela         }
6931b08e436SShashi Mallela         break;
6941b08e436SShashi Mallela     case GITS_CWRITER:
6951b08e436SShashi Mallela         s->cwriter = value & ~R_GITS_CWRITER_RETRY_MASK;
696*7eca39e0SShashi Mallela         if (s->cwriter != s->creadr) {
697*7eca39e0SShashi Mallela             process_cmdq(s);
698*7eca39e0SShashi Mallela         }
6991b08e436SShashi Mallela         break;
7001b08e436SShashi Mallela     case GITS_CREADR:
7011b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
7021b08e436SShashi Mallela             s->creadr = value & ~R_GITS_CREADR_STALLED_MASK;
7031b08e436SShashi Mallela         } else {
7041b08e436SShashi Mallela             /* RO register, ignore the write */
7051b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
7061b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
7071b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
7081b08e436SShashi Mallela         }
7091b08e436SShashi Mallela         break;
7101b08e436SShashi Mallela     case GITS_TYPER:
7111b08e436SShashi Mallela         /* RO registers, ignore the write */
7121b08e436SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
7131b08e436SShashi Mallela                       "%s: invalid guest write to RO register at offset "
7141b08e436SShashi Mallela                       TARGET_FMT_plx "\n", __func__, offset);
7151b08e436SShashi Mallela         break;
7161b08e436SShashi Mallela     default:
7171b08e436SShashi Mallela         result = false;
7181b08e436SShashi Mallela         break;
7191b08e436SShashi Mallela     }
72018f6290aSShashi Mallela     return result;
72118f6290aSShashi Mallela }
72218f6290aSShashi Mallela 
72318f6290aSShashi Mallela static bool its_readll(GICv3ITSState *s, hwaddr offset,
72418f6290aSShashi Mallela                               uint64_t *data, MemTxAttrs attrs)
72518f6290aSShashi Mallela {
72618f6290aSShashi Mallela     bool result = true;
7271b08e436SShashi Mallela     int index;
72818f6290aSShashi Mallela 
7291b08e436SShashi Mallela     switch (offset) {
7301b08e436SShashi Mallela     case GITS_TYPER:
7311b08e436SShashi Mallela         *data = s->typer;
7321b08e436SShashi Mallela         break;
7331b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
7341b08e436SShashi Mallela         index = (offset - GITS_BASER) / 8;
7351b08e436SShashi Mallela         *data = s->baser[index];
7361b08e436SShashi Mallela         break;
7371b08e436SShashi Mallela     case GITS_CBASER:
7381b08e436SShashi Mallela         *data = s->cbaser;
7391b08e436SShashi Mallela         break;
7401b08e436SShashi Mallela     case GITS_CREADR:
7411b08e436SShashi Mallela         *data = s->creadr;
7421b08e436SShashi Mallela         break;
7431b08e436SShashi Mallela     case GITS_CWRITER:
7441b08e436SShashi Mallela         *data = s->cwriter;
7451b08e436SShashi Mallela         break;
7461b08e436SShashi Mallela     default:
7471b08e436SShashi Mallela         result = false;
7481b08e436SShashi Mallela         break;
7491b08e436SShashi Mallela     }
75018f6290aSShashi Mallela     return result;
75118f6290aSShashi Mallela }
75218f6290aSShashi Mallela 
75318f6290aSShashi Mallela static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
75418f6290aSShashi Mallela                                   unsigned size, MemTxAttrs attrs)
75518f6290aSShashi Mallela {
75618f6290aSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
75718f6290aSShashi Mallela     bool result;
75818f6290aSShashi Mallela 
75918f6290aSShashi Mallela     switch (size) {
76018f6290aSShashi Mallela     case 4:
76118f6290aSShashi Mallela         result = its_readl(s, offset, data, attrs);
76218f6290aSShashi Mallela         break;
76318f6290aSShashi Mallela     case 8:
76418f6290aSShashi Mallela         result = its_readll(s, offset, data, attrs);
76518f6290aSShashi Mallela         break;
76618f6290aSShashi Mallela     default:
76718f6290aSShashi Mallela         result = false;
76818f6290aSShashi Mallela         break;
76918f6290aSShashi Mallela     }
77018f6290aSShashi Mallela 
77118f6290aSShashi Mallela     if (!result) {
77218f6290aSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
77318f6290aSShashi Mallela                       "%s: invalid guest read at offset " TARGET_FMT_plx
77418f6290aSShashi Mallela                       "size %u\n", __func__, offset, size);
77518f6290aSShashi Mallela         /*
77618f6290aSShashi Mallela          * The spec requires that reserved registers are RAZ/WI;
77718f6290aSShashi Mallela          * so use false returns from leaf functions as a way to
77818f6290aSShashi Mallela          * trigger the guest-error logging but don't return it to
77918f6290aSShashi Mallela          * the caller, or we'll cause a spurious guest data abort.
78018f6290aSShashi Mallela          */
78118f6290aSShashi Mallela         *data = 0;
78218f6290aSShashi Mallela     }
78318f6290aSShashi Mallela     return MEMTX_OK;
78418f6290aSShashi Mallela }
78518f6290aSShashi Mallela 
78618f6290aSShashi Mallela static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data,
78718f6290aSShashi Mallela                                    unsigned size, MemTxAttrs attrs)
78818f6290aSShashi Mallela {
78918f6290aSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
79018f6290aSShashi Mallela     bool result;
79118f6290aSShashi Mallela 
79218f6290aSShashi Mallela     switch (size) {
79318f6290aSShashi Mallela     case 4:
79418f6290aSShashi Mallela         result = its_writel(s, offset, data, attrs);
79518f6290aSShashi Mallela         break;
79618f6290aSShashi Mallela     case 8:
79718f6290aSShashi Mallela         result = its_writell(s, offset, data, attrs);
79818f6290aSShashi Mallela         break;
79918f6290aSShashi Mallela     default:
80018f6290aSShashi Mallela         result = false;
80118f6290aSShashi Mallela         break;
80218f6290aSShashi Mallela     }
80318f6290aSShashi Mallela 
80418f6290aSShashi Mallela     if (!result) {
80518f6290aSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
80618f6290aSShashi Mallela                       "%s: invalid guest write at offset " TARGET_FMT_plx
80718f6290aSShashi Mallela                       "size %u\n", __func__, offset, size);
80818f6290aSShashi Mallela         /*
80918f6290aSShashi Mallela          * The spec requires that reserved registers are RAZ/WI;
81018f6290aSShashi Mallela          * so use false returns from leaf functions as a way to
81118f6290aSShashi Mallela          * trigger the guest-error logging but don't return it to
81218f6290aSShashi Mallela          * the caller, or we'll cause a spurious guest data abort.
81318f6290aSShashi Mallela          */
81418f6290aSShashi Mallela     }
81518f6290aSShashi Mallela     return MEMTX_OK;
81618f6290aSShashi Mallela }
81718f6290aSShashi Mallela 
81818f6290aSShashi Mallela static const MemoryRegionOps gicv3_its_control_ops = {
81918f6290aSShashi Mallela     .read_with_attrs = gicv3_its_read,
82018f6290aSShashi Mallela     .write_with_attrs = gicv3_its_write,
82118f6290aSShashi Mallela     .valid.min_access_size = 4,
82218f6290aSShashi Mallela     .valid.max_access_size = 8,
82318f6290aSShashi Mallela     .impl.min_access_size = 4,
82418f6290aSShashi Mallela     .impl.max_access_size = 8,
82518f6290aSShashi Mallela     .endianness = DEVICE_NATIVE_ENDIAN,
82618f6290aSShashi Mallela };
82718f6290aSShashi Mallela 
82818f6290aSShashi Mallela static const MemoryRegionOps gicv3_its_translation_ops = {
82918f6290aSShashi Mallela     .write_with_attrs = gicv3_its_translation_write,
83018f6290aSShashi Mallela     .valid.min_access_size = 2,
83118f6290aSShashi Mallela     .valid.max_access_size = 4,
83218f6290aSShashi Mallela     .impl.min_access_size = 2,
83318f6290aSShashi Mallela     .impl.max_access_size = 4,
83418f6290aSShashi Mallela     .endianness = DEVICE_NATIVE_ENDIAN,
83518f6290aSShashi Mallela };
83618f6290aSShashi Mallela 
83718f6290aSShashi Mallela static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
83818f6290aSShashi Mallela {
83918f6290aSShashi Mallela     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
84018f6290aSShashi Mallela     int i;
84118f6290aSShashi Mallela 
84218f6290aSShashi Mallela     for (i = 0; i < s->gicv3->num_cpu; i++) {
84318f6290aSShashi Mallela         if (!(s->gicv3->cpu[i].gicr_typer & GICR_TYPER_PLPIS)) {
84418f6290aSShashi Mallela             error_setg(errp, "Physical LPI not supported by CPU %d", i);
84518f6290aSShashi Mallela             return;
84618f6290aSShashi Mallela         }
84718f6290aSShashi Mallela     }
84818f6290aSShashi Mallela 
84918f6290aSShashi Mallela     gicv3_its_init_mmio(s, &gicv3_its_control_ops, &gicv3_its_translation_ops);
85018f6290aSShashi Mallela 
8511b08e436SShashi Mallela     address_space_init(&s->gicv3->dma_as, s->gicv3->dma,
8521b08e436SShashi Mallela                        "gicv3-its-sysmem");
8531b08e436SShashi Mallela 
85418f6290aSShashi Mallela     /* set the ITS default features supported */
85518f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, PHYSICAL,
85618f6290aSShashi Mallela                           GITS_TYPE_PHYSICAL);
85718f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, ITT_ENTRY_SIZE,
85818f6290aSShashi Mallela                           ITS_ITT_ENTRY_SIZE - 1);
85918f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, IDBITS, ITS_IDBITS);
86018f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, DEVBITS, ITS_DEVBITS);
86118f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIL, 1);
86218f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIDBITS, ITS_CIDBITS);
86318f6290aSShashi Mallela }
86418f6290aSShashi Mallela 
86518f6290aSShashi Mallela static void gicv3_its_reset(DeviceState *dev)
86618f6290aSShashi Mallela {
86718f6290aSShashi Mallela     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
86818f6290aSShashi Mallela     GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s);
86918f6290aSShashi Mallela 
87018f6290aSShashi Mallela     c->parent_reset(dev);
87118f6290aSShashi Mallela 
87218f6290aSShashi Mallela     /* Quiescent bit reset to 1 */
87318f6290aSShashi Mallela     s->ctlr = FIELD_DP32(s->ctlr, GITS_CTLR, QUIESCENT, 1);
87418f6290aSShashi Mallela 
87518f6290aSShashi Mallela     /*
87618f6290aSShashi Mallela      * setting GITS_BASER0.Type = 0b001 (Device)
87718f6290aSShashi Mallela      *         GITS_BASER1.Type = 0b100 (Collection Table)
87818f6290aSShashi Mallela      *         GITS_BASER<n>.Type,where n = 3 to 7 are 0b00 (Unimplemented)
87918f6290aSShashi Mallela      *         GITS_BASER<0,1>.Page_Size = 64KB
88018f6290aSShashi Mallela      * and default translation table entry size to 16 bytes
88118f6290aSShashi Mallela      */
88218f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, TYPE,
88318f6290aSShashi Mallela                              GITS_BASER_TYPE_DEVICE);
88418f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, PAGESIZE,
88518f6290aSShashi Mallela                              GITS_BASER_PAGESIZE_64K);
88618f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, ENTRYSIZE,
88718f6290aSShashi Mallela                              GITS_DTE_SIZE - 1);
88818f6290aSShashi Mallela 
88918f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, TYPE,
89018f6290aSShashi Mallela                              GITS_BASER_TYPE_COLLECTION);
89118f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, PAGESIZE,
89218f6290aSShashi Mallela                              GITS_BASER_PAGESIZE_64K);
89318f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, ENTRYSIZE,
89418f6290aSShashi Mallela                              GITS_CTE_SIZE - 1);
89518f6290aSShashi Mallela }
89618f6290aSShashi Mallela 
8971b08e436SShashi Mallela static void gicv3_its_post_load(GICv3ITSState *s)
8981b08e436SShashi Mallela {
8991b08e436SShashi Mallela     if (s->ctlr & ITS_CTLR_ENABLED) {
9001b08e436SShashi Mallela         extract_table_params(s);
9011b08e436SShashi Mallela         extract_cmdq_params(s);
9021b08e436SShashi Mallela     }
9031b08e436SShashi Mallela }
9041b08e436SShashi Mallela 
90518f6290aSShashi Mallela static Property gicv3_its_props[] = {
90618f6290aSShashi Mallela     DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "arm-gicv3",
90718f6290aSShashi Mallela                      GICv3State *),
90818f6290aSShashi Mallela     DEFINE_PROP_END_OF_LIST(),
90918f6290aSShashi Mallela };
91018f6290aSShashi Mallela 
91118f6290aSShashi Mallela static void gicv3_its_class_init(ObjectClass *klass, void *data)
91218f6290aSShashi Mallela {
91318f6290aSShashi Mallela     DeviceClass *dc = DEVICE_CLASS(klass);
91418f6290aSShashi Mallela     GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass);
9151b08e436SShashi Mallela     GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
91618f6290aSShashi Mallela 
91718f6290aSShashi Mallela     dc->realize = gicv3_arm_its_realize;
91818f6290aSShashi Mallela     device_class_set_props(dc, gicv3_its_props);
91918f6290aSShashi Mallela     device_class_set_parent_reset(dc, gicv3_its_reset, &ic->parent_reset);
9201b08e436SShashi Mallela     icc->post_load = gicv3_its_post_load;
92118f6290aSShashi Mallela }
92218f6290aSShashi Mallela 
92318f6290aSShashi Mallela static const TypeInfo gicv3_its_info = {
92418f6290aSShashi Mallela     .name = TYPE_ARM_GICV3_ITS,
92518f6290aSShashi Mallela     .parent = TYPE_ARM_GICV3_ITS_COMMON,
92618f6290aSShashi Mallela     .instance_size = sizeof(GICv3ITSState),
92718f6290aSShashi Mallela     .class_init = gicv3_its_class_init,
92818f6290aSShashi Mallela     .class_size = sizeof(GICv3ITSClass),
92918f6290aSShashi Mallela };
93018f6290aSShashi Mallela 
93118f6290aSShashi Mallela static void gicv3_its_register_types(void)
93218f6290aSShashi Mallela {
93318f6290aSShashi Mallela     type_register_static(&gicv3_its_info);
93418f6290aSShashi Mallela }
93518f6290aSShashi Mallela 
93618f6290aSShashi Mallela type_init(gicv3_its_register_types)
937