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