All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation
@ 2016-01-11 14:16 pmallapp
  2016-01-11 14:16 ` [Qemu-devel] [PATCH RFC 1/4] arm: smmu: ARM SMMUv3 emulation pmallapp
                   ` (6 more replies)
  0 siblings, 7 replies; 16+ messages in thread
From: pmallapp @ 2016-01-11 14:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Prem Mallappa

From: Prem Mallappa <pmallapp@broadcom.com>

Implementation Notes:

        - SMMUv3 model, as per ARM SMMUv3 11.0 spec
        - Works with Linux Kernel 4.4 SMMUv3 Driver By Will Deacon.
	- Stage1 only
        - only LPAE Translation tables supported
        - BE for translation tables is not supported.
        - Save/Restore not supported "YET".
        - Broadcom variant added, not much different at the moment

Untested
	- Stage2 only
	- Stage1+Stage2 support

Future planned work:
	- MSI(x) support

Test Case setup:
-------------------
 - DPDK + VFIO (DPDK from git master)
 - QEMU (master)
 - Linux Kernel 4.5
 - Bridge interface in Linux

1. Create Bridge interface
- create br0
	sudo brctl addbr br0
- create tap0 tap1 
	sudo ip tuntap add dev tap0 mode tap user ${USER}
	sudo ip tuntap add dev tap1 mode tap user ${USER}

- assign IP address to br0
	sudo ip addr add 20.40.60.80/24 dev br0

2. Launch QEMU (3 ethernet, one unused, the virtio-net is used for NFS)

     pmallapp> aarch64-softmmu/qemu-system-aarch64 -machine type=virt -cpu cortex-a57 \
		-m 4192 -smp 4 -nographic \
		-append 'console=ttyAMA0,38400n8 mem=4192M  root=/dev/nfs \
			nfsroot=10.0.2.2:/srv/nfsroot/v8,vers=3,nolock rw e1000e.IntMode=2 \
			ip=10.0.2.15:10.0.2.2:10.0.2.2:255.255.255.0:prems:eth0  ' \
		-kernel /home/pmallapp/work/vulcan/armsw/linux/build/arch/arm64/boot/Image \
		-chardev socket,id=serial0,host=localhost,port=5000,server,telnet \
		-serial chardev:serial0 \
		-chardev socket,id=mon0,host=localhost,port=6001,server,telnet,nowait \
		-monitor chardev:mon0 \
		-device pci-bridge,bus=pcie.0,multifunction=on,chassis_nr=2,msi=on,id=pcie.2 \
		-netdev user,id=eth0 \
		-device virtio-net-device,netdev=eth0 \
		-netdev tap,id=eth1,ifname=tap0,script=no,downscript=no \
		-device e1000,netdev=eth1,bus=pcie.2,addr=3 \
		-netdev tap,id=eth2,ifname=tap1,script=no,downscript=no \
		-device virtio-net-pci,netdev=eth2,vectors=0

3. Remove Device from Linux, Add to VFIO, create some reserved Huge pages
	# lspci -nn
	00:00.0 Host bridge [0600]: Red Hat, Inc. Device [1b36:0008]
	00:01.0 PCI bridge [0604]: Red Hat, Inc. QEMU PCI-PCI bridge [1b36:0001]
	00:02.0 Ethernet controller [0200]: Red Hat, Inc Virtio network device [1af4:1000]
	01:03.0 Ethernet controller [0200]: Intel Corporation 82540EM Gigabit Ethernet Controller [8086:100e] (rev 03)
	
	echo 0000:01:03.0 > /sys/bus/pci/devices/0000:01:03.0/driver/unbind
	echo 8086 100e > /sys/bus/pci/drivers/vfio-pci/new_id

	echo 300 > /proc/sys/vm/nr_hugepages (my case HugePageSize is 2MB)

4. Launch DPDK app, testpmd 
	./testpmd -c 0xf  -w 0000:01:03.0 -- --rxq=1 --txq= rxd=32  \
		--txd=32 --mbuf-size=32 --total-num-mbufs=1025 --max-pkt-len=512 -i
	testpmd> set fwd icmpecho
	testpmd> start

5. From host ping any address in 20.40.60.80/24 range
	ping 20.40.60.90 -I br0 -c 10 -r

Prem Mallappa (4):
  arm: smmu: ARM SMMUv3 emulation
  hw: arm: Added smmuv3 files for build
  hw: arm: Add SMMUv3 to virt platform
  devicetree: Added new APIs to make use of more fdt functions

 default-configs/aarch64-softmmu.mak |    1 +
 device_tree.c                       |   35 +
 hw/arm/Makefile.objs                |    1 +
 hw/arm/smmuv3-internal.h            |  343 ++++++++
 hw/arm/smmuv3.c                     | 1530 +++++++++++++++++++++++++++++++++++
 hw/arm/virt.c                       |   62 ++
 include/hw/arm/smmuv3.h             |   39 +
 include/hw/arm/virt.h               |    2 +
 include/sysemu/device_tree.h        |   18 +
 9 files changed, 2031 insertions(+)
 create mode 100644 hw/arm/smmuv3-internal.h
 create mode 100644 hw/arm/smmuv3.c
 create mode 100644 include/hw/arm/smmuv3.h

-- 
2.6.4

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH RFC 1/4] arm: smmu: ARM SMMUv3 emulation
  2016-01-11 14:16 [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation pmallapp
@ 2016-01-11 14:16 ` pmallapp
  2016-01-11 14:16 ` [Qemu-devel] [PATCH RFC 2/4] hw: arm: Added smmuv3 files for build pmallapp
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 16+ messages in thread
From: pmallapp @ 2016-01-11 14:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Prem Mallappa

From: Prem Mallappa <pmallapp@broadcom.com>

Implementation Notes:
        - Implements ARM SMMUv3 version 11.0
	- Works with SMMUv3 Driver in Linux Kernel 4.4
	- Only LPAE mode Translation supported
	- BE mode TT not supported Yet
	- Stage1 only
	- Suspend/Resume not yet supported
	- Broadcom variant added, but not much difference at the moment

Signed-off-by: Prem Mallappa <pmallapp@broadcom.com>
---
 hw/arm/smmuv3-internal.h |  343 +++++++++++
 hw/arm/smmuv3.c          | 1530 ++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/smmuv3.h  |   39 ++
 3 files changed, 1912 insertions(+)
 create mode 100644 hw/arm/smmuv3-internal.h
 create mode 100644 hw/arm/smmuv3.c
 create mode 100644 include/hw/arm/smmuv3.h

diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
new file mode 100644
index 0000000..54ef52a
--- /dev/null
+++ b/hw/arm/smmuv3-internal.h
@@ -0,0 +1,343 @@
+/*
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2014-2015 Broadcom Corporation
+ *
+ * Author: Prem Mallappa <pmallapp@broadcom.com>
+ *
+ */
+
+#ifndef HW_ARM_SMMU_V3_INTERNAL_H
+#define HW_ARM_SMMU_V3_INTERNAL_H
+
+/*****************************
+ * MMIO Register
+ *****************************/
+enum {
+    SMMU_REG_IDR0            = 0x0,
+
+#define SMMU_IDR0_S2P            (1 << 0)
+#define SMMU_IDR0_S1P            (1 << 1)
+#define SMMU_IDR0_TTF            (0x3 << 2)
+#define SMMU_IDR0_HTTU           (0x3 << 6)
+#define SMMU_IDR0_HYP            (1 << 9)
+#define SMMU_IDR0_ATS            (1 << 10)
+#define SMMU_IDR0_VMID16         (1 << 18)
+#define SMMU_IDR0_CD2L           (1 << 19)
+
+    SMMU_REG_IDR1            = 0x4,
+    SMMU_REG_IDR2            = 0x8,
+    SMMU_REG_IDR3            = 0xc,
+    SMMU_REG_IDR4            = 0x10,
+    SMMU_REG_IDR5            = 0x14,
+    SMMU_REG_IIDR            = 0x1c,
+    SMMU_REG_CR0             = 0x20,
+
+#define SMMU_CR0_SMMU_ENABLE (1 << 0)
+#define SMMU_CR0_PRIQ_ENABLE (1 << 1)
+#define SMMU_CR0_EVTQ_ENABLE (1 << 2)
+#define SMMU_CR0_CMDQ_ENABLE (1 << 3)
+#define SMMU_CR0_ATS_CHECK   (1 << 4)
+
+    SMMU_REG_CR0_ACK         = 0x24,
+    SMMU_REG_CR1             = 0x28,
+    SMMU_REG_CR2             = 0x2c,
+
+    SMMU_REG_STATUSR         = 0x40,
+
+    SMMU_REG_IRQ_CTRL        = 0x50,
+    SMMU_REG_IRQ_CTRL_ACK    = 0x54,
+
+#define SMMU_IRQ_CTRL_GERROR_EN (1 << 0)
+#define SMMU_IRQ_CTRL_EVENT_EN  (1 << 1)
+#define SMMU_IRQ_CTRL_PRI_EN    (1 << 2)
+
+    SMMU_REG_GERROR          = 0x60,
+
+#define SMMU_GERROR_CMDQ       (1 << 0)
+#define SMMU_GERROR_EVENTQ     (1 << 1)
+#define SMMU_GERROR_PRIQ       (1 << 2)
+#define SMMU_GERROR_MSI_CMDQ   (1 << 3)
+#define SMMU_GERROR_MSI_EVENTQ (1 << 4)
+#define SMMU_GERROR_MSI_PRIQ   (1 << 5)
+#define SMMU_GERROR_MSI_GERROR (1 << 6)
+#define SMMU_GERROR_SFM_ERR    (1 << 7)
+
+    SMMU_REG_GERRORN         = 0x64,
+    SMMU_REG_GERROR_IRQ_CFG0 = 0x68,
+    SMMU_REG_GERROR_IRQ_CFG1 = 0x70,
+    SMMU_REG_GERROR_IRQ_CFG2 = 0x74,
+
+    /* SMMU_BASE_RA Applies to STRTAB_BASE, CMDQ_BASE and EVTQ_BASE */
+#define SMMU_BASE_RA        (1ULL << 62)
+    SMMU_REG_STRTAB_BASE     = 0x80,
+    SMMU_REG_STRTAB_BASE_CFG = 0x88,
+
+    SMMU_REG_CMDQ_BASE       = 0x90,
+    SMMU_REG_CMDQ_PROD       = 0x98,
+    SMMU_REG_CMDQ_CONS       = 0x9c,
+    /* CMD Consumer (CONS) */
+#define SMMU_CMD_CONS_ERR_SHIFT        24
+#define SMMU_CMD_CONS_ERR_BITS         7
+
+    SMMU_REG_EVTQ_BASE       = 0xa0,
+    SMMU_REG_EVTQ_PROD       = 0xa8,
+    SMMU_REG_EVTQ_CONS       = 0xac,
+    SMMU_REG_EVTQ_IRQ_CFG0   = 0xb0,
+    SMMU_REG_EVTQ_IRQ_CFG1   = 0xb8,
+    SMMU_REG_EVTQ_IRQ_CFG2   = 0xbc,
+
+    SMMU_REG_PRIQ_BASE       = 0xc0,
+    SMMU_REG_PRIQ_PROD       = 0xc8,
+    SMMU_REG_PRIQ_CONS       = 0xcc,
+    SMMU_REG_PRIQ_IRQ_CFG0   = 0xd0,
+    SMMU_REG_PRIQ_IRQ_CFG1   = 0xd8,
+    SMMU_REG_PRIQ_IRQ_CFG2   = 0xdc,
+
+    SMMU_ID_REGS_OFFSET      = 0xfd0,
+
+    /* Secure registers are not used for now */
+    SMMU_SECURE_OFFSET       = 0x8000,
+};
+
+/*****************************
+ * STE fields
+ *****************************/
+#define STE_VALID(x)   extract32((x)->word[0], 0, 1) /* 0 */
+#define STE_CONFIG(x)  extract32((x)->word[0], 1, 3)
+enum {
+    STE_CONFIG_NONE      = 0,
+    STE_CONFIG_S1BY_S2BY = 4,   /* S1 Bypass, S2 Bypass */
+    STE_CONFIG_S1TR_S2BY,       /* S1 Translate, S2 Bypass */
+    STE_CONFIG_S1BY_S2TR,       /* S1 Bypass, S2 Translate */
+    STE_CONFIG_S1TR_S2TR,       /* S1 Translate, S2 Translate */
+};
+#define STE_S1FMT(x)   extract32((x)->word[0], 4, 2)
+#define STE_S1CDMAX(x) extract32((x)->word[1], 8, 2)
+#define STE_EATS(x)    extract32((x)->word[2], 28, 2)
+#define STE_STRW(x)    extract32((x)->word[2], 30, 2)
+#define STE_S2VMID(x)  extract32((x)->word[4], 0, 16) /* 4 */
+#define STE_S2T0SZ(x)  extract32((x)->word[5], 0, 6) /* 5 */
+#define STE_S2TG(x)    extract32((x)->word[5], 14, 2)
+#define STE_S2PS(x)    extract32((x)->word[5], 16, 3)
+#define STE_S2AA64(x)  extract32((x)->word[5], 19, 1)
+#define STE_S2HD(x)    extract32((x)->word[5], 24, 1)
+#define STE_S2HA(x)    extract32((x)->word[5], 25, 1)
+#define STE_S2S(x)     extract32((x)->word[5], 26, 1)
+#define STE_CTXPTR(x)                                           \
+    ({                                                          \
+        unsigned long addr;                                     \
+        addr = (uint64_t)extract32((x)->word[1], 0, 16) << 32;  \
+        addr |= (uint64_t)((x)->word[0] & 0xffffffc0);          \
+        addr;                                                   \
+    })
+
+#define STE_S2TTB(x)                                            \
+    ({                                                          \
+        unsigned long addr;                                     \
+        addr = (uint64_t)extract32((x)->word[7], 0, 16) << 32;  \
+        addr |= (uint64_t)((x)->word[6] & 0xfffffff0);          \
+        addr;                                                   \
+    })
+
+/*****************************
+ * CD fields
+ *****************************/
+#define CD_VALID(x)   extract32((x)->word[0], 30, 1)
+#define CD_ASID(x)    extract32((x)->word[1], 16, 16)
+#define CD_TTB(x, sel)                                  \
+    ({                                                  \
+        uint64_t hi, lo;                                \
+        hi = extract32((x)->word[(sel)*2 + 3], 0, 16);  \
+        hi <<= 32;                                      \
+        lo = (x)->word[(sel)*2+2] & ~0xf;               \
+        hi | lo;                                        \
+    })
+
+#define CD_TSZ(x, sel)   extract32((x)->word[0], (16*(sel)) + 0, 6)
+#define CD_TG(x, sel)    extract32((x)->word[0], (16*(sel)) + 6, 2)
+#define CD_EPD(x, sel)   extract32((x)->word[0], (16*(sel)) + 14, 1)
+
+#define CD_T0SZ(x)    CD_TSZ((x), 0)
+#define CD_T1SZ(x)    CD_TSZ((x), 1)
+#define CD_TG0(x)     CD_TG((x), 0)
+#define CD_TG1(x)     CD_TG((x), 1)
+#define CD_EPD0(x)    CD_EPD((x), 0)
+#define CD_EPD1(x)    CD_EPD((x), 1)
+#define CD_IPS(x)     extract32((x)->word[(1)], 0, 3)
+#define CD_AARCH64(x) extract32((x)->word[(1)], 9, 1)
+#define CD_TTB0(x)    CD_TTB((x), 0)
+#define CD_TTB1(x)    CD_TTB((x), 1)
+
+#define CDM_VALID(x)    ((x)->word[0] & 0x1)
+
+/*****************************
+ * Commands
+ *****************************/
+enum {
+    SMMU_CMD_PREFETCH_CONFIG = 0x01,
+    SMMU_CMD_PREFETCH_ADDR,
+    SMMU_CMD_CFGI_STE,
+    SMMU_CMD_CFGI_STE_RANGE,
+    SMMU_CMD_CFGI_CD,
+    SMMU_CMD_CFGI_CD_ALL,
+    SMMU_CMD_TLBI_NH_ALL     = 0x10,
+    SMMU_CMD_TLBI_NH_ASID,
+    SMMU_CMD_TLBI_NH_VA,
+    SMMU_CMD_TLBI_NH_VAA,
+    SMMU_CMD_TLBI_EL3_ALL    = 0x18,
+    SMMU_CMD_TLBI_EL3_VA     = 0x1a,
+    SMMU_CMD_TLBI_EL2_ALL    = 0x20,
+    SMMU_CMD_TLBI_EL2_ASID,
+    SMMU_CMD_TLBI_EL2_VA,
+    SMMU_CMD_TLBI_EL2_VAA,  /* 0x23 */
+    SMMU_CMD_TLBI_S12_VMALL  = 0x28,
+    SMMU_CMD_TLBI_S2_IPA     = 0x2a,
+    SMMU_CMD_TLBI_NSNH_ALL   = 0x30,
+    SMMU_CMD_ATC_INV         = 0x40,
+    SMMU_CMD_PRI_RESP,
+    SMMU_CMD_RESUME          = 0x44,
+    SMMU_CMD_STALL_TERM,
+    SMMU_CMD_SYNC,          /* 0x46 */
+};
+
+/*****************************
+ * CMDQ fields
+ *****************************/
+
+enum { /* Command Errors */
+    SMMU_CMD_ERR_NONE = 0,
+    SMMU_CMD_ERR_ILLEGAL,
+    SMMU_CMD_ERR_ABORT
+};
+
+enum { /* Command completion notification */
+    CMD_SYNC_SIG_NONE,
+    CMD_SYNC_SIG_IRQ,
+    CMD_SYNC_SIG_SEV,
+};
+
+#define CMD_TYPE(x)  extract32((x)->word[0], 0, 8)
+#define CMD_SEC(x)   extract32((x)->word[0], 9, 1)
+#define CMD_SEV(x)   extract32((x)->word[0], 10, 1)
+#define CMD_AC(x)    extract32((x)->word[0], 12, 1)
+#define CMD_AB(x)    extract32((x)->word[0], 13, 1)
+#define CMD_CS(x)    extract32((x)->word[0], 12, 2)
+#define CMD_SSID(x)  extract32((x)->word[0], 16, 16)
+#define CMD_SID(x)   ((x)->word[1])
+#define CMD_VMID(x)  extract32((x)->word[1], 0, 16)
+#define CMD_ASID(x)  extract32((x)->word[1], 16, 16)
+#define CMD_STAG(x)  extract32((x)->word[2], 0, 16)
+#define CMD_RESP(x)  extract32((x)->word[2], 11, 2)
+#define CMD_GRPID(x) extract32((x)->word[3], 0, 8)
+#define CMD_SIZE(x)  extract32((x)->word[3], 0, 16)
+#define CMD_LEAF(x)  extract32((x)->word[3], 0, 1)
+#define CMD_SPAN(x)  extract32((x)->word[3], 0, 5)
+#define CMD_ADDR(x) ({                                  \
+            uint64_t addr = (uint64_t)(x)->word[3];     \
+            addr <<= 32;                                \
+            addr |=  extract32((x)->word[3], 12, 20);   \
+            addr;                                       \
+        })
+
+/*****************************
+ * EVTQ fields
+ *****************************/
+#define EVT_Q_OVERFLOW        (1<<31)
+
+#define EVT_SET_TYPE(x, t)    deposit32((x)->word[0], 0, 8, t)
+#define EVT_SET_SID(x, s)     ((x)->word[1] =  s)
+#define EVT_SET_INPUT_ADDR(x, addr) ({                    \
+            (x)->word[5] = (uint32_t)(addr >> 32);        \
+            (x)->word[4] = (uint32_t)(addr & 0xffffffff); \
+            addr;                                         \
+        })
+
+/*****************************
+ * Events
+ *****************************/
+enum evt_err {
+    SMMU_EVT_F_UUT    = 0x1,
+    SMMU_EVT_C_BAD_SID,
+    SMMU_EVT_F_STE_FETCH,
+    SMMU_EVT_C_BAD_STE,
+    SMMU_EVT_F_BAD_ATS_REQ,
+    SMMU_EVT_F_STREAM_DISABLED,
+    SMMU_EVT_F_TRANS_FORBIDDEN,
+    SMMU_EVT_C_BAD_SSID,
+    SMMU_EVT_F_CD_FETCH,
+    SMMU_EVT_C_BAD_CD,
+    SMMU_EVT_F_WALK_EXT_ABRT,
+    SMMU_EVT_F_TRANS        = 0x10,
+    SMMU_EVT_F_ADDR_SZ,
+    SMMU_EVT_F_ACCESS,
+    SMMU_EVT_F_PERM,
+    SMMU_EVT_F_TLB_CONFLICT = 0x20,
+    SMMU_EVT_F_CFG_CONFLICT = 0x21,
+    SMMU_EVT_E_PAGE_REQ     = 0x24,
+};
+
+typedef enum evt_err SMMUEvtErr;
+
+
+/*****************************
+ * SMMU Data structures
+ *****************************/
+#define ARM_SMMU_FEAT_PASSID_SUPPORT  (1 << 24) /* Some random bits for now */
+#define ARM_SMMU_FEAT_CD_2LVL         (1 << 25)
+
+struct __smmu_data2 {
+    uint32_t word[2];
+};
+
+struct __smmu_data8 {
+    uint32_t word[8];
+};
+
+struct __smmu_data16 {
+    uint32_t word[16];
+};
+
+struct __smmu_data4 {
+    uint32_t word[4];
+};
+
+typedef struct __smmu_data2  STEDesc; /* STE Level 1 Descriptor */
+typedef struct __smmu_data16 Ste;     /* Stream Table Entry(STE) */
+typedef struct __smmu_data2  CDDesc;  /* CD Level 1 Descriptor */
+typedef struct __smmu_data16 Cd;      /* Context Descriptor(CD) */
+
+typedef struct __smmu_data4  Cmd; /* Command Entry */
+typedef struct __smmu_data8  Evt; /* Event Entry */
+typedef struct __smmu_data4  Pri; /* PRI entry */
+
+
+/*****************************
+ * Broadcom Specific register and bits
+ *****************************/
+#define SMMU_REG_CNTL         (0x410 << 2)
+#define SMMU_REG_CNTL_1       (0x411 << 2)
+#define SMMU_REG_INTERRUPT    (0x412 << 2)
+/* BIT encoding is same as SMMU_REG_INTERRUPT, except for last 4 bits */
+#define SMMU_REG_INTERRUPT_EN (0x413 << 2)
+
+#define SMMU_INTR_BMI_ERR  (1 << 6) /* Smmu BMI Rd Wr Error*/
+#define SMMU_INTR_BSI_ERR  (1 << 5) /* Smmu BSI Rd Wr Error*/
+#define SMMU_INTR_SBU_INTR (1 << 4) /* SBU interrupt 0 */
+#define SMMU_INTR_CMD_SYNC (1 << 3) /* CmdSync completion set to interrupt */
+#define SMMU_INTR_EVENT    (1 << 2) /* high till EventQ.PROD != EventQ.CONS */
+#define SMMU_INTR_PRI      (1 << 1) /* PriQ. high till PriQ.PROD != PriQ.CONS */
+#define SMMU_INTR_GERROR   (1 << 0) /* cleared when  GERRORN is written */
+
+#endif
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
new file mode 100644
index 0000000..ffb4339
--- /dev/null
+++ b/hw/arm/smmuv3.c
@@ -0,0 +1,1530 @@
+/*
+ * QEMU emulation for ARM SMMUv3
+ * Copyright (C) 2014-2015 Broadcom Corporation
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Prem Mallappa <pmallapp@broadcom.com>
+ *
+ */
+
+/*
+ * - Doesn't yet consider BE/LE for data structure and translation tables
+ * - LPAE Pagetables only
+ * - Works with SMMUv3 driver in Linux 4.5
+ * - Save/Restore not yet supported
+ */
+
+#include "hw/sysbus.h"
+#include "hw/pci/pci.h"
+#include "exec/address-spaces.h"
+
+#include "hw/arm/smmuv3.h"
+#include "smmuv3-internal.h"
+
+#define ARM_SMMU_DEBUG
+#ifdef ARM_SMMU_DEBUG
+
+enum {SMMU_DBG_PANIC, SMMU_DBG_CRIT, SMMU_DBG_WARN, /* error level */
+      SMMU_DBG_DBG1, SMMU_DBG_DBG2, SMMU_DBG_INFO, /* info level */
+      SMMU_DBG_CMDQ,                /* Just command queue */
+      SMMU_DBG_STE, SMMU_DBG_CD,    /* Specific parts STE/CD */
+      SMMU_DBG_TT_1, SMMU_DBG_TT_2, /* Translation Stage 1/2 */
+      SMMU_DBG_IRQ,                 /* IRQ  */
+};
+
+#define DBG_BIT(bit)    (1 << SMMU_DBG_##bit)
+
+#define IS_DBG_ENABLED(bit) (dbg_bits & (1 << SMMU_DBG_##bit))
+
+#define DBG_DEFAULT  (DBG_BIT(PANIC) | DBG_BIT(CRIT) | DBG_BIT(IRQ))
+#define DBG_EXTRA    (DBG_BIT(STE) | DBG_BIT(CD) | DBG_BIT(TT_1))
+#define DBG_VERBOSE1 DBG_BIT(DBG1)
+#define DBG_VERBOSE2 (DBG_VERBOSE1 | DBG_BIT(DBG1))
+#define DBG_VERBOSE3 (DBG_VERBOSE2 | DBG_BIT(DBG2))
+#define DBG_VERBOSE4 (DBG_VERBOSE3 | DBG_BIT(INFO))
+
+static uint32_t  dbg_bits =                     \
+    DBG_DEFAULT |                               \
+    DBG_EXTRA |                                 \
+    DBG_VERBOSE1;
+
+#define SMMU_DPRINTF(lvl, fmt, ...)                     \
+    do {                                                \
+        if (dbg_bits & DBG_BIT(lvl)) {                  \
+            fprintf(stderr, "(smmu)%s: " fmt ,          \
+                    __func__, ## __VA_ARGS__);          \
+        }                                               \
+    } while (0)
+
+#define dump_ste(...) do {} while (0)
+#define dump_cd(...) do {} while (0)
+#define dump_cmd(...) do {} while (0)
+#else
+#define IS_DBG_ENABLED(bit) false
+#define SMMU_DPRINTF(lvl, fmt, ...)
+#endif  /* SMMU_DEBUG */
+
+#define SMMU_NREGS       0xC000
+#define PCI_DEVFN_MAX    32
+
+typedef struct SMMUQueue {
+    hwaddr   base;
+    uint32_t prod;
+    uint32_t cons;
+    union {
+        struct {
+            uint8_t prod:1;
+            uint8_t cons:1;
+        };
+        uint8_t unused;
+    } wrap;
+
+    uint16_t entries;           /* Number of entries */
+    uint8_t  ent_size;          /* Size of entry in bytes */
+    uint8_t  shift;             /* Size in log2 */
+} SMMUQueue;
+#define Q_ENTRY(q, idx) (q->base + q->ent_size * idx)
+#define Q_WRAP(q, pc) ((pc) >> (q)->shift)
+#define Q_IDX(q, pc) ((pc) & ((1 << (q)->shift) - 1))
+
+typedef struct SMMUDevice {
+    void             *smmu;
+    PCIBus           *bus;
+    int              devfn;
+    MemoryRegion     mr;
+    AddressSpace     as;
+} SMMUDevice;
+
+typedef struct SMMUInfo {
+    const char *name;
+    const char *desc;
+    SMMUImpl    impl;           /* SMMU Implementations */
+} SMMUInfo;
+
+typedef struct SMMUState {
+    SMMUInfo     *info;
+    uint8_t       regs[SMMU_NREGS * sizeof(uint32_t)];
+    uint32_t      cid[4];       /* Coresight registers */
+    uint32_t      pid[8];       /* ---"---- */
+
+    qemu_irq      irq[4];
+    uint32_t      version;
+
+    SMMUQueue     cmdq, evtq;
+
+#define SMMU_FEATURE_2LVL_STE (1<<0)
+    struct {                    /* Group may move to different struct */
+        uint32_t  features;
+        uint16_t  sid_size;
+        uint16_t  sid_split;
+        uint64_t  strtab_base;
+    };
+    /* Register space */
+    MemoryRegion  iomem;
+    /* IOMMU Address space */
+    MemoryRegion  iommu;
+    AddressSpace  iommu_as;
+
+    SMMUDevice    pbdev[PCI_DEVFN_MAX];
+} SMMUState;
+
+typedef enum {
+    CMD_Q_EMPTY,
+    CMD_Q_FULL,
+    CMD_Q_INUSE,
+} SMMUQStatus;
+
+static inline SMMUQStatus
+__smmu_queue_status(SMMUState *s, SMMUQueue *q)
+{
+    if ((q->prod == q->cons) && (q->wrap.prod != q->wrap.cons)) {
+        return CMD_Q_FULL;
+    } else if ((q->prod == q->cons) && (q->wrap.prod == q->wrap.cons)) {
+        return CMD_Q_EMPTY;
+    }
+
+    return CMD_Q_INUSE;
+}
+#define smmu_is_q_full(s, q) (__smmu_queue_status(s, q) == CMD_Q_FULL)
+#define smmu_is_q_empty(s, q) (__smmu_queue_status(s, q) == CMD_Q_EMPTY)
+
+static int __smmu_q_enabled(SMMUState *s, uint32_t q)
+{
+    return s->regs[SMMU_REG_CR0] & q;
+}
+#define smmu_cmd_q_enabled(s) __smmu_q_enabled(s, SMMU_CR0_CMDQ_ENABLE)
+#define smmu_evt_q_enabled(s) __smmu_q_enabled(s, SMMU_CR0_EVTQ_ENABLE)
+
+static inline int smmu_enabled(SMMUState *s)
+{
+    return (s->regs[SMMU_REG_CR0] & SMMU_CR0_SMMU_ENABLE) != 0;
+}
+
+static inline int __smmu_irq_enabled(SMMUState *s, uint32_t q)
+{
+    return s->regs[SMMU_REG_IRQ_CTRL] & q;
+}
+#define smmu_evt_irq_enabled(s)                   \
+    __smmu_irq_enabled(s, SMMU_IRQ_CTRL_EVENT_EN)
+#define smmu_gerror_irq_enabled(s)                  \
+    __smmu_irq_enabled(s, SMMU_IRQ_CTRL_GERROR_EN)
+#define smmu_pri_irq_enabled(s)                 \
+    __smmu_irq_enabled(s, SMMU_IRQ_CTRL_PRI_EN)
+
+static inline uint32_t smmu_read32_reg(SMMUState *s, uint32_t reg)
+{
+    return *(uint32_t *)&s->regs[reg];
+}
+
+static void smmu_write32_reg(SMMUState *s, uint32_t reg, uint32_t val)
+{
+    uint32_t *ptr = (uint32_t *)&s->regs[reg];
+    *ptr = val;
+}
+
+static inline uint64_t smmu_read64_reg(SMMUState *s, uint64_t reg)
+{
+    return *(uint64_t *)&s->regs[reg];
+}
+
+static inline void smmu_write64_reg(SMMUState *s, uint64_t reg, uint64_t val)
+{
+    uint64_t *ptr = (uint64_t *)&s->regs[reg];
+    *ptr = val;
+}
+
+static inline MemTxResult smmu_read_sysmem(SMMUState *s, hwaddr addr,
+                                           void *buf, int len)
+{
+    switch (len) {
+    case 4:
+        *(uint32_t *)buf = ldl_le_phys(&address_space_memory, addr);
+        break;
+    case 8:
+        *(uint64_t *)buf = ldq_le_phys(&address_space_memory, addr);
+        break;
+    default:
+        return address_space_rw(&address_space_memory, addr,
+                                MEMTXATTRS_UNSPECIFIED, buf, len, false);
+    }
+    return MEMTX_OK;
+}
+
+static inline void
+smmu_write_sysmem(SMMUState *s, hwaddr addr, void *buf, int len)
+{
+    switch (len) {
+    case 4:
+        stl_le_phys(&address_space_memory, addr, *(uint32_t *)buf);
+        break;
+    case 8:
+        stq_le_phys(&address_space_memory, addr, *(uint64_t *)buf);
+        break;
+    default:
+         address_space_rw(&address_space_memory, addr,
+                          MEMTXATTRS_UNSPECIFIED, buf, len, true);
+    }
+}
+
+typedef struct SMMUSysState {
+    /* <private> */
+    SysBusDevice  dev;
+    SMMUState     smmu_state;
+} SMMUSysState;
+
+#define SMMU_SYS_DEV(obj) OBJECT_CHECK(SMMUSysState, (obj), TYPE_SMMU_DEV_BASE)
+
+static inline int is_cd_valid(SMMUState *s, Ste *ste, Cd *cd)
+{
+    return CD_VALID(cd);
+}
+
+static inline int is_ste_valid(SMMUState *s, Ste *ste)
+{
+    return STE_VALID(ste);
+}
+
+static inline int is_ste_bypass(SMMUState *s, Ste *ste)
+{
+    return STE_CONFIG(ste) == STE_CONFIG_S1BY_S2BY;
+}
+
+static uint16_t smmu_get_sid(PCIBus *bus, int devfn)
+{
+    return  ((pci_bus_num(bus) & 0xff) << 8) | devfn;
+}
+
+static inline MemTxResult
+__smmu_read_aligned_sysmem(SMMUState *s, hwaddr addr, void *buf,
+                           int size, int len)
+{
+    for ( ; len; len -= size, buf += size, addr += size) {
+        MemTxResult ret = smmu_read_sysmem(s, addr, buf, size);
+        if (ret != MEMTX_OK) {
+            return ret;
+        }
+    }
+    return MEMTX_OK;
+}
+
+/*
+ * All SMMU data structures are little endian, and are aligned to 8 bytes
+ *  L1STE/STE/L1CD/CD, Queue entries in CMDQ/EVTQ/
+ */
+static inline int smmu_get_ste(SMMUState *s, hwaddr addr, Ste *buf)
+{
+    return __smmu_read_aligned_sysmem(s, addr, buf, sizeof(buf->word[0]),
+                                      ARRAY_SIZE(buf->word)) != MEMTX_OK;
+}
+
+/*
+ * For now we only support CD with a single entry, 'ssid' is used to identify
+ * otherwise
+ */
+static inline int smmu_get_cd(SMMUState *s, Ste *ste, uint32_t ssid, Cd *buf)
+{
+    hwaddr addr = STE_CTXPTR(ste);
+
+    if (STE_S1CDMAX(ste) != 0) {
+        SMMU_DPRINTF(CRIT, "Multilevel Ctx Descriptor not supported yet\n");
+    }
+
+    return __smmu_read_aligned_sysmem(s, addr, buf, sizeof(buf->word[0]),
+                                      ARRAY_SIZE(buf->word)) != MEMTX_OK;
+}
+
+static inline void
+smmu_write_event(SMMUState *s, hwaddr addr, Evt *evt)
+{
+    const int size = 4;
+    int len =  sizeof(Evt);
+    void *buf = evt;
+
+    for (; len; len -= size, buf += size, addr += size) {
+        smmu_write_sysmem(s, addr, buf, size);
+    }
+}
+
+#define STM2U64(stm) ({                                 \
+            uint64_t hi, lo;                            \
+            hi = (stm)->word[1];                        \
+            lo = (stm)->word[0] & ~(uint64_t)0x1f;      \
+            hi << 32 | lo;                              \
+        })
+
+#define STMSPAN(stm) (1 << (extract32((stm)->word[0], 0, 4) - 1))
+
+static int smmu_find_ste(SMMUState *s, uint16_t sid, Ste *ste)
+{
+    hwaddr addr;
+
+    SMMU_DPRINTF(STE, "SID:%x\n", sid);
+    /* Check SID range */
+    if (sid > (1 << s->sid_size)) {
+        return SMMU_EVT_C_BAD_SID;
+    }
+
+    if (s->features & SMMU_FEATURE_2LVL_STE) {
+        int span;
+        hwaddr stm_addr;
+        STEDesc stm;
+        int l1_ste_offset, l2_ste_offset;
+        SMMU_DPRINTF(STE, "no. ste: %x\n", s->sid_split);
+
+        l1_ste_offset = sid >> s->sid_split;
+        l2_ste_offset = sid & ((1 << s->sid_split) - 1);
+
+        stm_addr = (hwaddr)(s->strtab_base + l1_ste_offset * sizeof(stm));
+        smmu_read_sysmem(s, stm_addr, &stm, sizeof(stm));
+
+        SMMU_DPRINTF(STE, "strtab_base:%lx stm_addr:%lx\n"
+                     "l1_ste_offset:%x l1(64):%#016lx\n",
+                     s->strtab_base, stm_addr, l1_ste_offset, STM2U64(&stm));
+
+        span = STMSPAN(&stm);
+        SMMU_DPRINTF(STE, "l2_ste_offset:%x ~ span:%d\n", l2_ste_offset, span);
+        if (l2_ste_offset > span) {
+            return SMMU_EVT_C_BAD_STE;
+        }
+        addr = STM2U64(&stm) + l2_ste_offset * sizeof(*ste);
+    } else {
+        addr = s->strtab_base + sid * sizeof(*ste);
+    }
+
+    if (smmu_get_ste(s, addr, ste)) {
+        return SMMU_EVT_F_UUT;
+    }
+
+    return 0;
+}
+
+/*
+ * STE validity as per SMMUv3 11.0
+ */
+static int
+is_ste_consistent(SMMUState *s, Ste *ste)
+{
+    uint32_t _config = STE_CONFIG(ste) & 0x7,
+        idr0 = s->regs[SMMU_REG_IDR0],
+        idr5 = s->regs[SMMU_REG_IDR5];
+
+    uint32_t httu = extract32(idr0, 6, 2);
+    bool config[] = {_config & 0x1,
+                     _config & 0x2,
+                     _config & 0x3};
+    bool granule_supported = (1 << STE_S2TG(ste)) & (idr5 >> 4);
+
+    bool s1p = idr0 & SMMU_IDR0_S1P,
+        s2p = idr0 & SMMU_IDR0_S2P,
+        hyp = idr0 & SMMU_IDR0_HYP,
+        cd2l = idr0 & SMMU_IDR0_CD2L,
+        idr0_vmid = idr0 & SMMU_IDR0_VMID16,
+        ats = idr0 & SMMU_IDR0_ATS,
+        ttf0 = (idr0 >> 2) & 0x1,
+        ttf1 = (idr0 >> 3) & 0x1;
+
+    int ssidsz = (s->regs[SMMU_REG_IDR1] >> 6) & 0x1f;
+
+    uint32_t ste_vmid = STE_S2VMID(ste),
+        ste_eats = STE_EATS(ste),
+        ste_s2s = STE_S2S(ste),
+        ste_s1fmt = STE_S1FMT(ste),
+        aa64 = STE_S2AA64(ste),
+        ste_s1cdmax = STE_S1CDMAX(ste);
+
+    uint8_t ste_strw = STE_STRW(ste);
+    uint64_t oas, max_pa;
+    bool strw_ign;
+    bool addr_out_of_range;
+
+    if (!STE_VALID(ste)) {
+        return false;
+    }
+
+    if (!config[2]) {
+        if ((!s1p && config[0]) ||
+            (!s2p && config[1]) ||
+            (s2p && config[1])) {
+            return false;
+        }
+        if (!ssidsz && ste_s1cdmax && config[0] && !cd2l &&
+            (ste_s1fmt == 1 || ste_s1fmt == 2)) {
+            return false;
+        }
+        if (ats && ((_config & 0x3) == 0) &&
+            ((ste_eats == 2 && (_config != 0x7 || ste_s2s)) ||
+             (ste_eats == 1 && !ste_s2s))) {
+            return false;
+        }
+        if (config[0] && (ssidsz && (ste_s1cdmax > ssidsz))) {
+            return false;
+        }
+    }
+
+    oas = MIN(STE_S2PS(ste), idr5 & 0x7);
+
+    if (oas == 3) {
+        max_pa = ~(1UL << 42);
+    } else {
+        max_pa = ~(1UL << (32 + (oas * 4)));
+    }
+
+    strw_ign = (!s1p || !hyp || (_config == 4));
+
+    addr_out_of_range = (int64_t)(max_pa - STE_S2TTB(ste)) < 0;
+
+    if (config[1] &&
+        (!granule_supported || addr_out_of_range ||
+         (!aa64 && !ttf0) || (aa64 && ttf1)  ||
+         ((STE_S2HA(ste) || STE_S2HD(ste)) && !aa64) ||
+         ((STE_S2HA(ste) || STE_S2HD(ste)) && !httu) ||
+         (STE_S2HD(ste) && httu))) {
+        return false;
+    }
+    if (s2p && (config[0] == 0 && config[1]) &&
+        (strw_ign || !ste_strw) && !idr0_vmid && !(ste_vmid>>8)) {
+        return false;
+    }
+
+    return true;
+}
+
+static int tg2granule(int bits, bool tg1)
+{
+    switch (bits) {
+    case 1:
+        return tg1 ? 14 : 16;
+    case 2:
+        return tg1 ? 14 : 12;
+    case 3:
+        return tg1 ? 16 : 12;
+    default:
+        return 12;
+    }
+}
+
+static inline int oas2bits(int oas)
+{
+    switch (oas) {
+    case 2:
+        return 40;
+    case 3:
+        return 42;
+    case 4:
+        return 44;
+    case 5:
+    default: return 48;
+    }
+}
+
+typedef struct SMMUCfg {
+    union {
+        hwaddr va;              /* Input to S1 */
+        hwaddr ipa;             /* Input to S2 */
+    };
+    uint32_t oas;
+    uint32_t tsz;
+    uint64_t ttbr;
+    uint32_t granule;
+    uint32_t va_size;
+    uint32_t granule_sz;
+
+    union {
+        hwaddr opa;             /* Output from S2 */
+        hwaddr pa;              /* Output from S1, Final PA */
+    };
+
+    struct SMMUCfg *s2cfg;
+} SMMUCfg;
+
+static void smmu_cfg_populate_s2(Ste *ste, SMMUCfg *cfg)
+{                           /* stage 2 cfg */
+    bool s2a64 = STE_S2AA64(ste);
+
+    cfg->granule = STE_S2TG(ste);
+    cfg->tsz = STE_S2T0SZ(ste);
+    cfg->ttbr = STE_S2TTB(ste);
+    cfg->oas = oas2bits(STE_S2PS(ste));
+
+    if (s2a64) {
+        cfg->tsz = MIN(cfg->tsz, 39);
+        cfg->tsz = MAX(cfg->tsz, 16);
+    }
+    cfg->va_size = STE_S2AA64(ste) ? 64 : 32;
+    cfg->granule_sz = tg2granule(cfg->granule, 0) - 3;
+}
+
+static void smmu_cfg_populate_s1(Cd *cd, SMMUCfg *cfg)
+{                           /* stage 1 cfg */
+    bool s1a64 = CD_AARCH64(cd);
+
+    cfg->granule = (CD_EPD0(cd)) ? CD_TG1(cd) : CD_TG0(cd);
+    cfg->tsz = (CD_EPD0(cd)) ? CD_T1SZ(cd) : CD_T0SZ(cd);
+    cfg->ttbr = (CD_EPD0(cd)) ? CD_TTB1(cd) : CD_TTB0(cd);
+    cfg->oas = oas2bits(CD_IPS(cd));
+
+    if (s1a64) {
+        cfg->tsz = MIN(cfg->tsz, 39);
+        cfg->tsz = MAX(cfg->tsz, 16);
+    }
+    cfg->va_size = CD_AARCH64(cd) ? 64 : 32;
+    cfg->granule_sz = tg2granule(cfg->granule, CD_EPD0(cd)) - 3;
+}
+
+static SMMUEvtErr
+smmu_get_phys_addr(SMMUState *s, SMMUCfg *cfg, Ste *ste,
+                   Cd *cd, uint32_t *pagesize, uint32_t *perm,
+                   bool stage2, bool is_write)
+{
+    int     ret, level;
+    int     granule_sz = cfg->granule_sz;
+    int     va_size = cfg->va_size;
+    hwaddr  va, addr, mask;
+    hwaddr *outaddr;
+    bool    s2needed   = false;
+
+    va = addr = cfg->va;        /* or ipa in Stage2 */
+
+    s2needed = !stage2 && (STE_CONFIG(ste) == STE_CONFIG_S1TR_S2TR);
+    if (s2needed) {
+        smmu_cfg_populate_s2(ste, cfg->s2cfg);
+    }
+
+    assert(va_size == 64);      /* We dont support 32-bit yet */
+
+    outaddr = stage2 ? &cfg->opa : &cfg->pa; /* same location, for clearity */
+
+    level = 4 - (va_size - cfg->tsz - 4) / granule_sz;
+
+    mask = (1ULL << (granule_sz + 3)) - 1;
+
+    addr = extract64(cfg->ttbr, 0, 48);
+    addr &= ~((1ULL << (va_size - cfg->tsz - (granule_sz * (4 - level)))) - 1);
+
+    for (;;) {
+        uint64_t desc;
+
+        addr |= (va >> (granule_sz * (4 - level))) & mask;
+        addr &= ~7ULL;
+
+        if (smmu_read_sysmem(s, addr, &desc, sizeof(desc))) {
+            ret = SMMU_EVT_F_WALK_EXT_ABRT;
+            SMMU_DPRINTF(CRIT, "Translation table read error lvl:%d\n", level);
+            break;
+        }
+        SMMU_DPRINTF(TT_1,
+                     "Level: %d granule_sz:%d mask:%lx addr:%lx desc:%lx\n",
+                     level, granule_sz, mask, addr, desc);
+
+        if (!(desc & 1) ||
+            (!(desc & 2) & (level == 3))) {
+            ret = SMMU_EVT_F_TRANS;
+            break;
+        }
+
+        if (s2needed) {   /* We call again to resolve address at this 'level' */
+            uint32_t unused1, unused2 ATTRIBUTE_UNUSED;
+            SMMUCfg *s2cfg = cfg->s2cfg;
+            s2cfg->ipa = desc;
+            ret = smmu_get_phys_addr(s, s2cfg, ste, cd, &unused1,
+                                     &unused2, true, is_write);
+            if (ret) {
+                break;
+            }
+            desc = (uint64_t)s2cfg->opa;
+        }
+
+        addr = desc & 0xfffffff000ULL;
+        if ((desc & 2) && (level < 3)) {
+            level++;
+            continue;
+        }
+        *pagesize = (1ULL << ((granule_sz * (4 - level)) + 3));
+        addr |= (va & (*pagesize - 1));
+        SMMU_DPRINTF(TT_1, "addr:%lx pagesize:%x\n", addr, *pagesize);
+        break;
+    }
+
+    if (ret == 0) {
+        *outaddr = addr;
+    }
+
+    return ret;
+}
+
+static SMMUEvtErr smmu_walk_pgtable(SMMUState *s, Ste *ste, Cd *cd,
+                                    IOMMUTLBEntry *tlbe, bool is_write)
+{
+    SMMUCfg cfg[2] = {{{0,} } };
+    SMMUCfg *s1cfg = &cfg[0], *s2cfg = &cfg[1];
+    SMMUEvtErr retval = 0;
+    uint32_t ste_cfg = STE_CONFIG(ste);
+    uint32_t page_size = 0, perm = 0;
+    hwaddr pa;                 /* Input address, output address */
+
+    SMMU_DPRINTF(DBG1, "ste_cfg :%x\n", ste_cfg);
+    /* Both Bypass, we dont need to do anything */
+    if (ste_cfg == STE_CONFIG_S1BY_S2BY) {
+        return 0;
+    }
+    s1cfg->va = tlbe->iova;
+
+    SMMU_DPRINTF(TT_1, "Input addr: %lx ste_config:%d\n",
+                 s1cfg->va, ste_cfg);
+
+    if (ste_cfg == STE_CONFIG_S1TR_S2BY || ste_cfg == STE_CONFIG_S1TR_S2TR) {
+        smmu_cfg_populate_s1(cd, s1cfg);
+
+        s1cfg->oas = MIN(oas2bits(smmu_read32_reg(s, SMMU_REG_IDR5) & 0xf),
+                         s1cfg->oas);
+        /* fix ttbr - make top bits zero*/
+        cfg->ttbr = extract64(cfg->ttbr, 0, cfg->oas);
+        s1cfg->s2cfg = s2cfg;
+
+        retval = smmu_get_phys_addr(s, s1cfg, ste, cd, &page_size, &perm,
+                                    false, is_write);
+        if (retval != 0) {
+            SMMU_DPRINTF(CRIT, "FAILED Stage1 translation\n");
+            goto exit;
+        }
+        pa = cfg->pa;
+        SMMU_DPRINTF(DBG1, "DONE: Stage1 tanslated :%lx\n ", pa);
+
+    } else if (ste_cfg == STE_CONFIG_S1BY_S2TR) {
+        /* Stage2 only configuratoin */
+        smmu_cfg_populate_s2(ste, s2cfg);
+
+        s2cfg->oas = MIN(oas2bits(smmu_read32_reg(s, SMMU_REG_IDR5) & 0xf),
+                         s2cfg->oas);
+        /* fix ttbr - make top bits zero*/
+        cfg->ttbr = extract64(cfg->ttbr, 0, cfg->oas);
+
+        retval = smmu_get_phys_addr(s, s2cfg, ste, cd, &page_size,
+                                    &perm, true, is_write);
+        if (retval != 0) {
+            SMMU_DPRINTF(CRIT, "FAILED Stage2 translation\n");
+            goto exit;
+        }
+        pa = s2cfg->opa;
+        SMMU_DPRINTF(DBG1, "DONE: Stage2 tanslated :%lx\n ", pa);
+    }
+
+    SMMU_DPRINTF(TT_1, "DONE: translation o/p addr:%lx mask:%x is_write:%d\n ",
+                 pa, page_size-1, is_write);
+    tlbe->translated_addr = pa;
+    tlbe->addr_mask = page_size - 1;
+    tlbe->perm = perm;
+exit:
+    return retval;
+}
+
+/*
+ * smmu_irq_update:
+ * update corresponding register,
+ * return > 0 when IRQ is supposed to be rased
+ */
+static int
+smmu_irq_update(SMMUState *s, int irq, uint64_t data)
+{
+    uint32_t error = 0;
+
+    switch (irq) {
+    case SMMU_IRQ_EVTQ:
+        if (smmu_evt_irq_enabled(s)) {
+            error = SMMU_GERROR_EVENTQ;
+        }
+        break;
+    case SMMU_IRQ_CMD_SYNC:
+        if (smmu_gerror_irq_enabled(s)) {
+            uint32_t err_type = (uint32_t)data;
+            if (err_type) {
+                uint32_t regval = smmu_read32_reg(s, SMMU_REG_CMDQ_CONS);
+                smmu_write32_reg(s, SMMU_REG_CMDQ_CONS,
+                                 regval | err_type << SMMU_CMD_CONS_ERR_SHIFT);
+            }
+            error = SMMU_GERROR_CMDQ;
+        }
+        break;
+    case SMMU_IRQ_PRIQ:
+        if (smmu_pri_irq_enabled(s)) {
+            error = SMMU_GERROR_PRIQ;
+        }
+        break;
+    }
+    SMMU_DPRINTF(DBG2, "<< error:%x\n", error);
+    if (error && smmu_gerror_irq_enabled(s)) {
+        uint32_t val = smmu_read32_reg(s, SMMU_REG_GERROR);
+        SMMU_DPRINTF(DBG2, "<<<< error:%x gerror:%x\n", error, val);
+        smmu_write32_reg(s, SMMU_REG_GERROR, val ^ error);
+    }
+    return error;
+}
+
+static void smmu_irq_raise(SMMUState *s, int irq, uint64_t data)
+{
+    SMMU_DPRINTF(IRQ, "irq:%d\n", irq);
+
+    if (s->info->impl == SMMU_IMPL_BRCM) {
+        uint32_t val = smmu_read32_reg(s, SMMU_REG_INTERRUPT);
+
+        SMMU_DPRINTF(IRQ, "irq:%d reg_interrupt:%x\n", irq, val);
+
+        switch (irq) {
+        case SMMU_IRQ_EVTQ:
+            val |= SMMU_INTR_EVENT;
+            break;
+        case SMMU_IRQ_PRIQ:
+            val |= SMMU_INTR_PRI;
+            break;
+        case SMMU_IRQ_CMD_SYNC:
+            val |= SMMU_INTR_CMD_SYNC;
+            break;
+        }
+
+        smmu_write32_reg(s, SMMU_REG_INTERRUPT, val | SMMU_INTR_GERROR);
+    }
+
+    if (smmu_irq_update(s, irq, data)) {
+        /*
+         * Single interrupt pin in Broadcom implementation,
+         * PRIq not supported
+         */
+        if (s->info->impl == SMMU_IMPL_BRCM) {
+            qemu_irq_raise(s->irq[0]);
+        } else {
+            qemu_irq_raise(s->irq[irq]);
+        }
+    }
+}
+
+/*
+ * Events created on the EventQ
+ */
+static void smmu_create_event(SMMUState *s, hwaddr iova,
+                              uint32_t sid, bool is_write, int error)
+{
+    SMMUQueue *q = &s->evtq;
+    uint64_t head = Q_IDX(q, q->prod);
+    bool overflow = true, setva = false;
+    Evt evt;
+
+    if (!smmu_evt_q_enabled(s)) {
+        overflow = true;
+        goto set_overflow;
+    }
+
+    if (!smmu_is_q_full(s, &s->evtq)) {
+        overflow = true;
+        goto set_overflow;
+    }
+
+    EVT_SET_TYPE(&evt, error);
+    EVT_SET_SID(&evt, sid);
+
+    switch (error) {
+    case SMMU_EVT_F_UUT:
+    case SMMU_EVT_C_BAD_STE:
+        break;
+    case SMMU_EVT_C_BAD_CD:
+    case SMMU_EVT_F_CD_FETCH:
+        break;
+    case SMMU_EVT_F_TRANS_FORBIDDEN:
+    case SMMU_EVT_F_WALK_EXT_ABRT:
+        setva = true;
+    default:
+        break;
+    }
+    if (setva) {
+        EVT_SET_INPUT_ADDR(&evt, iova);
+    }
+    smmu_write_sysmem(s, Q_ENTRY(q, head), &evt, sizeof(evt));
+
+    head++;
+
+set_overflow:
+    if (overflow) {
+        head ^= 1 << 31;
+    } else if (smmu_evt_irq_enabled(s)) {
+        smmu_irq_raise(s, SMMU_IRQ_EVTQ, (uint64_t)&evt);
+    }
+    q->prod = head;
+
+    smmu_write32_reg(s, SMMU_REG_EVTQ_PROD, head);
+}
+
+/*
+ * TR - Translation Request
+ * TT - Translated Tansaction
+ * OT - Other Transaction
+ */
+static IOMMUTLBEntry
+smmu_translate(MemoryRegion *mr, hwaddr addr, bool is_write)
+{
+
+    SMMUDevice *sdev = container_of(mr, SMMUDevice, mr);
+    SMMUState *s = sdev->smmu;
+    uint16_t sid = 0, config;
+    Ste ste;
+    Cd cd;
+    SMMUEvtErr error = 0;
+
+    IOMMUTLBEntry ret = {
+        .target_as = &address_space_memory,
+        .iova = addr,
+        .translated_addr = addr,
+        .addr_mask = ~(hwaddr)0,
+        .perm = IOMMU_NONE,
+    };
+
+    /* SMMU Bypass */
+    /* We allow traffic through if SMMU is disabled */
+    if (!smmu_enabled(s)) {
+        SMMU_DPRINTF(CRIT, "SMMU Not enabled.. bypassing addr:%lx\n", addr);
+        goto bypass;
+    }
+
+    sid = smmu_get_sid(sdev->bus, sdev->devfn);
+    SMMU_DPRINTF(TT_1, "SID:%x bus:%d\n", sid, pci_bus_num(sdev->bus));
+
+    /* Fetch & Check STE */
+    error = smmu_find_ste(s, sid, &ste);
+    if (error) {
+        goto error_out;  /* F_STE_FETCH or F_CFG_CONFLICT */
+    }
+
+    if (IS_DBG_ENABLED(STE)) {
+        dump_ste(&ste);
+    }
+
+    if (is_ste_valid(s, &ste) && is_ste_bypass(s, &ste)) {
+        goto bypass;
+    }
+
+    SMMU_DPRINTF(STE, "STE is not bypass\n");
+    if (!is_ste_consistent(s, &ste)) {
+        error = SMMU_EVT_C_BAD_STE;
+        goto error_out;
+    }
+    SMMU_DPRINTF(INFO, "Valid STE Found\n");
+
+    /* Stream Bypass */
+    config = STE_CONFIG(&ste);
+    /*
+     * Mostly we have S1-Translate and S2-Bypass, Others will be
+     * implemented as we go
+     */
+    switch (config) {
+    case STE_CONFIG_S1BY_S2BY:  /* S1-bypass, S2-bypass */
+        goto bypass;
+
+    case STE_CONFIG_S1TR_S2TR:  /* S1-trans, S2-trans, assume S1-Only */
+        SMMU_DPRINTF(CRIT, "S1+S2 translation, not supported\n");
+        break;
+    case STE_CONFIG_S1TR_S2BY:        /* S1-Trans, S2-bypass */
+        smmu_get_cd(s, &ste, 0, &cd); /* We dont have SSID yet, so 0 */
+
+        if (IS_DBG_ENABLED(CD)) {
+            dump_cd(&cd);
+        }
+
+        if (!is_cd_valid(s, &ste, &cd)) {
+            error = SMMU_EVT_C_BAD_CD;
+            goto error_out;
+        }
+        break;
+    case STE_CONFIG_S1BY_S2TR:
+        SMMU_DPRINTF(CRIT, "S2-only translation, not supported right now\n");
+        goto out;
+        break;
+    default:
+        SMMU_DPRINTF(CRIT, "Unknown config field in STE\n");
+        goto out;
+    }
+
+    /* Walk Stage1, if S2 is enabled, S2 walked for Every access on S1 */
+    error = smmu_walk_pgtable(s, &ste, &cd, &ret, is_write);
+
+    SMMU_DPRINTF(INFO, "DONE walking tables(1)\n");
+error_out:
+    if (error) {        /* Post the Error using Event Q */
+        SMMU_DPRINTF(CRIT, "Translation Error: %x\n", error);
+        smmu_create_event(s, ret.iova, sid, is_write, error);
+        goto out;
+    }
+
+bypass:
+    ret.perm = is_write ? IOMMU_RW : IOMMU_RO;
+
+out:
+    return ret;
+}
+
+static const MemoryRegionIOMMUOps smmu_ops = {
+    .translate = smmu_translate,
+};
+
+
+static bool
+smmu_is_irq_pending(SMMUState *s, int irq)
+{
+    return (smmu_read32_reg(s, SMMU_REG_INTERRUPT) & 0xf) |
+        (smmu_read32_reg(s, SMMU_REG_GERROR) ^
+         smmu_read32_reg(s, SMMU_REG_GERRORN));
+}
+
+static void
+smmu_irq_clear_brcm(SMMUState *s, int irq)
+{
+    uint32_t val = 0;
+
+    val = smmu_read32_reg(s, SMMU_REG_INTERRUPT);
+    SMMU_DPRINTF(IRQ, "Clearing IRQ:%d reg_interrupt:%x\n", irq, val);
+
+    switch (irq) {
+    case SMMU_GERROR_CMDQ:
+        val ^= SMMU_INTR_CMD_SYNC;
+        break;
+    case SMMU_GERROR_EVENTQ:
+        val ^= SMMU_INTR_EVENT;
+        break;
+    case SMMU_GERROR_PRIQ:
+        val ^= SMMU_INTR_PRI;
+        break;
+    }
+    val ^= SMMU_INTR_GERROR;
+
+    smmu_write32_reg(s, SMMU_REG_INTERRUPT, val);
+}
+
+/*
+ * GERROR is updated when rasing an interrupt, GERRORN will be updated
+ * by s/w and should match GERROR before normal operation resumes.
+ */
+static void smmu_irq_clear(SMMUState *s, uint64_t gerrorn)
+{
+    int irq_new = SMMU_IRQ_GERROR;
+    uint32_t toggled;
+
+    toggled = smmu_read32_reg(s, SMMU_REG_GERRORN) ^ gerrorn;
+
+    while (toggled) {
+        int intr = ctz32(toggled);
+
+        if (s->info->impl == SMMU_IMPL_BRCM) {
+            smmu_irq_clear_brcm(s, intr);
+        } else {
+            qemu_irq_lower(s->irq[irq_new]);
+        }
+
+        toggled &= toggled - 1;
+    }
+}
+
+static int smmu_evtq_update(SMMUState *s)
+{
+    if (!smmu_enabled(s)) {
+        return 0;
+    }
+    return 1;
+}
+
+#define SMMU_CMDQ_ERR(s) ((smmu_read32_reg(s, SMMU_REG_GERROR) ^    \
+                           smmu_read32_reg(s, SMMU_REG_GERRORN)) &  \
+                          SMMU_GERROR_CMDQ)
+
+static int smmu_cmdq_consume(SMMUState *s)
+{
+    SMMUQueue *q = &s->cmdq;
+    uint64_t val = 0;
+    uint32_t error = SMMU_CMD_ERR_NONE;
+    SMMU_DPRINTF(CMDQ, "CMDQ_ERR: %d\n", SMMU_CMDQ_ERR(s));
+    while (!SMMU_CMDQ_ERR(s) && !smmu_is_q_empty(s, &s->cmdq)) {
+        Cmd cmd;
+        hwaddr addr;
+
+        addr = q->base + (sizeof(cmd) * q->cons);
+
+        if (smmu_read_sysmem(s, addr, &cmd, sizeof(cmd)) != MEMTX_OK) {
+            error = SMMU_CMD_ERR_ABORT;
+            goto out_while;
+        }
+
+        switch (CMD_TYPE(&cmd)) {
+        case SMMU_CMD_CFGI_STE:
+        case SMMU_CMD_CFGI_STE_RANGE:
+            break;
+        case SMMU_CMD_TLBI_NSNH_ALL: /* TLB not implemented */
+        case SMMU_CMD_TLBI_EL2_ALL:  /* Fallthrough */
+        case SMMU_CMD_TLBI_EL3_ALL:
+        case SMMU_CMD_TLBI_NH_ALL:
+            break;
+        case SMMU_CMD_SYNC:     /* Fallthrough */
+            if (CMD_CS(&cmd) & CMD_SYNC_SIG_IRQ) {
+                smmu_irq_raise(s, SMMU_IRQ_CMD_SYNC, SMMU_CMD_ERR_NONE);
+            }
+        case SMMU_CMD_PREFETCH_CONFIG:
+            break;
+        case SMMU_CMD_TLBI_NH_ASID:
+        case SMMU_CMD_TLBI_NH_VA:   /* too many of this is sent */
+            break;
+
+        default:
+            error = SMMU_CMD_ERR_ILLEGAL;
+            SMMU_DPRINTF(CRIT, "Unknown Command type: %x, ignoring\n",
+                         CMD_TYPE(&cmd));
+            if (IS_DBG_ENABLED(CD)) {
+                dump_cmd(&cmd);
+            }
+            break;
+        }
+
+        if (error) {
+            SMMU_DPRINTF(INFO, "CMD Error\n");
+            break;
+        }
+
+        q->cons++;
+        if (q->cons == q->entries) {
+            q->cons = 0;
+            q->wrap.cons++;     /* this will toggle */
+        }
+    }
+
+out_while:
+    if (error) {
+        smmu_irq_raise(s, SMMU_IRQ_GERROR, error);
+    }
+    val |= (q->wrap.cons << q->shift) | q->cons;
+
+    SMMU_DPRINTF(CMDQ, "prod_wrap:%d, prod:%x cons_wrap:%d cons:%x\n",
+                 s->cmdq.wrap.prod, s->cmdq.prod,
+                 s->cmdq.wrap.cons, s->cmdq.cons);
+    /* Update consumer pointer */
+    smmu_write32_reg(s, SMMU_REG_CMDQ_CONS, val);
+
+    return 0;
+}
+
+static void smmu_update(SMMUState *s)
+{
+    int error = 0;
+
+    /* SMMU starts processing commands even when not enabled */
+    if (!smmu_enabled(s)) {
+        goto check_cmdq;
+    }
+    /* EVENT Q updates takes more priority */
+    if ((smmu_evt_q_enabled(s))) {
+        error = smmu_evtq_update(s);
+    }
+    if (error) {
+        smmu_create_event(s, 0, 0, 0, error);
+    }
+check_cmdq:
+    if (smmu_cmd_q_enabled(s) && !SMMU_CMDQ_ERR(s)) {
+        smmu_cmdq_consume(s);
+    }
+}
+
+static inline void
+smmu_update_base(SMMUState *s, uint32_t reg)
+{
+    uint64_t *base = NULL;
+
+    switch (reg) {
+    case SMMU_REG_STRTAB_BASE:
+    case SMMU_REG_STRTAB_BASE + 4:
+        base = &s->strtab_base;
+        reg = SMMU_REG_STRTAB_BASE;
+        break;
+    case SMMU_REG_EVTQ_BASE + 4:
+    case SMMU_REG_EVTQ_BASE:
+        base = &s->evtq.base;
+        reg = SMMU_REG_EVTQ_BASE;
+        break;
+    case SMMU_REG_CMDQ_BASE + 4:
+    case SMMU_REG_CMDQ_BASE:
+        base = &s->cmdq.base;
+        reg = SMMU_REG_CMDQ_BASE;
+        break;
+    }
+
+    /* BIT[62], BIT[5:0] are ignored */
+    *base = smmu_read64_reg(s, reg) & ~(SMMU_BASE_RA | 0x3fUL);
+}
+
+static inline void
+smmu_update_q(SMMUState *s, SMMUQueue *q, uint32_t val, uint32_t reg)
+{
+    bool update = false;
+
+    switch (reg) {
+    case SMMU_REG_CMDQ_BASE:
+    case SMMU_REG_EVTQ_BASE:
+        q->shift = val & 0x1f;
+        q->entries = 1 << (q->shift);
+        break;
+    case SMMU_REG_CMDQ_PROD:
+        update = 1;
+    case SMMU_REG_EVTQ_PROD:
+        q->prod = Q_IDX(q, val);
+        q->wrap.prod = val >> q->shift;
+        break;
+    case SMMU_REG_EVTQ_CONS:
+    case SMMU_REG_CMDQ_CONS:
+        q->cons = Q_IDX(q, val);
+        q->wrap.cons = val >> q->shift;
+        break;
+    }
+
+    if (update) {
+        smmu_update(s);
+    }
+}
+
+static void smmu_write_mmio(void *opaque, hwaddr addr,
+                            uint64_t val, unsigned size)
+{
+    SMMUState *s = opaque;
+    SMMUQueue *q = NULL;
+    int i;
+    bool update_queue = false;
+    bool is64 = false;
+    bool base = false;
+    uint32_t val32 = (uint32_t)val;
+    SMMU_DPRINTF(DBG2, "reg:%lx cur: %x new: %lx\n", addr,
+                 smmu_read32_reg(s, addr), val);
+
+    /* We update the ACK registers, actual write happens towards end */
+
+    switch (addr) {
+    case SMMU_REG_IRQ_CTRL:     /* Update the ACK as well */
+        val &= 0xf;
+
+        for (i = 0; i < 4; i++)
+            if (!(val & (1 << i))) {
+                qemu_irq_lower(s->irq[i]);
+            }
+
+        smmu_write32_reg(s, addr + 4, val32);
+        break;
+
+    case SMMU_REG_CR0:
+        smmu_write32_reg(s, addr + 4, val32);
+        smmu_update(s);         /* Start processing as soon as enabled */
+        break;
+
+    case SMMU_REG_GERRORN:
+        smmu_irq_clear(s, val32);
+        smmu_write32_reg(s, SMMU_REG_GERRORN, val32);
+        SMMU_DPRINTF(IRQ, "irq pend: %d reg_intr:%x gerror:%x gerrorn:%x\n",
+                     smmu_is_irq_pending(s, 0),
+                     smmu_read32_reg(s, SMMU_REG_INTERRUPT),
+                     smmu_read32_reg(s, SMMU_REG_GERROR),
+                     smmu_read32_reg(s, SMMU_REG_GERRORN));
+        /* Clear only when no more left */
+        if ((s->info->impl == SMMU_IMPL_BRCM) && !smmu_is_irq_pending(s, 0)) {
+            qemu_irq_lower(s->irq[0]);
+        }
+        return;                 /* No further processing */
+
+    case SMMU_REG_CMDQ_BASE:
+        is64 = true;            /* fallthru */
+    case SMMU_REG_CMDQ_BASE + 4:
+        base = true;
+    case SMMU_REG_CMDQ_PROD:
+    case SMMU_REG_CMDQ_CONS:
+        q = &s->cmdq;
+        update_queue = true;
+        break;
+    case SMMU_REG_EVTQ_BASE:
+        is64 = true;            /* fallthru */
+    case SMMU_REG_EVTQ_BASE + 4:
+        base = true;
+    case SMMU_REG_EVTQ_CONS:
+    case SMMU_REG_EVTQ_PROD:
+        q = &s->evtq;
+        update_queue = true;
+        break;
+
+    case SMMU_REG_STRTAB_BASE:
+        is64 = true;
+    case SMMU_REG_STRTAB_BASE + 4:
+        base = true;
+        break;
+
+    case SMMU_REG_STRTAB_BASE_CFG:
+        is64 = true;
+        if (((val32 >> 16) & 0x3) == 0x1) {
+            s->sid_split = (val32 >> 6) & 0x1f;
+            s->features |= SMMU_FEATURE_2LVL_STE;
+        }
+        break;
+    case SMMU_REG_INTERRUPT_EN: /* Valid in BRCM implementation */
+        break;
+    case SMMU_REG_PRIQ_BASE ... SMMU_REG_PRIQ_IRQ_CFG1:
+        SMMU_DPRINTF(CRIT, "Trying to write to PRIQ, not implemented\n");
+        break;
+
+    case SMMU_REG_GERROR_IRQ_CFG0 ...  SMMU_REG_GERROR_IRQ_CFG2:
+    case SMMU_REG_EVTQ_IRQ_CFG0 ... SMMU_REG_EVTQ_IRQ_CFG2:
+        return; /* RAZ/WI */
+
+    default:
+    case SMMU_REG_STATUSR:
+    case 0xFDC ... 0xFFC:
+    case SMMU_REG_IDR0 ... SMMU_REG_IDR5:
+        SMMU_DPRINTF(CRIT, "write to RO/Unimpl reg %lx val64:%lx val32:%x\n",
+                     addr, val, val32);
+        return;
+    }
+
+    if (is64) {
+        SMMU_DPRINTF(CRIT, "64bit write, reg:%lx val:%lx\n", addr, val);
+        smmu_write64_reg(s, addr, val);
+    } else {
+        smmu_write32_reg(s, addr, val32);
+    }
+
+    if (base) {
+        smmu_update_base(s, addr);
+    }
+    if (update_queue) {
+        smmu_update_q(s, q, val, addr);
+    }
+}
+
+
+static uint64_t smmu_read_mmio(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    SMMUState *s = opaque;
+    uint64_t val;
+
+    /* Primecell/Corelink ID registers */
+    switch (addr) {
+    case 0xFF0 ... 0xFFC:
+        val = (uint64_t)s->cid[(addr - 0xFF0)>>2]; break;
+
+    case 0xFDC ... 0xFE4:
+        val = (uint64_t)s->pid[(addr - 0xFDC)>>2]; break;
+
+    default:
+    case SMMU_REG_IDR0 ... SMMU_REG_GERROR_IRQ_CFG1:
+        val = (uint64_t)smmu_read32_reg(s, addr); break;
+
+    case SMMU_REG_STRTAB_BASE ... SMMU_REG_CMDQ_BASE:
+    case SMMU_REG_EVTQ_BASE:
+    case SMMU_REG_PRIQ_BASE ... SMMU_REG_PRIQ_IRQ_CFG1:
+        val = smmu_read64_reg(s, addr); break;
+    }
+
+    SMMU_DPRINTF(DBG2, "addr: %lx val:%lx\n", addr, val);
+    return val;
+}
+
+static const MemoryRegionOps smmu_mem_ops = {
+    .read = smmu_read_mmio,
+    .write = smmu_write_mmio,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 8,
+    },
+};
+
+static AddressSpace *smmu_pci_iommu(PCIBus *bus, void *opaque, int devfn)
+{
+    SMMUState *s = opaque;
+    SMMUDevice *sdev = &s->pbdev[PCI_SLOT(devfn)];
+    SMMUSysState *sys = container_of(s, SMMUSysState, smmu_state);
+
+    sdev->smmu = s;
+    sdev->bus = bus;
+    sdev->devfn = devfn;
+
+    memory_region_init_iommu(&sdev->mr, OBJECT(sys),
+                             &smmu_ops, "smmuv3", UINT64_MAX);
+
+    address_space_init(&sdev->as, &sdev->mr, "smmu-pci");
+
+    return &sdev->as;
+}
+
+static void smmu_init_iommu_as(SMMUSysState *sys)
+{
+    SMMUState *s = &sys->smmu_state;
+    PCIBus *pcibus = pci_find_primary_bus();
+
+    if (pcibus) {
+        SMMU_DPRINTF(CRIT, "Found PCI bus, setting up iommu\n");
+        pci_setup_iommu(pcibus, smmu_pci_iommu, s);
+    } else {
+        SMMU_DPRINTF(CRIT, "Could'nt find PCI bus, SMMU is not registered\n");
+    }
+}
+
+typedef struct {
+    /* <private> */
+    SysBusDeviceClass parent_class;
+    SMMUInfo *info;
+} SMMUBaseClass;
+
+#define SMMU_DEVICE_CLASS(klass)                                    \
+    OBJECT_CLASS_CHECK(SMMUBaseClass, (klass), TYPE_SMMU_DEV_BASE)
+#define SMMU_DEVICE_GET_CLASS(obj)                              \
+    OBJECT_GET_CLASS(SMMUBaseClass, (obj), TYPE_SMMU_DEV_BASE)
+
+static void smmu_configure(SMMUState *s, SysBusDevice *dev)
+{
+    int i;
+
+    switch (s->info->impl) {
+    default:
+    case SMMU_IMPL_ARM:
+        for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
+            sysbus_init_irq(dev, &s->irq[i]);
+        }
+        break;
+    case SMMU_IMPL_BRCM:
+        sysbus_init_irq(dev, &s->irq[0]);
+        break;
+    }
+}
+
+static int smmu_init(SysBusDevice *dev)
+{
+    SMMUSysState *sys = SMMU_SYS_DEV(dev);
+    SMMUBaseClass *sbc = SMMU_DEVICE_GET_CLASS(sys);
+    SMMUState *s = &sys->smmu_state;
+
+    /* Register Access */
+    memory_region_init_io(&s->iomem, OBJECT(sys),
+                          &smmu_mem_ops, s, "smmuv3", 0x1000);
+
+    sysbus_init_mmio(dev, &s->iomem);
+
+    s->info = sbc->info;
+
+    smmu_configure(s, dev);
+    smmu_init_iommu_as(sys);
+
+    return 0;
+}
+
+static void smmu_populate_regs(SMMUState *s)
+{
+    int i;
+    uint32_t val;
+
+    /* Primecell ID registers */
+    s->cid[0] = 0x0D;
+    s->cid[1] = 0xF0;
+    s->cid[2] = 0x05;
+    s->cid[3] = 0xB1;
+
+    for (i = 0; i < ARRAY_SIZE(s->pid); i++) {
+        s->pid[i] = 0x1;
+    }
+    /* Only IDR0-5 will show what features supported */
+    val =
+        1 << 27 |                   /* 2 Level stream id */
+        1 << 26 |                   /* Term Model  */
+        1 << 24 |                   /* Stall model not supported */
+        1 << 18 |                   /* VMID 16 bits */
+        1 << 16 |                   /* PRI */
+        1 << 12 |                   /* ASID 16 bits */
+        1 << 10 |                   /* ATS */
+        1 << 9 |                    /* HYP */
+        2 << 6 |                    /* HTTU */
+        1 << 4 |                    /* COHACC */
+        2 << 2 |                    /* TTF=Arch64 */
+        1 << 1 |                    /* Stage 1 */
+        1 << 0;                     /* Stage 2 */
+
+    smmu_write32_reg(s, SMMU_REG_IDR0, val);
+
+#define SMMU_SID_SIZE    16
+    s->sid_size = SMMU_SID_SIZE;
+
+#define SMMU_QUEUE_SIZE_LOG2 19
+    val =
+        1 << 27 |                    /* Attr Types override */
+        SMMU_QUEUE_SIZE_LOG2 << 21 | /* Cmd Q size */
+        SMMU_QUEUE_SIZE_LOG2 << 16 | /* Event Q size */
+        SMMU_QUEUE_SIZE_LOG2 << 11 | /* PRI Q size */
+        0  << 6 |                    /* SSID not supported */
+        SMMU_SID_SIZE << 0 ;         /* SID size  */
+
+    smmu_write32_reg(s, SMMU_REG_IDR1, val);
+
+    val =
+        1 << 6 |                    /* Granule 16K */
+        1 << 4 |                    /* Granule 4K */
+        4 << 0;                     /* OAS = 44 bits */
+
+    smmu_write32_reg(s, SMMU_REG_IDR5, val);
+
+    s->cmdq.entries = (smmu_read32_reg(s, SMMU_REG_IDR1) >> 21) & 0x1f;
+    s->cmdq.ent_size = sizeof(Cmd);
+    s->evtq.entries = (smmu_read32_reg(s, SMMU_REG_IDR1) >> 16) & 0x1f;
+    s->evtq.ent_size = sizeof(Evt);
+}
+
+static void smmu_reset(DeviceState *dev)
+{
+    SMMUSysState *sys = SMMU_SYS_DEV(dev);
+    SMMUState *s = &sys->smmu_state;
+
+    smmu_populate_regs(s);
+}
+
+/*
+ * DUMMY: Will get to this one day
+ */
+static const VMStateDescription vmstate_smmu = {
+    .name = "smmu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY(regs, SMMUState, SMMU_NREGS * sizeof(uint32_t)),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void smmu_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    SMMUBaseClass *sbc = SMMU_DEVICE_CLASS(klass);
+    SMMUInfo *info = (SMMUInfo *)data;
+
+    k->init = smmu_init;
+
+    sbc->info = info;
+
+    dc->desc = info->desc;
+    dc->reset = smmu_reset;
+    dc->vmsd = &vmstate_smmu;
+}
+
+static void smmu_instance_init(Object *obj)
+{
+    /* Nothing so far */
+}
+
+static const SMMUInfo smmu_info[] = {
+    {                           /* ARM Implementation */
+        .name = TYPE_SMMU_DEV,
+        .desc = "ARM SMMUv3",
+        .impl = SMMU_IMPL_ARM,
+    },
+    {                           /* Broadcom version */
+        .name = TYPE_SMMU_BRCM_DEV,
+        .desc = "ARM SMMUv3 (Broadcom)",
+        .impl = SMMU_IMPL_BRCM,
+    },
+};
+
+static const TypeInfo smmu_base_info = {
+    .name          = TYPE_SMMU_DEV_BASE,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SMMUSysState),
+    .instance_init = smmu_instance_init,
+    .class_size    = sizeof(SMMUBaseClass),
+    .abstract      = true,
+};
+
+static void smmu_register_types(void)
+{
+    int i;
+
+    type_register_static(&smmu_base_info);
+
+    for (i = 0; i < ARRAY_SIZE(smmu_info); i++) {
+        const SMMUInfo *info = &smmu_info[i];
+        TypeInfo type_info = {};
+
+        type_info.name = info->name;
+        type_info.parent = TYPE_SMMU_DEV_BASE;
+        type_info.class_data = (void *)info;
+        type_info.class_init = smmu_class_init;
+        type_info.instance_init = smmu_instance_init;
+
+        type_register(&type_info);
+    }
+}
+
+type_init(smmu_register_types)
diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
new file mode 100644
index 0000000..d071edc
--- /dev/null
+++ b/include/hw/arm/smmuv3.h
@@ -0,0 +1,39 @@
+/*
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2014-2015 Broadcom Corporation
+ *
+ * Author: Prem Mallappa <pmallapp@broadcom.com>
+ *
+ */
+#ifndef HW_ARM_SMMU_V3_H
+#define HW_ARM_SMMU_V3_H
+
+#define TYPE_SMMU_DEV_BASE "smmuv3-base"
+#define TYPE_SMMU_DEV      "smmuv3"
+#define TYPE_SMMU_BRCM_DEV "smmuv3-brcm"
+
+typedef enum {
+    SMMU_IMPL_ARM = 0x1,
+    SMMU_IMPL_BRCM,
+} SMMUImpl;
+
+typedef enum {
+    SMMU_IRQ_GERROR,
+    SMMU_IRQ_PRIQ,
+    SMMU_IRQ_EVTQ,
+    SMMU_IRQ_CMD_SYNC,
+} SMMUIrq;
+
+#endif
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH RFC 2/4] hw: arm: Added smmuv3 files for build
  2016-01-11 14:16 [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation pmallapp
  2016-01-11 14:16 ` [Qemu-devel] [PATCH RFC 1/4] arm: smmu: ARM SMMUv3 emulation pmallapp
@ 2016-01-11 14:16 ` pmallapp
  2016-01-11 14:16 ` [Qemu-devel] [PATCH RFC 3/4] hw: arm: Add SMMUv3 to virt platform pmallapp
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 16+ messages in thread
From: pmallapp @ 2016-01-11 14:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Prem Mallappa

From: Prem Mallappa <pmallapp@broadcom.com>

Added files to build system

Signed-off-by: Prem Mallappa <pmallapp@broadcom.com>
---
 default-configs/aarch64-softmmu.mak | 1 +
 hw/arm/Makefile.objs                | 1 +
 2 files changed, 2 insertions(+)

diff --git a/default-configs/aarch64-softmmu.mak b/default-configs/aarch64-softmmu.mak
index 96dd994..4c69280 100644
--- a/default-configs/aarch64-softmmu.mak
+++ b/default-configs/aarch64-softmmu.mak
@@ -4,3 +4,4 @@
 include arm-softmmu.mak
 
 CONFIG_XLNX_ZYNQMP=y
+CONFIG_ARM_SMMUV3=y
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 2195b60..0b453ff 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -15,3 +15,4 @@ obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
 obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o
 obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
 obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
+obj-$(CONFIG_ARM_SMMUV3) += smmuv3.o
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH RFC 3/4] hw: arm: Add SMMUv3 to virt platform
  2016-01-11 14:16 [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation pmallapp
  2016-01-11 14:16 ` [Qemu-devel] [PATCH RFC 1/4] arm: smmu: ARM SMMUv3 emulation pmallapp
  2016-01-11 14:16 ` [Qemu-devel] [PATCH RFC 2/4] hw: arm: Added smmuv3 files for build pmallapp
@ 2016-01-11 14:16 ` pmallapp
  2016-01-11 14:16 ` [Qemu-devel] [PATCH RFC 4/4] devicetree: Added new APIs to make use of more fdt functions pmallapp
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 16+ messages in thread
From: pmallapp @ 2016-01-11 14:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Prem Mallappa

From: Prem Mallappa <pmallapp@broadcom.com>

Signed-off-by: Prem Mallappa <pmallapp@broadcom.com>
---
 hw/arm/virt.c         | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/arm/virt.h |  2 ++
 2 files changed, 64 insertions(+)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index acc1fcb..5538175 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -53,6 +53,7 @@
 #include "hw/smbios/smbios.h"
 #include "qapi/visitor.h"
 #include "standard-headers/linux/input.h"
+#include "hw/arm/smmuv3.h"
 
 /* Number of external interrupt lines to configure the GIC with */
 #define NUM_IRQS 256
@@ -72,6 +73,7 @@ typedef struct VirtBoardInfo {
     uint32_t clock_phandle;
     uint32_t gic_phandle;
     uint32_t v2m_phandle;
+    uint32_t smmu_phandle;
 } VirtBoardInfo;
 
 typedef struct {
@@ -122,6 +124,7 @@ static const MemMapEntry a15memmap[] = {
     [VIRT_RTC] =                { 0x09010000, 0x00001000 },
     [VIRT_FW_CFG] =             { 0x09020000, 0x00000018 },
     [VIRT_GPIO] =               { 0x09030000, 0x00001000 },
+    [VIRT_SMMU] =               { 0x09040000, 0x00020000 }, /* 128K, needed */
     [VIRT_MMIO] =               { 0x0a000000, 0x00000200 },
     /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
     [VIRT_PLATFORM_BUS] =       { 0x0c000000, 0x02000000 },
@@ -140,9 +143,19 @@ static const int a15irqmap[] = {
     [VIRT_GPIO] = 7,
     [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
     [VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
+    [VIRT_SMMU] = 74,    /* ...to 74 + NUM_SMMU_IRQS - 1 */
     [VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
 };
 
+static const struct smmuirq {
+    const char *name;
+} smmuirqmap[NUM_SMMU_IRQS] = {
+    [SMMU_IRQ_EVTQ] = {"eventq"},
+    [SMMU_IRQ_PRIQ] = {"priq"},
+    [SMMU_IRQ_CMD_SYNC] = {"cmdq-sync"},
+    [SMMU_IRQ_GERROR] = {"gerror"},
+};
+
 static VirtBoardInfo machines[] = {
     {
         .cpu_model = "cortex-a15",
@@ -787,6 +800,50 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle,
                            0x7           /* PCI irq */);
 }
 
+static void alloc_smmu_phandle(VirtBoardInfo *vbi)
+{
+    if (!vbi->smmu_phandle)
+        vbi->smmu_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
+}
+
+static void create_smmu(VirtBoardInfo *vbi, qemu_irq *pic)
+{
+    int i;
+    char *smmu;
+    const char compat[] = "arm,smmu-v3";
+    int irq =  vbi->irqmap[VIRT_SMMU];
+    hwaddr base = vbi->memmap[VIRT_SMMU].base;
+    hwaddr size = vbi->memmap[VIRT_SMMU].size;
+    int type = GIC_FDT_IRQ_TYPE_SPI;
+
+    sysbus_create_varargs("smmuv3", base,
+                          pic[irq],
+                          pic[irq + 1],
+                          pic[irq + 2],
+                          pic[irq + 3],
+                          NULL);
+
+    smmu = g_strdup_printf("/smmuv3@%" PRIx64, base);
+    qemu_fdt_add_subnode(vbi->fdt, smmu);
+    qemu_fdt_setprop(vbi->fdt, smmu, "compatible", compat, sizeof(compat));
+    qemu_fdt_setprop_sized_cells(vbi->fdt, smmu, "reg", 2, base, 2, size);
+
+    for (i = 0; i < NUM_SMMU_IRQS; i++) {
+        qemu_fdt_appendprop_cells(vbi->fdt, smmu, "interrupts",
+                                  type, irq + i,
+                                  GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+        qemu_fdt_appendprop_string(vbi->fdt, smmu, "interrupt-names",
+                                   smmuirqmap[i].name);
+    }
+
+    qemu_fdt_setprop_cell(vbi->fdt, smmu, "clocks", vbi->clock_phandle);
+    qemu_fdt_setprop_cell(vbi->fdt, smmu, "#iommu-cells", 0);
+    qemu_fdt_setprop_string(vbi->fdt, smmu, "clock-names", "apb_pclk");
+
+    qemu_fdt_setprop_cell(vbi->fdt, smmu, "phandle", vbi->smmu_phandle);
+    g_free(smmu);
+}
+
 static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
                         bool use_highmem)
 {
@@ -883,6 +940,7 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
     }
 
     qemu_fdt_setprop_cell(vbi->fdt, nodename, "#interrupt-cells", 1);
+    qemu_fdt_setprop_cells(vbi->fdt, nodename, "iommus", vbi->smmu_phandle);
     create_pcie_irq_map(vbi, vbi->gic_phandle, irq, nodename);
 
     g_free(nodename);
@@ -1097,8 +1155,12 @@ static void machvirt_init(MachineState *machine)
 
     create_rtc(vbi, pic);
 
+    alloc_smmu_phandle(vbi);
+
     create_pcie(vbi, pic, vms->highmem);
 
+    create_smmu(vbi, pic);
+
     create_gpio(vbi, pic);
 
     /* Create mmio transports, so the user can create virtio backends
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 925faa7..76349ba 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -34,6 +34,7 @@
 
 #define NUM_GICV2M_SPIS       64
 #define NUM_VIRTIO_TRANSPORTS 32
+#define NUM_SMMU_IRQS          4
 
 #define ARCH_TIMER_VIRT_IRQ   11
 #define ARCH_TIMER_S_EL1_IRQ  13
@@ -49,6 +50,7 @@ enum {
     VIRT_GIC_V2M,
     VIRT_GIC_ITS,
     VIRT_GIC_REDIST,
+    VIRT_SMMU,
     VIRT_UART,
     VIRT_MMIO,
     VIRT_RTC,
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH RFC 4/4] devicetree: Added new APIs to make use of more fdt functions
  2016-01-11 14:16 [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation pmallapp
                   ` (2 preceding siblings ...)
  2016-01-11 14:16 ` [Qemu-devel] [PATCH RFC 3/4] hw: arm: Add SMMUv3 to virt platform pmallapp
@ 2016-01-11 14:16 ` pmallapp
  2016-01-11 14:19 ` [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation Peter Maydell
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 16+ messages in thread
From: pmallapp @ 2016-01-11 14:16 UTC (permalink / raw)
  To: qemu-devel; +Cc: Prem Mallappa

From: Prem Mallappa <pmallapp@broadcom.com>

SMMUv3 needs device tree entry like below

       interrupt-names = "gerror", "priq", "eventq", "cmdq-sync";

This patch introduces helper function to add entries like above

Signed-off-by: Prem Mallappa <pmallapp@broadcom.com>
---
 device_tree.c                | 35 +++++++++++++++++++++++++++++++++++
 include/sysemu/device_tree.h | 18 ++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/device_tree.c b/device_tree.c
index a9f5f8e..7690ff4 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -146,6 +146,24 @@ int qemu_fdt_setprop(void *fdt, const char *node_path,
     return r;
 }
 
+int qemu_fdt_appendprop(void *fdt, const char *node_path,
+                     const char *property, const void *val, int size)
+{
+    int r;
+
+    r = fdt_appendprop(fdt, findnode_nofail(fdt, node_path), property,
+                       val, size);
+    if (r < 0) {
+        error_report("%s: Couldn't set %s/%s: %s", __func__, node_path,
+                     property, fdt_strerror(r));
+        exit(1);
+    }
+
+    return r;
+}
+
+
+
 int qemu_fdt_setprop_cell(void *fdt, const char *node_path,
                           const char *property, uint32_t val)
 {
@@ -168,6 +186,23 @@ int qemu_fdt_setprop_u64(void *fdt, const char *node_path,
     return qemu_fdt_setprop(fdt, node_path, property, &val, sizeof(val));
 }
 
+int qemu_fdt_appendprop_string(void *fdt, const char *node_path,
+                            const char *property, const char *string)
+{
+    int r;
+
+    r = fdt_appendprop_string(fdt, findnode_nofail(fdt, node_path),
+                              property, string);
+    if (r < 0) {
+        error_report("%s: Couldn't set %s/%s = %s: %s", __func__,
+                     node_path, property, string, fdt_strerror(r));
+        exit(1);
+    }
+
+    return r;
+}
+
+
 int qemu_fdt_setprop_string(void *fdt, const char *node_path,
                             const char *property, const char *string)
 {
diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h
index 359e143..d5d32b4 100644
--- a/include/sysemu/device_tree.h
+++ b/include/sysemu/device_tree.h
@@ -19,12 +19,16 @@ void *load_device_tree(const char *filename_path, int *sizep);
 
 int qemu_fdt_setprop(void *fdt, const char *node_path,
                      const char *property, const void *val, int size);
+int qemu_fdt_appendprop(void *fdt, const char *node_path,
+                     const char *property, const void *val, int size);
 int qemu_fdt_setprop_cell(void *fdt, const char *node_path,
                           const char *property, uint32_t val);
 int qemu_fdt_setprop_u64(void *fdt, const char *node_path,
                          const char *property, uint64_t val);
 int qemu_fdt_setprop_string(void *fdt, const char *node_path,
                             const char *property, const char *string);
+int qemu_fdt_appendprop_string(void *fdt, const char *node_path,
+                               const char *property, const char *string);
 int qemu_fdt_setprop_phandle(void *fdt, const char *node_path,
                              const char *property,
                              const char *target_node_path);
@@ -49,6 +53,20 @@ int qemu_fdt_add_subnode(void *fdt, const char *name);
                          sizeof(qdt_tmp));                                    \
     } while (0)
 
+
+#define qemu_fdt_appendprop_cells(fdt, node_path, property, ...)              \
+    do {                                                                      \
+        uint32_t qdt_tmp[] = { __VA_ARGS__ };                                 \
+        int i;                                                                \
+                                                                              \
+        for (i = 0; i < ARRAY_SIZE(qdt_tmp); i++) {                           \
+            qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]);                             \
+        }                                                                     \
+        qemu_fdt_appendprop(fdt, node_path, property, qdt_tmp,                \
+                         sizeof(qdt_tmp));                                    \
+    } while (0)
+
+
 void qemu_fdt_dumpdtb(void *fdt, int size);
 
 /**
-- 
2.6.4

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation
  2016-01-11 14:16 [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation pmallapp
                   ` (3 preceding siblings ...)
  2016-01-11 14:16 ` [Qemu-devel] [PATCH RFC 4/4] devicetree: Added new APIs to make use of more fdt functions pmallapp
@ 2016-01-11 14:19 ` Peter Maydell
  2016-01-11 15:32   ` Prem (Premachandra) Mallappa
  2016-01-15 17:28 ` Peter Maydell
  2016-02-16 10:50 ` Peter Maydell
  6 siblings, 1 reply; 16+ messages in thread
From: Peter Maydell @ 2016-01-11 14:19 UTC (permalink / raw)
  To: pmallapp; +Cc: QEMU Developers

On 11 January 2016 at 14:16,  <pmallapp@broadcom.com> wrote:
> From: Prem Mallappa <pmallapp@broadcom.com>
>
> Implementation Notes:
>
>         - SMMUv3 model, as per ARM SMMUv3 11.0 spec

You seem to have sent three copies of this in the last few
hours. Is there any difference between them?

thanks
-- PMM

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation
  2016-01-11 14:19 ` [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation Peter Maydell
@ 2016-01-11 15:32   ` Prem (Premachandra) Mallappa
  0 siblings, 0 replies; 16+ messages in thread
From: Prem (Premachandra) Mallappa @ 2016-01-11 15:32 UTC (permalink / raw)
  To: Peter Maydell; +Cc: QEMU Developers


Hi,
 
> You seem to have sent three copies of this in the last few hours. Is there any
> difference between them?


Nope, my apologies for spamming your inbox,
Previous ones failed to post to _qemu-devel_, due to my office SMTP adding some incompatible bits.

Cheers,
/Prem

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation
  2016-01-11 14:16 [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation pmallapp
                   ` (4 preceding siblings ...)
  2016-01-11 14:19 ` [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation Peter Maydell
@ 2016-01-15 17:28 ` Peter Maydell
  2016-01-15 21:17   ` Alistair Francis
  2016-02-16 10:50 ` Peter Maydell
  6 siblings, 1 reply; 16+ messages in thread
From: Peter Maydell @ 2016-01-15 17:28 UTC (permalink / raw)
  To: Edgar E. Iglesias, Alistair Francis
  Cc: Peter Crosthwaite, QEMU Developers, pmallapp

On 11 January 2016 at 14:16,  <pmallapp@broadcom.com> wrote:
> From: Prem Mallappa <pmallapp@broadcom.com>
>
> Implementation Notes:
>
>         - SMMUv3 model, as per ARM SMMUv3 11.0 spec
>         - Works with Linux Kernel 4.4 SMMUv3 Driver By Will Deacon.
>         - Stage1 only
>         - only LPAE Translation tables supported
>         - BE for translation tables is not supported.
>         - Save/Restore not supported "YET".
>         - Broadcom variant added, not much different at the moment
>
> Untested
>         - Stage2 only
>         - Stage1+Stage2 support
>
> Future planned work:
>         - MSI(x) support

So, Xilinx also has an SMMU model (out of tree). Edgar, Alistair,
would you care to have a look at this code and suggest whether one
or the other is a better base to start from? (If there's not much
difference then I'm inclined to start with the one that got posted
to the list first :-))

thanks
-- PMM

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation
  2016-01-15 17:28 ` Peter Maydell
@ 2016-01-15 21:17   ` Alistair Francis
  2016-01-18  6:11     ` Prem (Premachandra) Mallappa
  0 siblings, 1 reply; 16+ messages in thread
From: Alistair Francis @ 2016-01-15 21:17 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Edgar E. Iglesias, Peter Crosthwaite, QEMU Developers, pmallapp,
	Alistair Francis

On Fri, Jan 15, 2016 at 9:28 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 11 January 2016 at 14:16,  <pmallapp@broadcom.com> wrote:
>> From: Prem Mallappa <pmallapp@broadcom.com>
>>
>> Implementation Notes:
>>
>>         - SMMUv3 model, as per ARM SMMUv3 11.0 spec
>>         - Works with Linux Kernel 4.4 SMMUv3 Driver By Will Deacon.
>>         - Stage1 only
>>         - only LPAE Translation tables supported
>>         - BE for translation tables is not supported.
>>         - Save/Restore not supported "YET".
>>         - Broadcom variant added, not much different at the moment
>>
>> Untested
>>         - Stage2 only
>>         - Stage1+Stage2 support
>>
>> Future planned work:
>>         - MSI(x) support
>
> So, Xilinx also has an SMMU model (out of tree). Edgar, Alistair,
> would you care to have a look at this code and suggest whether one
> or the other is a better base to start from? (If there's not much
> difference then I'm inclined to start with the one that got posted
> to the list first :-))

Edgar has done all of the SMMU work for Xilinx, he knows it the best.
I'll let him comment on it.

For anyone interested you can see our implementation at:
https://github.com/Xilinx/qemu/blob/master/hw/misc/arm-smmu.c. It does
use the register API that we have been trying to upstream.

Thanks,

Alistair

>
> thanks
> -- PMM
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation
  2016-01-15 21:17   ` Alistair Francis
@ 2016-01-18  6:11     ` Prem (Premachandra) Mallappa
  2016-01-18 13:21       ` Edgar E. Iglesias
  0 siblings, 1 reply; 16+ messages in thread
From: Prem (Premachandra) Mallappa @ 2016-01-18  6:11 UTC (permalink / raw)
  To: Alistair Francis, Peter Maydell
  Cc: Edgar E. Iglesias, Peter Crosthwaite, QEMU Developers

> Edgar has done all of the SMMU work for Xilinx, he knows it the best.
> I'll let him comment on it.
> 
> For anyone interested you can see our implementation at:
> https://github.com/Xilinx/qemu/blob/master/hw/misc/arm-smmu.c. It does
> use the register API that we have been trying to upstream.
> 
Hi,
I took a quick look at the code, The Xilinx implements mmu-500 which is a SMMU- v2.
I am not very familiar with V2, however, the architecture and internal workings are different between v2 and v3. 
hence there are 2 different drivers in Linux for V2 and V3, and the code I posted is for SMMU-v3.

Cheers,
/Prem

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation
  2016-01-18  6:11     ` Prem (Premachandra) Mallappa
@ 2016-01-18 13:21       ` Edgar E. Iglesias
  2016-01-20  4:30         ` Prem (Premachandra) Mallappa
  0 siblings, 1 reply; 16+ messages in thread
From: Edgar E. Iglesias @ 2016-01-18 13:21 UTC (permalink / raw)
  To: Prem (Premachandra) Mallappa
  Cc: Peter Maydell, Peter Crosthwaite, QEMU Developers, Alistair Francis

On Mon, Jan 18, 2016 at 06:11:35AM +0000, Prem (Premachandra) Mallappa wrote:
> > Edgar has done all of the SMMU work for Xilinx, he knows it the best.
> > I'll let him comment on it.
> > 
> > For anyone interested you can see our implementation at:
> > https://github.com/Xilinx/qemu/blob/master/hw/misc/arm-smmu.c. It does
> > use the register API that we have been trying to upstream.
> > 
> Hi,
> I took a quick look at the code, The Xilinx implements mmu-500 which is a SMMU- v2.
> I am not very familiar with V2, however, the architecture and internal workings are different between v2 and v3. 
> hence there are 2 different drivers in Linux for V2 and V3, and the code I posted is for SMMU-v3.
>

Hi,

Yes, we did SMMUv2 but I think there is opportunity to reuse quite a
bit of code.

I don't mind basing the implementation from the broadcom code but
there are a few things that could be taken from our our code or at
least re-implemented.

I haven't looked at the SMMUv3 at all but I'm guessing the translation
tables are the same. We could share code between a v2 and a v3 SMMU
and possibly even some of it with the CPU models.
Our translation code has been tested with S1 only, S2 only and S1 + S2.
We've ran it with the Linux SMMU v2 driver, XEN SMMU v2 driver and
our internal testsuites. This code could be a candidate for merging with
your SMMU code as I noticed that the broadcom implementation is lacking
some of the modes.

Another thing I noticed is that it doesn't seem like you've modelled
the TBUs (these may be named differently in SMMUv3 terminology if they
even exist)? Anyway, we need these as the address-spaces on the ZynqMP
are not all the same for all TBUs.

Cheers,
Edgar

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation
  2016-01-18 13:21       ` Edgar E. Iglesias
@ 2016-01-20  4:30         ` Prem (Premachandra) Mallappa
  0 siblings, 0 replies; 16+ messages in thread
From: Prem (Premachandra) Mallappa @ 2016-01-20  4:30 UTC (permalink / raw)
  To: Edgar E. Iglesias
  Cc: Peter Maydell, Peter Crosthwaite, QEMU Developers, Alistair Francis

Hi Edgar,

> Yes, we did SMMUv2 but I think there is opportunity to reuse quite a bit of code.

I agree

> 
> I don't mind basing the implementation from the broadcom code but 
> there are a few things that could be taken from our our code or at 
> least re- implemented.

We can collaborate in refactoring common code.

> I haven't looked at the SMMUv3 at all but I'm guessing the translation 
> tables are the same. We could share code between a v2 and a v3 SMMU 
> and possibly even some of it with the CPU models.

Yes TT are same w.r.t CPU, my code re-uses the CPU code but just little differently

> Our translation code has been tested with S1 only, S2 only and S1 + S2.
> We've ran it with the Linux SMMU v2 driver, XEN SMMU v2 driver and our 
> internal testsuites. This code could be a candidate for merging with 
> your SMMU code as I noticed that the broadcom implementation is 
> lacking some of the modes.

Yes, I have so far only able to test S1 only, I'll contact you off-list for setting up a Xen based
S1+S2 testing. But I guess my hands are tied in this case with 
S1+FastModels not (yet) having SMMUv3
And Qemu 64-bit ARM doesn't yet have KVM support, I'll be using Qemu v7
 And it's a RFC version posted early to avoid duplicate effort and before digging too deep.

> Another thing I noticed is that it doesn't seem like you've modelled 
> the TBUs (these may be named differently in SMMUv3 terminology if they 
> even exist)? Anyway, we need these as the address-spaces on the ZynqMP 
> are not all the same for all TBUs.

No TLB cache so far, I have plans of implementing (or reusing code from your implementation, whichever works).

I look forward to having more discussion on this topic.

Cheers,
/Prem

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation
  2016-01-11 14:16 [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation pmallapp
                   ` (5 preceding siblings ...)
  2016-01-15 17:28 ` Peter Maydell
@ 2016-02-16 10:50 ` Peter Maydell
  2016-02-17  4:39   ` Prem Mallappa
  6 siblings, 1 reply; 16+ messages in thread
From: Peter Maydell @ 2016-02-16 10:50 UTC (permalink / raw)
  To: pmallapp
  Cc: Edgar E. Iglesias, Peter Crosthwaite, QEMU Developers, Alistair Francis

On 11 January 2016 at 14:16,  <pmallapp@broadcom.com> wrote:
> From: Prem Mallappa <pmallapp@broadcom.com>
>
> Implementation Notes:
>
>         - SMMUv3 model, as per ARM SMMUv3 11.0 spec

I haven't reviewed any of this yet, but 11.0 is not the current
revision of the SMMUv3 spec, so you should probably start by
updating your code to the current version. Otherwise code review
will be full of "this isn't what the spec says"...

thanks
-- PMM

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation
  2016-02-16 10:50 ` Peter Maydell
@ 2016-02-17  4:39   ` Prem Mallappa
  2016-04-04 11:08     ` Peter Maydell
  0 siblings, 1 reply; 16+ messages in thread
From: Prem Mallappa @ 2016-02-17  4:39 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Edgar E. Iglesias, Peter Crosthwaite, QEMU Developers,
	Prem Mallappa, Alistair Francis

[-- Attachment #1: Type: text/plain, Size: 989 bytes --]

Hi Peter,

I have access till
"PRD03-GENC-010952 Version 11.0" updated 18/04/15.

infocenter.arm.com has only SMMUv2 made public

Please let me know if there is a new version available
 - to public.
 - through channels, I have to work with my organizational contact to get
to the new one.

I am not expecting any fundamental operation changes. However, I'll take a
look if theres a new version.

Cheers,
/Prem


On Tue, Feb 16, 2016 at 4:20 PM, Peter Maydell <peter.maydell@linaro.org>
wrote:

> On 11 January 2016 at 14:16,  <pmallapp@broadcom.com> wrote:
> > From: Prem Mallappa <pmallapp@broadcom.com>
> >
> > Implementation Notes:
> >
> >         - SMMUv3 model, as per ARM SMMUv3 11.0 spec
>
> I haven't reviewed any of this yet, but 11.0 is not the current
> revision of the SMMUv3 spec, so you should probably start by
> updating your code to the current version. Otherwise code review
> will be full of "this isn't what the spec says"...
>
> thanks
> -- PMM
>



-- 
Cheers,
/Prem

[-- Attachment #2: Type: text/html, Size: 1863 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation
  2016-02-17  4:39   ` Prem Mallappa
@ 2016-04-04 11:08     ` Peter Maydell
  2016-04-04 13:14       ` Prem Mallappa
  0 siblings, 1 reply; 16+ messages in thread
From: Peter Maydell @ 2016-04-04 11:08 UTC (permalink / raw)
  To: Prem Mallappa
  Cc: Edgar E. Iglesias, Peter Crosthwaite, QEMU Developers,
	Prem Mallappa, Alistair Francis

On 17 February 2016 at 04:39, Prem Mallappa <prem.mallappa@broadcom.com> wrote:
> Hi Peter,
>
> I have access till
> "PRD03-GENC-010952 Version 11.0" updated 18/04/15.
>
> infocenter.arm.com has only SMMUv2 made public
>
> Please let me know if there is a new version available
>  - to public.
>  - through channels, I have to work with my organizational contact to get to
> the new one.
>
> I am not expecting any fundamental operation changes. However, I'll take a
> look if theres a new version.

Hi; just wanted to ask if you'd got the updated SMMUv3 spec yet,
and to check that there that we're in agreement that the next step
here is that you would do a respin of your patches updated to the
final specification. (That is, you're not blocked waiting for
anything more from me or Edgar. Occasionally in these patch review
threads there's a miscommunication and both sides think they're
waiting for the other, so I just wanted to check that.)

thanks
-- PMM

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation
  2016-04-04 11:08     ` Peter Maydell
@ 2016-04-04 13:14       ` Prem Mallappa
  0 siblings, 0 replies; 16+ messages in thread
From: Prem Mallappa @ 2016-04-04 13:14 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Edgar E. Iglesias, Peter Crosthwaite, QEMU Developers,
	Prem Mallappa, Alistair Francis

[-- Attachment #1: Type: text/plain, Size: 1719 bytes --]

Hi Peter,
Thanks for following up.

I got access to 16.0 version, I dont particularly see any difference in
basic functionality.

I had been in touch with Edger, We agreed upon making usable code b/w
smmuv2 and smmuv3 for now. Currently the code is in working state.

I also heard, there has been talks to merge code with CPU's page walk code.
but till then we can make use of the current setup.

I'll be sending out v2 soon, just trying to write some Qtests to test
2-stage page walks.

Edger, if you already have written Qtest code please do share, it would be
of tremendous help now.


Thanks

On Mon, Apr 4, 2016 at 4:38 PM, Peter Maydell <peter.maydell@linaro.org>
wrote:

> On 17 February 2016 at 04:39, Prem Mallappa <prem.mallappa@broadcom.com>
> wrote:
> > Hi Peter,
> >
> > I have access till
> > "PRD03-GENC-010952 Version 11.0" updated 18/04/15.
> >
> > infocenter.arm.com has only SMMUv2 made public
> >
> > Please let me know if there is a new version available
> >  - to public.
> >  - through channels, I have to work with my organizational contact to
> get to
> > the new one.
> >
> > I am not expecting any fundamental operation changes. However, I'll take
> a
> > look if theres a new version.
>
> Hi; just wanted to ask if you'd got the updated SMMUv3 spec yet,
> and to check that there that we're in agreement that the next step
> here is that you would do a respin of your patches updated to the
> final specification. (That is, you're not blocked waiting for
> anything more from me or Edgar. Occasionally in these patch review
> threads there's a miscommunication and both sides think they're
> waiting for the other, so I just wanted to check that.)
>
> thanks
> -- PMM
>



-- 
Cheers,
/Prem

[-- Attachment #2: Type: text/html, Size: 2626 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2016-04-04 13:14 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-11 14:16 [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation pmallapp
2016-01-11 14:16 ` [Qemu-devel] [PATCH RFC 1/4] arm: smmu: ARM SMMUv3 emulation pmallapp
2016-01-11 14:16 ` [Qemu-devel] [PATCH RFC 2/4] hw: arm: Added smmuv3 files for build pmallapp
2016-01-11 14:16 ` [Qemu-devel] [PATCH RFC 3/4] hw: arm: Add SMMUv3 to virt platform pmallapp
2016-01-11 14:16 ` [Qemu-devel] [PATCH RFC 4/4] devicetree: Added new APIs to make use of more fdt functions pmallapp
2016-01-11 14:19 ` [Qemu-devel] [PATCH RFC 0/4] ARM SMMUv3 Emulation Peter Maydell
2016-01-11 15:32   ` Prem (Premachandra) Mallappa
2016-01-15 17:28 ` Peter Maydell
2016-01-15 21:17   ` Alistair Francis
2016-01-18  6:11     ` Prem (Premachandra) Mallappa
2016-01-18 13:21       ` Edgar E. Iglesias
2016-01-20  4:30         ` Prem (Premachandra) Mallappa
2016-02-16 10:50 ` Peter Maydell
2016-02-17  4:39   ` Prem Mallappa
2016-04-04 11:08     ` Peter Maydell
2016-04-04 13:14       ` Prem Mallappa

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.