1 /*
2 * QEMU emulation of an RISC-V IOMMU
3 *
4 * Copyright (C) 2022-2023 Rivos Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2 or later, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #ifndef HW_RISCV_IOMMU_STATE_H
20 #define HW_RISCV_IOMMU_STATE_H
21
22 #include "qom/object.h"
23 #include "hw/riscv/iommu.h"
24
25 struct RISCVIOMMUState {
26 /*< private >*/
27 DeviceState parent_obj;
28
29 /*< public >*/
30 uint32_t version; /* Reported interface version number */
31 uint32_t pid_bits; /* process identifier width */
32 uint32_t bus; /* PCI bus mapping for non-root endpoints */
33
34 uint64_t cap; /* IOMMU supported capabilities */
35 uint64_t fctl; /* IOMMU enabled features */
36 uint64_t icvec_avail_vectors; /* Available interrupt vectors in ICVEC */
37
38 bool enable_off; /* Enable out-of-reset OFF mode (DMA disabled) */
39 bool enable_msi; /* Enable MSI remapping */
40 bool enable_ats; /* Enable ATS support */
41 bool enable_s_stage; /* Enable S/VS-Stage translation */
42 bool enable_g_stage; /* Enable G-Stage translation */
43
44 /* IOMMU Internal State */
45 uint64_t ddtp; /* Validated Device Directory Tree Root Pointer */
46
47 dma_addr_t cq_addr; /* Command queue base physical address */
48 dma_addr_t fq_addr; /* Fault/event queue base physical address */
49 dma_addr_t pq_addr; /* Page request queue base physical address */
50
51 uint32_t cq_mask; /* Command queue index bit mask */
52 uint32_t fq_mask; /* Fault/event queue index bit mask */
53 uint32_t pq_mask; /* Page request queue index bit mask */
54
55 /* interrupt notifier */
56 void (*notify)(RISCVIOMMUState *iommu, unsigned vector);
57
58 /* IOMMU State Machine */
59 QemuThread core_proc; /* Background processing thread */
60 QemuCond core_cond; /* Background processing wake up signal */
61 unsigned core_exec; /* Processing thread execution actions */
62
63 /* IOMMU target address space */
64 AddressSpace *target_as;
65 MemoryRegion *target_mr;
66
67 /* MSI / MRIF access trap */
68 AddressSpace trap_as;
69 MemoryRegion trap_mr;
70
71 GHashTable *ctx_cache; /* Device translation Context Cache */
72
73 GHashTable *iot_cache; /* IO Translated Address Cache */
74 unsigned iot_limit; /* IO Translation Cache size limit */
75
76 /* MMIO Hardware Interface */
77 MemoryRegion regs_mr;
78 uint8_t *regs_rw; /* register state (user write) */
79 uint8_t *regs_wc; /* write-1-to-clear mask */
80 uint8_t *regs_ro; /* read-only mask */
81
82 QLIST_ENTRY(RISCVIOMMUState) iommus;
83 QLIST_HEAD(, RISCVIOMMUSpace) spaces;
84 };
85
86 void riscv_iommu_pci_setup_iommu(RISCVIOMMUState *iommu, PCIBus *bus,
87 Error **errp);
88
89 /* private helpers */
90
91 /* Register helper functions */
riscv_iommu_reg_mod32(RISCVIOMMUState * s,unsigned idx,uint32_t set,uint32_t clr)92 static inline uint32_t riscv_iommu_reg_mod32(RISCVIOMMUState *s,
93 unsigned idx, uint32_t set, uint32_t clr)
94 {
95 uint32_t val = ldl_le_p(s->regs_rw + idx);
96 stl_le_p(s->regs_rw + idx, (val & ~clr) | set);
97 return val;
98 }
99
riscv_iommu_reg_set32(RISCVIOMMUState * s,unsigned idx,uint32_t set)100 static inline void riscv_iommu_reg_set32(RISCVIOMMUState *s, unsigned idx,
101 uint32_t set)
102 {
103 stl_le_p(s->regs_rw + idx, set);
104 }
105
riscv_iommu_reg_get32(RISCVIOMMUState * s,unsigned idx)106 static inline uint32_t riscv_iommu_reg_get32(RISCVIOMMUState *s, unsigned idx)
107 {
108 return ldl_le_p(s->regs_rw + idx);
109 }
110
riscv_iommu_reg_mod64(RISCVIOMMUState * s,unsigned idx,uint64_t set,uint64_t clr)111 static inline uint64_t riscv_iommu_reg_mod64(RISCVIOMMUState *s, unsigned idx,
112 uint64_t set, uint64_t clr)
113 {
114 uint64_t val = ldq_le_p(s->regs_rw + idx);
115 stq_le_p(s->regs_rw + idx, (val & ~clr) | set);
116 return val;
117 }
118
riscv_iommu_reg_set64(RISCVIOMMUState * s,unsigned idx,uint64_t set)119 static inline void riscv_iommu_reg_set64(RISCVIOMMUState *s, unsigned idx,
120 uint64_t set)
121 {
122 stq_le_p(s->regs_rw + idx, set);
123 }
124
riscv_iommu_reg_get64(RISCVIOMMUState * s,unsigned idx)125 static inline uint64_t riscv_iommu_reg_get64(RISCVIOMMUState *s,
126 unsigned idx)
127 {
128 return ldq_le_p(s->regs_rw + idx);
129 }
130 #endif
131