hw/arm/smmuv3: Skeleton

This patch implements a skeleton for the smmuv3 device.
Datatypes and register definitions are introduced. The MMIO
region, the interrupts and the queue are initialized.

Only the MMIO read operation is implemented here.

Signed-off-by: Prem Mallappa <prem.mallappa@broadcom.com>
Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1524665762-31355-5-git-send-email-eric.auger@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Prem Mallappa 2018-05-04 18:05:51 +01:00 committed by Peter Maydell
parent 93641948d4
commit 10a83cb988
5 changed files with 599 additions and 1 deletions

View File

@ -35,4 +35,4 @@ obj-$(CONFIG_MPS2) += mps2-tz.o
obj-$(CONFIG_MSF2) += msf2-soc.o msf2-som.o
obj-$(CONFIG_IOTKIT) += iotkit.o
obj-$(CONFIG_FSL_IMX7) += fsl-imx7.o mcimx7d-sabre.o
obj-$(CONFIG_ARM_SMMUV3) += smmu-common.o
obj-$(CONFIG_ARM_SMMUV3) += smmu-common.o smmuv3.o

142
hw/arm/smmuv3-internal.h Normal file
View File

@ -0,0 +1,142 @@
/*
* ARM SMMUv3 support - Internal API
*
* Copyright (C) 2014-2016 Broadcom Corporation
* Copyright (c) 2017 Red Hat, Inc.
* Written by Prem Mallappa, Eric Auger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HW_ARM_SMMU_V3_INTERNAL_H
#define HW_ARM_SMMU_V3_INTERNAL_H
#include "hw/arm/smmu-common.h"
/* MMIO Registers */
REG32(IDR0, 0x0)
FIELD(IDR0, S1P, 1 , 1)
FIELD(IDR0, TTF, 2 , 2)
FIELD(IDR0, COHACC, 4 , 1)
FIELD(IDR0, ASID16, 12, 1)
FIELD(IDR0, TTENDIAN, 21, 2)
FIELD(IDR0, STALL_MODEL, 24, 2)
FIELD(IDR0, TERM_MODEL, 26, 1)
FIELD(IDR0, STLEVEL, 27, 2)
REG32(IDR1, 0x4)
FIELD(IDR1, SIDSIZE, 0 , 6)
FIELD(IDR1, EVENTQS, 16, 5)
FIELD(IDR1, CMDQS, 21, 5)
#define SMMU_IDR1_SIDSIZE 16
#define SMMU_CMDQS 19
#define SMMU_EVENTQS 19
REG32(IDR2, 0x8)
REG32(IDR3, 0xc)
REG32(IDR4, 0x10)
REG32(IDR5, 0x14)
FIELD(IDR5, OAS, 0, 3);
FIELD(IDR5, GRAN4K, 4, 1);
FIELD(IDR5, GRAN16K, 5, 1);
FIELD(IDR5, GRAN64K, 6, 1);
#define SMMU_IDR5_OAS 4
REG32(IIDR, 0x1c)
REG32(CR0, 0x20)
FIELD(CR0, SMMU_ENABLE, 0, 1)
FIELD(CR0, EVENTQEN, 2, 1)
FIELD(CR0, CMDQEN, 3, 1)
REG32(CR0ACK, 0x24)
REG32(CR1, 0x28)
REG32(CR2, 0x2c)
REG32(STATUSR, 0x40)
REG32(IRQ_CTRL, 0x50)
FIELD(IRQ_CTRL, GERROR_IRQEN, 0, 1)
FIELD(IRQ_CTRL, PRI_IRQEN, 1, 1)
FIELD(IRQ_CTRL, EVENTQ_IRQEN, 2, 1)
REG32(IRQ_CTRL_ACK, 0x54)
REG32(GERROR, 0x60)
FIELD(GERROR, CMDQ_ERR, 0, 1)
FIELD(GERROR, EVENTQ_ABT_ERR, 2, 1)
FIELD(GERROR, PRIQ_ABT_ERR, 3, 1)
FIELD(GERROR, MSI_CMDQ_ABT_ERR, 4, 1)
FIELD(GERROR, MSI_EVENTQ_ABT_ERR, 5, 1)
FIELD(GERROR, MSI_PRIQ_ABT_ERR, 6, 1)
FIELD(GERROR, MSI_GERROR_ABT_ERR, 7, 1)
FIELD(GERROR, MSI_SFM_ERR, 8, 1)
REG32(GERRORN, 0x64)
#define A_GERROR_IRQ_CFG0 0x68 /* 64b */
REG32(GERROR_IRQ_CFG1, 0x70)
REG32(GERROR_IRQ_CFG2, 0x74)
#define A_STRTAB_BASE 0x80 /* 64b */
#define SMMU_BASE_ADDR_MASK 0xffffffffffe0
REG32(STRTAB_BASE_CFG, 0x88)
FIELD(STRTAB_BASE_CFG, FMT, 16, 2)
FIELD(STRTAB_BASE_CFG, SPLIT, 6 , 5)
FIELD(STRTAB_BASE_CFG, LOG2SIZE, 0 , 6)
#define A_CMDQ_BASE 0x90 /* 64b */
REG32(CMDQ_PROD, 0x98)
REG32(CMDQ_CONS, 0x9c)
FIELD(CMDQ_CONS, ERR, 24, 7)
#define A_EVENTQ_BASE 0xa0 /* 64b */
REG32(EVENTQ_PROD, 0xa8)
REG32(EVENTQ_CONS, 0xac)
#define A_EVENTQ_IRQ_CFG0 0xb0 /* 64b */
REG32(EVENTQ_IRQ_CFG1, 0xb8)
REG32(EVENTQ_IRQ_CFG2, 0xbc)
#define A_IDREGS 0xfd0
static inline int smmu_enabled(SMMUv3State *s)
{
return FIELD_EX32(s->cr[0], CR0, SMMU_ENABLE);
}
/* Command Queue Entry */
typedef struct Cmd {
uint32_t word[4];
} Cmd;
/* Event Queue Entry */
typedef struct Evt {
uint32_t word[8];
} Evt;
static inline uint32_t smmuv3_idreg(int regoffset)
{
/*
* Return the value of the Primecell/Corelink ID registers at the
* specified offset from the first ID register.
* These value indicate an ARM implementation of MMU600 p1
*/
static const uint8_t smmuv3_ids[] = {
0x04, 0, 0, 0, 0x84, 0xB4, 0xF0, 0x10, 0x0D, 0xF0, 0x05, 0xB1
};
return smmuv3_ids[regoffset / 4];
}
#endif

366
hw/arm/smmuv3.c Normal file
View File

@ -0,0 +1,366 @@
/*
* Copyright (C) 2014-2016 Broadcom Corporation
* Copyright (c) 2017 Red Hat, Inc.
* Written by Prem Mallappa, Eric Auger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "hw/boards.h"
#include "sysemu/sysemu.h"
#include "hw/sysbus.h"
#include "hw/qdev-core.h"
#include "hw/pci/pci.h"
#include "exec/address-spaces.h"
#include "trace.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/arm/smmuv3.h"
#include "smmuv3-internal.h"
static void smmuv3_init_regs(SMMUv3State *s)
{
/**
* IDR0: stage1 only, AArch64 only, coherent access, 16b ASID,
* multi-level stream table
*/
s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S1P, 1); /* stage 1 supported */
s->idr[0] = FIELD_DP32(s->idr[0], IDR0, TTF, 2); /* AArch64 PTW only */
s->idr[0] = FIELD_DP32(s->idr[0], IDR0, COHACC, 1); /* IO coherent */
s->idr[0] = FIELD_DP32(s->idr[0], IDR0, ASID16, 1); /* 16-bit ASID */
s->idr[0] = FIELD_DP32(s->idr[0], IDR0, TTENDIAN, 2); /* little endian */
s->idr[0] = FIELD_DP32(s->idr[0], IDR0, STALL_MODEL, 1); /* No stall */
/* terminated transaction will always be aborted/error returned */
s->idr[0] = FIELD_DP32(s->idr[0], IDR0, TERM_MODEL, 1);
/* 2-level stream table supported */
s->idr[0] = FIELD_DP32(s->idr[0], IDR0, STLEVEL, 1);
s->idr[1] = FIELD_DP32(s->idr[1], IDR1, SIDSIZE, SMMU_IDR1_SIDSIZE);
s->idr[1] = FIELD_DP32(s->idr[1], IDR1, EVENTQS, SMMU_EVENTQS);
s->idr[1] = FIELD_DP32(s->idr[1], IDR1, CMDQS, SMMU_CMDQS);
/* 4K and 64K granule support */
s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN4K, 1);
s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN64K, 1);
s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS); /* 44 bits */
s->cmdq.base = deposit64(s->cmdq.base, 0, 5, SMMU_CMDQS);
s->cmdq.prod = 0;
s->cmdq.cons = 0;
s->cmdq.entry_size = sizeof(struct Cmd);
s->eventq.base = deposit64(s->eventq.base, 0, 5, SMMU_EVENTQS);
s->eventq.prod = 0;
s->eventq.cons = 0;
s->eventq.entry_size = sizeof(struct Evt);
s->features = 0;
s->sid_split = 0;
}
static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t data,
unsigned size, MemTxAttrs attrs)
{
/* not yet implemented */
return MEMTX_ERROR;
}
static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset,
uint64_t *data, MemTxAttrs attrs)
{
switch (offset) {
case A_GERROR_IRQ_CFG0:
*data = s->gerror_irq_cfg0;
return MEMTX_OK;
case A_STRTAB_BASE:
*data = s->strtab_base;
return MEMTX_OK;
case A_CMDQ_BASE:
*data = s->cmdq.base;
return MEMTX_OK;
case A_EVENTQ_BASE:
*data = s->eventq.base;
return MEMTX_OK;
default:
*data = 0;
qemu_log_mask(LOG_UNIMP,
"%s Unexpected 64-bit access to 0x%"PRIx64" (RAZ)\n",
__func__, offset);
return MEMTX_OK;
}
}
static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset,
uint64_t *data, MemTxAttrs attrs)
{
switch (offset) {
case A_IDREGS ... A_IDREGS + 0x1f:
*data = smmuv3_idreg(offset - A_IDREGS);
return MEMTX_OK;
case A_IDR0 ... A_IDR5:
*data = s->idr[(offset - A_IDR0) / 4];
return MEMTX_OK;
case A_IIDR:
*data = s->iidr;
return MEMTX_OK;
case A_CR0:
*data = s->cr[0];
return MEMTX_OK;
case A_CR0ACK:
*data = s->cr0ack;
return MEMTX_OK;
case A_CR1:
*data = s->cr[1];
return MEMTX_OK;
case A_CR2:
*data = s->cr[2];
return MEMTX_OK;
case A_STATUSR:
*data = s->statusr;
return MEMTX_OK;
case A_IRQ_CTRL:
case A_IRQ_CTRL_ACK:
*data = s->irq_ctrl;
return MEMTX_OK;
case A_GERROR:
*data = s->gerror;
return MEMTX_OK;
case A_GERRORN:
*data = s->gerrorn;
return MEMTX_OK;
case A_GERROR_IRQ_CFG0: /* 64b */
*data = extract64(s->gerror_irq_cfg0, 0, 32);
return MEMTX_OK;
case A_GERROR_IRQ_CFG0 + 4:
*data = extract64(s->gerror_irq_cfg0, 32, 32);
return MEMTX_OK;
case A_GERROR_IRQ_CFG1:
*data = s->gerror_irq_cfg1;
return MEMTX_OK;
case A_GERROR_IRQ_CFG2:
*data = s->gerror_irq_cfg2;
return MEMTX_OK;
case A_STRTAB_BASE: /* 64b */
*data = extract64(s->strtab_base, 0, 32);
return MEMTX_OK;
case A_STRTAB_BASE + 4: /* 64b */
*data = extract64(s->strtab_base, 32, 32);
return MEMTX_OK;
case A_STRTAB_BASE_CFG:
*data = s->strtab_base_cfg;
return MEMTX_OK;
case A_CMDQ_BASE: /* 64b */
*data = extract64(s->cmdq.base, 0, 32);
return MEMTX_OK;
case A_CMDQ_BASE + 4:
*data = extract64(s->cmdq.base, 32, 32);
return MEMTX_OK;
case A_CMDQ_PROD:
*data = s->cmdq.prod;
return MEMTX_OK;
case A_CMDQ_CONS:
*data = s->cmdq.cons;
return MEMTX_OK;
case A_EVENTQ_BASE: /* 64b */
*data = extract64(s->eventq.base, 0, 32);
return MEMTX_OK;
case A_EVENTQ_BASE + 4: /* 64b */
*data = extract64(s->eventq.base, 32, 32);
return MEMTX_OK;
case A_EVENTQ_PROD:
*data = s->eventq.prod;
return MEMTX_OK;
case A_EVENTQ_CONS:
*data = s->eventq.cons;
return MEMTX_OK;
default:
*data = 0;
qemu_log_mask(LOG_UNIMP,
"%s unhandled 32-bit access at 0x%"PRIx64" (RAZ)\n",
__func__, offset);
return MEMTX_OK;
}
}
static MemTxResult smmu_read_mmio(void *opaque, hwaddr offset, uint64_t *data,
unsigned size, MemTxAttrs attrs)
{
SMMUState *sys = opaque;
SMMUv3State *s = ARM_SMMUV3(sys);
MemTxResult r;
/* CONSTRAINED UNPREDICTABLE choice to have page0/1 be exact aliases */
offset &= ~0x10000;
switch (size) {
case 8:
r = smmu_readll(s, offset, data, attrs);
break;
case 4:
r = smmu_readl(s, offset, data, attrs);
break;
default:
r = MEMTX_ERROR;
break;
}
trace_smmuv3_read_mmio(offset, *data, size, r);
return r;
}
static const MemoryRegionOps smmu_mem_ops = {
.read_with_attrs = smmu_read_mmio,
.write_with_attrs = smmu_write_mmio,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 8,
},
.impl = {
.min_access_size = 4,
.max_access_size = 8,
},
};
static void smmu_init_irq(SMMUv3State *s, SysBusDevice *dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
sysbus_init_irq(dev, &s->irq[i]);
}
}
static void smmu_reset(DeviceState *dev)
{
SMMUv3State *s = ARM_SMMUV3(dev);
SMMUv3Class *c = ARM_SMMUV3_GET_CLASS(s);
c->parent_reset(dev);
smmuv3_init_regs(s);
}
static void smmu_realize(DeviceState *d, Error **errp)
{
SMMUState *sys = ARM_SMMU(d);
SMMUv3State *s = ARM_SMMUV3(sys);
SMMUv3Class *c = ARM_SMMUV3_GET_CLASS(s);
SysBusDevice *dev = SYS_BUS_DEVICE(d);
Error *local_err = NULL;
c->parent_realize(d, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
memory_region_init_io(&sys->iomem, OBJECT(s),
&smmu_mem_ops, sys, TYPE_ARM_SMMUV3, 0x20000);
sys->mrtypename = TYPE_SMMUV3_IOMMU_MEMORY_REGION;
sysbus_init_mmio(dev, &sys->iomem);
smmu_init_irq(s, dev);
}
static const VMStateDescription vmstate_smmuv3_queue = {
.name = "smmuv3_queue",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT64(base, SMMUQueue),
VMSTATE_UINT32(prod, SMMUQueue),
VMSTATE_UINT32(cons, SMMUQueue),
VMSTATE_UINT8(log2size, SMMUQueue),
},
};
static const VMStateDescription vmstate_smmuv3 = {
.name = "smmuv3",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(features, SMMUv3State),
VMSTATE_UINT8(sid_size, SMMUv3State),
VMSTATE_UINT8(sid_split, SMMUv3State),
VMSTATE_UINT32_ARRAY(cr, SMMUv3State, 3),
VMSTATE_UINT32(cr0ack, SMMUv3State),
VMSTATE_UINT32(statusr, SMMUv3State),
VMSTATE_UINT32(irq_ctrl, SMMUv3State),
VMSTATE_UINT32(gerror, SMMUv3State),
VMSTATE_UINT32(gerrorn, SMMUv3State),
VMSTATE_UINT64(gerror_irq_cfg0, SMMUv3State),
VMSTATE_UINT32(gerror_irq_cfg1, SMMUv3State),
VMSTATE_UINT32(gerror_irq_cfg2, SMMUv3State),
VMSTATE_UINT64(strtab_base, SMMUv3State),
VMSTATE_UINT32(strtab_base_cfg, SMMUv3State),
VMSTATE_UINT64(eventq_irq_cfg0, SMMUv3State),
VMSTATE_UINT32(eventq_irq_cfg1, SMMUv3State),
VMSTATE_UINT32(eventq_irq_cfg2, SMMUv3State),
VMSTATE_STRUCT(cmdq, SMMUv3State, 0, vmstate_smmuv3_queue, SMMUQueue),
VMSTATE_STRUCT(eventq, SMMUv3State, 0, vmstate_smmuv3_queue, SMMUQueue),
VMSTATE_END_OF_LIST(),
},
};
static void smmuv3_instance_init(Object *obj)
{
/* Nothing much to do here as of now */
}
static void smmuv3_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SMMUv3Class *c = ARM_SMMUV3_CLASS(klass);
dc->vmsd = &vmstate_smmuv3;
device_class_set_parent_reset(dc, smmu_reset, &c->parent_reset);
c->parent_realize = dc->realize;
dc->realize = smmu_realize;
}
static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass,
void *data)
{
}
static const TypeInfo smmuv3_type_info = {
.name = TYPE_ARM_SMMUV3,
.parent = TYPE_ARM_SMMU,
.instance_size = sizeof(SMMUv3State),
.instance_init = smmuv3_instance_init,
.class_size = sizeof(SMMUv3Class),
.class_init = smmuv3_class_init,
};
static const TypeInfo smmuv3_iommu_memory_region_info = {
.parent = TYPE_IOMMU_MEMORY_REGION,
.name = TYPE_SMMUV3_IOMMU_MEMORY_REGION,
.class_init = smmuv3_iommu_memory_region_class_init,
};
static void smmuv3_register_types(void)
{
type_register(&smmuv3_type_info);
type_register(&smmuv3_iommu_memory_region_info);
}
type_init(smmuv3_register_types)

View File

@ -12,3 +12,6 @@ smmu_ptw_invalid_pte(int stage, int level, uint64_t baseaddr, uint64_t pteaddr,
smmu_ptw_page_pte(int stage, int level, uint64_t iova, uint64_t baseaddr, uint64_t pteaddr, uint64_t pte, uint64_t address) "stage=%d level=%d iova=0x%"PRIx64" base@=0x%"PRIx64" pte@=0x%"PRIx64" pte=0x%"PRIx64" page address = 0x%"PRIx64
smmu_ptw_block_pte(int stage, int level, uint64_t baseaddr, uint64_t pteaddr, uint64_t pte, uint64_t iova, uint64_t gpa, int bsize_mb) "stage=%d level=%d base@=0x%"PRIx64" pte@=0x%"PRIx64" pte=0x%"PRIx64" iova=0x%"PRIx64" block address = 0x%"PRIx64" block size = %d MiB"
smmu_get_pte(uint64_t baseaddr, int index, uint64_t pteaddr, uint64_t pte) "baseaddr=0x%"PRIx64" index=0x%x, pteaddr=0x%"PRIx64", pte=0x%"PRIx64
#hw/arm/smmuv3.c
smmuv3_read_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)"

87
include/hw/arm/smmuv3.h Normal file
View File

@ -0,0 +1,87 @@
/*
* Copyright (C) 2014-2016 Broadcom Corporation
* Copyright (c) 2017 Red Hat, Inc.
* Written by Prem Mallappa, Eric Auger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HW_ARM_SMMUV3_H
#define HW_ARM_SMMUV3_H
#include "hw/arm/smmu-common.h"
#include "hw/registerfields.h"
#define TYPE_SMMUV3_IOMMU_MEMORY_REGION "smmuv3-iommu-memory-region"
typedef struct SMMUQueue {
uint64_t base; /* base register */
uint32_t prod;
uint32_t cons;
uint8_t entry_size;
uint8_t log2size;
} SMMUQueue;
typedef struct SMMUv3State {
SMMUState smmu_state;
uint32_t features;
uint8_t sid_size;
uint8_t sid_split;
uint32_t idr[6];
uint32_t iidr;
uint32_t cr[3];
uint32_t cr0ack;
uint32_t statusr;
uint32_t irq_ctrl;
uint32_t gerror;
uint32_t gerrorn;
uint64_t gerror_irq_cfg0;
uint32_t gerror_irq_cfg1;
uint32_t gerror_irq_cfg2;
uint64_t strtab_base;
uint32_t strtab_base_cfg;
uint64_t eventq_irq_cfg0;
uint32_t eventq_irq_cfg1;
uint32_t eventq_irq_cfg2;
SMMUQueue eventq, cmdq;
qemu_irq irq[4];
} SMMUv3State;
typedef enum {
SMMU_IRQ_EVTQ,
SMMU_IRQ_PRIQ,
SMMU_IRQ_CMD_SYNC,
SMMU_IRQ_GERROR,
} SMMUIrq;
typedef struct {
/*< private >*/
SMMUBaseClass smmu_base_class;
/*< public >*/
DeviceRealize parent_realize;
DeviceReset parent_reset;
} SMMUv3Class;
#define TYPE_ARM_SMMUV3 "arm-smmuv3"
#define ARM_SMMUV3(obj) OBJECT_CHECK(SMMUv3State, (obj), TYPE_ARM_SMMUV3)
#define ARM_SMMUV3_CLASS(klass) \
OBJECT_CLASS_CHECK(SMMUv3Class, (klass), TYPE_ARM_SMMUV3)
#define ARM_SMMUV3_GET_CLASS(obj) \
OBJECT_GET_CLASS(SMMUv3Class, (obj), TYPE_ARM_SMMUV3)
#endif