1 /*
2 * Copyright (C) 2018-2022 Intel Corporation.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #ifndef PTDEV_H
8 #define PTDEV_H
9 #include <list.h>
10 #include <asm/lib/spinlock.h>
11 #include <timer.h>
12 #include <vacpi.h>
13
14
15 enum intx_ctlr {
16 INTX_CTLR_IOAPIC = 0U,
17 INTX_CTLR_PIC
18 };
19
20 #define PTDEV_INTR_MSI (1U << 0U)
21 #define PTDEV_INTR_INTX (1U << 1U)
22
23 #define GPU_OPREGION_SIZE 0x5000U
24 #define GPU_OPREGION_GPA (VIRT_ACPI_DATA_ADDR - GPU_OPREGION_SIZE)
25 #define PCIR_ASLS_CTL 0xfcU /* register offset in PCIe configuration space for Opregion base address */
26 #define PCIM_ASLS_OPREGION_MASK 0xfffff000U /* opregion need 4KB aligned */
27
28 #define INVALID_PTDEV_ENTRY_ID 0xffffU
29
30 #define DEFINE_MSI_SID(name, a, b) \
31 union source_id (name) = {.msi_id = {.bdf = (a), .entry_nr = (b)} }
32
33 #define DEFINE_INTX_SID(name, a, b) \
34 union source_id (name) = {.intx_id = {.gsi = (a), .ctlr = (b)} }
35
36 union irte_index {
37 uint16_t index;
38 struct {
39 uint16_t index_low:15;
40 uint16_t index_high:1;
41 } bits __packed;
42 };
43
44
45 union source_id {
46 uint64_t value;
47 struct {
48 uint16_t bdf;
49 uint16_t entry_nr;
50 uint32_t reserved;
51 } msi_id;
52 /*
53 * ctlr indicates if the source of interrupt is IO-APIC or PIC
54 * pin indicates the pin number of interrupt controller determined by ctlr
55 */
56 struct {
57 enum intx_ctlr ctlr;
58 uint32_t gsi;
59 } intx_id;
60 };
61
62 /*
63 * Macros for bits in union msi_addr_reg
64 */
65
66 #define MSI_ADDR_BASE 0xfeeUL /* Base address for MSI messages */
67 #define MSI_ADDR_RH 0x1U /* Redirection Hint */
68 #define MSI_ADDR_DESTMODE_LOGICAL 0x1U /* Destination Mode: Logical*/
69 #define MSI_ADDR_DESTMODE_PHYS 0x0U /* Destination Mode: Physical*/
70
71 union msi_addr_reg {
72 uint64_t full;
73 struct {
74 uint32_t rsvd_1:2;
75 uint32_t dest_mode:1;
76 uint32_t rh:1;
77 uint32_t rsvd_2:8;
78 uint32_t dest_field:8;
79 uint32_t addr_base:12;
80 uint32_t hi_32;
81 } bits __packed;
82 struct {
83 uint32_t rsvd_1:2;
84 uint32_t intr_index_high:1;
85 uint32_t shv:1;
86 uint32_t intr_format:1;
87 uint32_t intr_index_low:15;
88 uint32_t constant:12;
89 uint32_t hi_32;
90 } ir_bits __packed;
91
92 };
93
94 /*
95 * Macros for bits in union msi_data_reg
96 */
97
98 #define MSI_DATA_DELMODE_FIXED 0x0U /* Delivery Mode: Fixed */
99 #define MSI_DATA_DELMODE_LOPRI 0x1U /* Delivery Mode: Low Priority */
100 #define MSI_DATA_TRGRMODE_EDGE 0x0U /* Trigger Mode: Edge */
101 #define MSI_DATA_TRGRMODE_LEVEL 0x1U /* Trigger Mode: Level */
102
103 union msi_data_reg {
104 uint32_t full;
105 struct {
106 uint32_t vector:8;
107 uint32_t delivery_mode:3;
108 uint32_t rsvd_1:3;
109 uint32_t level:1;
110 uint32_t trigger_mode:1;
111 uint32_t rsvd_2:16;
112 } bits __packed;
113 };
114
115 struct msi_info {
116 union msi_addr_reg addr;
117 union msi_data_reg data;
118 };
119
120 struct ptirq_remapping_info;
121 typedef void (*ptirq_arch_release_fn_t)(const struct ptirq_remapping_info *entry);
122
123 /* entry per each allocated irq/vector
124 * it represents a pass-thru device's remapping data entry which collecting
125 * information related with its vm and msi/intx mapping & interaction nodes
126 * with interrupt handler and softirq.
127 */
128 struct ptirq_remapping_info {
129 struct hlist_node phys_link;
130 struct hlist_node virt_link;
131 uint16_t ptdev_entry_id;
132 uint32_t intr_type;
133 union source_id phys_sid;
134 union source_id virt_sid;
135 struct acrn_vm *vm;
136 bool active; /* true=active, false=inactive*/
137 uint32_t allocated_pirq;
138 uint32_t polarity; /* 0=active high, 1=active low*/
139 struct list_head softirq_node;
140 struct msi_info vmsi;
141 struct msi_info pmsi;
142 uint16_t irte_idx;
143
144 uint64_t intr_count;
145 struct hv_timer intr_delay_timer; /* used for delay intr injection */
146 ptirq_arch_release_fn_t release_cb;
147 };
148
is_entry_active(const struct ptirq_remapping_info * entry)149 static inline bool is_entry_active(const struct ptirq_remapping_info *entry)
150 {
151 return entry->active;
152 }
153
154 extern struct ptirq_remapping_info ptirq_entries[CONFIG_MAX_PT_IRQ_ENTRIES];
155 extern spinlock_t ptdev_lock;
156
157 /**
158 * @file ptdev.h
159 *
160 * @brief public APIs for ptdev
161 */
162
163 /**
164 * @brief ptdev
165 *
166 * @addtogroup acrn_passthrough
167 * @{
168 */
169
170
171 /*
172 * @brief Find a ptdev entry by sid
173 *
174 * param[in] intr_type interrupt type of the ptirq entry
175 * param[in] sid source id of the ptirq entry
176 * param[in] vm vm pointer of the ptirq entry if find the ptdev entry by virtual sid
177 *
178 * @retval NULL when no ptirq entry match the sid
179 * @retval ptirq entry when there is available ptirq entry match the sid
180 *
181 * @pre: vm must be NULL when lookup by physical sid, otherwise,
182 * vm must not be NULL when lookup by virtual sid.
183 */
184 struct ptirq_remapping_info *find_ptirq_entry(uint32_t intr_type,
185 const union source_id *sid, const struct acrn_vm *vm);
186
187 /**
188 * @brief Handler of softirq for passthrough device.
189 *
190 * When hypervisor receive a physical interrupt from passthrough device, it
191 * will enqueue a ptirq entry and raise softirq SOFTIRQ_PTDEV. This function
192 * is the handler of the softirq, it handles the interrupt and injects the
193 * virtual into VM.
194 * The handler is registered by calling @ref ptdev_init during hypervisor
195 * initialization.
196 *
197 * @param[in] pcpu_id physical cpu id of the soft irq
198 *
199 */
200 void ptirq_softirq(uint16_t pcpu_id);
201 /**
202 * @brief Passthrough device global data structure initialization.
203 *
204 * During the hypervisor cpu initialization stage, this function:
205 * - init global spinlock for ptdev (on BSP)
206 * - register SOFTIRQ_PTDEV handler (on BSP)
207 * - init the softirq entry list for each CPU
208 *
209 */
210 void ptdev_init(void);
211 /**
212 * @brief Deactivate and release all ptirq entries for a VM.
213 *
214 * This function deactivates and releases all ptirq entries for a VM. The function
215 * should only be called after the VM is already down.
216 *
217 * @param[in] vm acrn_vm on which the ptirq entries will be released
218 *
219 * @pre VM is already down
220 *
221 */
222 void ptdev_release_all_entries(const struct acrn_vm *vm);
223
224 /**
225 * @brief Dequeue an entry from per cpu ptdev softirq queue.
226 *
227 * Dequeue an entry from the ptdev softirq queue on the specific physical cpu.
228 *
229 * @param[in] pcpu_id physical cpu id
230 *
231 * @retval NULL when the queue is empty
232 * @retval !NULL when there is available ptirq_remapping_info entry in the queue
233 *
234 */
235 struct ptirq_remapping_info *ptirq_dequeue_softirq(uint16_t pcpu_id);
236 /**
237 * @brief Allocate a ptirq_remapping_info entry.
238 *
239 * Allocate a ptirq_remapping_info entry for hypervisor to store the remapping information.
240 * The total number of the entries is statically defined as CONFIG_MAX_PT_IRQ_ENTRIES.
241 * Appropriate number should be configured on different platforms.
242 *
243 * @param[in] vm acrn_vm that the entry allocated for.
244 * @param[in] intr_type interrupt type: PTDEV_INTR_MSI or PTDEV_INTR_INTX
245 *
246 * @retval NULL when the number of entries allocated is CONFIG_MAX_PT_IRQ_ENTRIES
247 * @retval !NULL when the number of entries allocated is less than CONFIG_MAX_PT_IRQ_ENTRIES
248 *
249 */
250 struct ptirq_remapping_info *ptirq_alloc_entry(struct acrn_vm *vm, uint32_t intr_type);
251 /**
252 * @brief Release a ptirq_remapping_info entry.
253 *
254 * @param[in] entry the ptirq_remapping_info entry to release.
255 *
256 */
257 void ptirq_release_entry(struct ptirq_remapping_info *entry);
258 /**
259 * @brief Activate a irq for the associated passthrough device.
260 *
261 * After activating the ptirq entry, the physical interrupt irq of passthrough device will be handled
262 * by the handler ptirq_interrupt_handler.
263 *
264 * @param[in] entry the ptirq_remapping_info entry that will be associated with the physical irq.
265 * @param[in] phys_irq physical interrupt irq for the entry
266 *
267 * @retval success when return value >=0
268 * @retval failure when return value < 0
269 *
270 */
271 int32_t ptirq_activate_entry(struct ptirq_remapping_info *entry, uint32_t phys_irq);
272 /**
273 * @brief De-activate a irq for the associated passthrough device.
274 *
275 * @param[in] entry the ptirq_remapping_info entry that will be de-activated.
276 *
277 */
278 void ptirq_deactivate_entry(struct ptirq_remapping_info *entry);
279 /**
280 * @brief Get the interrupt information and store to the buffer provided.
281 *
282 * @param[in] target_vm the VM to get the interrupt information.
283 * @param[out] buffer where interrupt information is stored.
284 * @param[in] buffer_cnt the size of the buffer.
285 *
286 * @retval the actual size the buffer filled with the interrupt information
287 *
288 */
289 uint32_t ptirq_get_intr_data(const struct acrn_vm *target_vm, uint64_t *buffer, uint32_t buffer_cnt);
290
291 /**
292 * @}
293 */
294
295 #endif /* PTDEV_H */
296