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