xref: /qemu/hw/riscv/riscv-iommu.h (revision 513823e7521a09ed7ad1e32e6454bac3b2cbf52d)
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 #include "hw/riscv/riscv-iommu-bits.h"
25 
26 typedef enum riscv_iommu_igs_modes riscv_iommu_igs_mode;
27 
28 struct RISCVIOMMUState {
29     /*< private >*/
30     DeviceState parent_obj;
31 
32     /*< public >*/
33     uint32_t version;     /* Reported interface version number */
34     uint32_t pid_bits;    /* process identifier width */
35     uint32_t bus;         /* PCI bus mapping for non-root endpoints */
36 
37     uint64_t cap;         /* IOMMU supported capabilities */
38     uint64_t fctl;        /* IOMMU enabled features */
39     uint64_t icvec_avail_vectors;  /* Available interrupt vectors in ICVEC */
40 
41     bool enable_off;      /* Enable out-of-reset OFF mode (DMA disabled) */
42     bool enable_msi;      /* Enable MSI remapping */
43     bool enable_ats;      /* Enable ATS support */
44     bool enable_s_stage;  /* Enable S/VS-Stage translation */
45     bool enable_g_stage;  /* Enable G-Stage translation */
46 
47     /* IOMMU Internal State */
48     uint64_t ddtp;        /* Validated Device Directory Tree Root Pointer */
49 
50     dma_addr_t cq_addr;   /* Command queue base physical address */
51     dma_addr_t fq_addr;   /* Fault/event queue base physical address */
52     dma_addr_t pq_addr;   /* Page request queue base physical address */
53 
54     uint32_t cq_mask;     /* Command queue index bit mask */
55     uint32_t fq_mask;     /* Fault/event queue index bit mask */
56     uint32_t pq_mask;     /* Page request queue index bit mask */
57 
58     /* interrupt notifier */
59     void (*notify)(RISCVIOMMUState *iommu, unsigned vector);
60 
61     /* IOMMU State Machine */
62     QemuThread core_proc; /* Background processing thread */
63     QemuCond core_cond;   /* Background processing wake up signal */
64     unsigned core_exec;   /* Processing thread execution actions */
65 
66     /* IOMMU target address space */
67     AddressSpace *target_as;
68     MemoryRegion *target_mr;
69 
70     /* MSI / MRIF access trap */
71     AddressSpace trap_as;
72     MemoryRegion trap_mr;
73 
74     GHashTable *ctx_cache;          /* Device translation Context Cache */
75 
76     GHashTable *iot_cache;          /* IO Translated Address Cache */
77     unsigned iot_limit;             /* IO Translation Cache size limit */
78 
79     /* MMIO Hardware Interface */
80     MemoryRegion regs_mr;
81     uint8_t *regs_rw;  /* register state (user write) */
82     uint8_t *regs_wc;  /* write-1-to-clear mask */
83     uint8_t *regs_ro;  /* read-only mask */
84 
85     QLIST_ENTRY(RISCVIOMMUState) iommus;
86     QLIST_HEAD(, RISCVIOMMUSpace) spaces;
87 };
88 
89 void riscv_iommu_pci_setup_iommu(RISCVIOMMUState *iommu, PCIBus *bus,
90          Error **errp);
91 void riscv_iommu_set_cap_igs(RISCVIOMMUState *s, riscv_iommu_igs_mode mode);
92 void riscv_iommu_reset(RISCVIOMMUState *s);
93 
94 /* private helpers */
95 
96 /* Register helper functions */
97 static inline uint32_t riscv_iommu_reg_mod32(RISCVIOMMUState *s,
98     unsigned idx, uint32_t set, uint32_t clr)
99 {
100     uint32_t val = ldl_le_p(s->regs_rw + idx);
101     stl_le_p(s->regs_rw + idx, (val & ~clr) | set);
102     return val;
103 }
104 
105 static inline void riscv_iommu_reg_set32(RISCVIOMMUState *s, unsigned idx,
106                                          uint32_t set)
107 {
108     stl_le_p(s->regs_rw + idx, set);
109 }
110 
111 static inline uint32_t riscv_iommu_reg_get32(RISCVIOMMUState *s, unsigned idx)
112 {
113     return ldl_le_p(s->regs_rw + idx);
114 }
115 
116 static inline uint64_t riscv_iommu_reg_mod64(RISCVIOMMUState *s, unsigned idx,
117                                              uint64_t set, uint64_t clr)
118 {
119     uint64_t val = ldq_le_p(s->regs_rw + idx);
120     stq_le_p(s->regs_rw + idx, (val & ~clr) | set);
121     return val;
122 }
123 
124 static inline void riscv_iommu_reg_set64(RISCVIOMMUState *s, unsigned idx,
125                                          uint64_t set)
126 {
127     stq_le_p(s->regs_rw + idx, set);
128 }
129 
130 static inline uint64_t riscv_iommu_reg_get64(RISCVIOMMUState *s,
131     unsigned idx)
132 {
133     return ldq_le_p(s->regs_rw + idx);
134 }
135 #endif
136