]>
Commit | Line | Data |
---|---|---|
eaab4d60 AK |
1 | #ifndef XEN_PT_H |
2 | #define XEN_PT_H | |
3 | ||
0d09e41a | 4 | #include "hw/xen/xen_common.h" |
47b43a1f | 5 | #include "xen-host-pci-device.h" |
db1015e9 | 6 | #include "qom/object.h" |
eaab4d60 | 7 | |
acd0c941 AP |
8 | bool xen_igd_gfx_pt_enabled(void); |
9 | void xen_igd_gfx_pt_set(bool value, Error **errp); | |
10 | ||
9edc6313 | 11 | void xen_pt_log(const PCIDevice *d, const char *f, ...) G_GNUC_PRINTF(2, 3); |
eaab4d60 AK |
12 | |
13 | #define XEN_PT_ERR(d, _f, _a...) xen_pt_log(d, "%s: Error: "_f, __func__, ##_a) | |
14 | ||
15 | #ifdef XEN_PT_LOGGING_ENABLED | |
16 | # define XEN_PT_LOG(d, _f, _a...) xen_pt_log(d, "%s: " _f, __func__, ##_a) | |
17 | # define XEN_PT_WARN(d, _f, _a...) \ | |
18 | xen_pt_log(d, "%s: Warning: "_f, __func__, ##_a) | |
19 | #else | |
20 | # define XEN_PT_LOG(d, _f, _a...) | |
21 | # define XEN_PT_WARN(d, _f, _a...) | |
22 | #endif | |
23 | ||
24 | #ifdef XEN_PT_DEBUG_PCI_CONFIG_ACCESS | |
25 | # define XEN_PT_LOG_CONFIG(d, addr, val, len) \ | |
26 | xen_pt_log(d, "%s: address=0x%04x val=0x%08x len=%d\n", \ | |
27 | __func__, addr, val, len) | |
28 | #else | |
29 | # define XEN_PT_LOG_CONFIG(d, addr, val, len) | |
30 | #endif | |
31 | ||
32 | ||
33 | /* Helper */ | |
34 | #define XEN_PFN(x) ((x) >> XC_PAGE_SHIFT) | |
35 | ||
74526eb0 | 36 | typedef const struct XenPTRegInfo XenPTRegInfo; |
eaab4d60 AK |
37 | typedef struct XenPTReg XenPTReg; |
38 | ||
eaab4d60 | 39 | |
f9b9d292 | 40 | #define TYPE_XEN_PT_DEVICE "xen-pci-passthrough" |
8063396b | 41 | OBJECT_DECLARE_SIMPLE_TYPE(XenPCIPassthroughState, XEN_PT_DEVICE) |
f9b9d292 | 42 | |
5cec8aa3 TC |
43 | uint32_t igd_read_opregion(XenPCIPassthroughState *s); |
44 | void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val); | |
76acef2b BB |
45 | void xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s, |
46 | XenHostPCIDevice *dev); | |
5cec8aa3 | 47 | |
eaab4d60 AK |
48 | /* function type for config reg */ |
49 | typedef int (*xen_pt_conf_reg_init) | |
50 | (XenPCIPassthroughState *, XenPTRegInfo *, uint32_t real_offset, | |
51 | uint32_t *data); | |
52 | typedef int (*xen_pt_conf_dword_write) | |
53 | (XenPCIPassthroughState *, XenPTReg *cfg_entry, | |
54 | uint32_t *val, uint32_t dev_value, uint32_t valid_mask); | |
55 | typedef int (*xen_pt_conf_word_write) | |
56 | (XenPCIPassthroughState *, XenPTReg *cfg_entry, | |
57 | uint16_t *val, uint16_t dev_value, uint16_t valid_mask); | |
58 | typedef int (*xen_pt_conf_byte_write) | |
59 | (XenPCIPassthroughState *, XenPTReg *cfg_entry, | |
60 | uint8_t *val, uint8_t dev_value, uint8_t valid_mask); | |
61 | typedef int (*xen_pt_conf_dword_read) | |
62 | (XenPCIPassthroughState *, XenPTReg *cfg_entry, | |
63 | uint32_t *val, uint32_t valid_mask); | |
64 | typedef int (*xen_pt_conf_word_read) | |
65 | (XenPCIPassthroughState *, XenPTReg *cfg_entry, | |
66 | uint16_t *val, uint16_t valid_mask); | |
67 | typedef int (*xen_pt_conf_byte_read) | |
68 | (XenPCIPassthroughState *, XenPTReg *cfg_entry, | |
69 | uint8_t *val, uint8_t valid_mask); | |
70 | ||
71 | #define XEN_PT_BAR_ALLF 0xFFFFFFFF | |
72 | #define XEN_PT_BAR_UNMAPPED (-1) | |
73 | ||
5cec8aa3 | 74 | #define XEN_PCI_CAP_MAX 48 |
93d7ae8e | 75 | |
5cec8aa3 | 76 | #define XEN_PCI_INTEL_OPREGION 0xfc |
eaab4d60 AK |
77 | |
78 | typedef enum { | |
79 | XEN_PT_GRP_TYPE_HARDWIRED = 0, /* 0 Hardwired reg group */ | |
80 | XEN_PT_GRP_TYPE_EMU, /* emul reg group */ | |
81 | } XenPTRegisterGroupType; | |
82 | ||
83 | typedef enum { | |
84 | XEN_PT_BAR_FLAG_MEM = 0, /* Memory type BAR */ | |
85 | XEN_PT_BAR_FLAG_IO, /* I/O type BAR */ | |
86 | XEN_PT_BAR_FLAG_UPPER, /* upper 64bit BAR */ | |
87 | XEN_PT_BAR_FLAG_UNUSED, /* unused BAR */ | |
88 | } XenPTBarFlag; | |
89 | ||
90 | ||
91 | typedef struct XenPTRegion { | |
92 | /* BAR flag */ | |
93 | XenPTBarFlag bar_flag; | |
94 | /* Translation of the emulated address */ | |
95 | union { | |
96 | uint64_t maddr; | |
97 | uint64_t pio_base; | |
98 | uint64_t u; | |
99 | } access; | |
100 | } XenPTRegion; | |
101 | ||
102 | /* XenPTRegInfo declaration | |
103 | * - only for emulated register (either a part or whole bit). | |
104 | * - for passthrough register that need special behavior (like interacting with | |
105 | * other component), set emu_mask to all 0 and specify r/w func properly. | |
106 | * - do NOT use ALL F for init_val, otherwise the tbl will not be registered. | |
107 | */ | |
108 | ||
0546b8c2 | 109 | /* emulated register information */ |
eaab4d60 AK |
110 | struct XenPTRegInfo { |
111 | uint32_t offset; | |
112 | uint32_t size; | |
113 | uint32_t init_val; | |
0ad3393a JB |
114 | /* reg reserved field mask (ON:reserved, OFF:defined) */ |
115 | uint32_t res_mask; | |
eaab4d60 AK |
116 | /* reg read only field mask (ON:RO/ROS, OFF:other) */ |
117 | uint32_t ro_mask; | |
55c8672c JB |
118 | /* reg read/write-1-clear field mask (ON:RW1C/RW1CS, OFF:other) */ |
119 | uint32_t rw1c_mask; | |
eaab4d60 AK |
120 | /* reg emulate field mask (ON:emu, OFF:passthrough) */ |
121 | uint32_t emu_mask; | |
eaab4d60 AK |
122 | xen_pt_conf_reg_init init; |
123 | /* read/write function pointer | |
124 | * for double_word/word/byte size */ | |
125 | union { | |
126 | struct { | |
127 | xen_pt_conf_dword_write write; | |
128 | xen_pt_conf_dword_read read; | |
129 | } dw; | |
130 | struct { | |
131 | xen_pt_conf_word_write write; | |
132 | xen_pt_conf_word_read read; | |
133 | } w; | |
134 | struct { | |
135 | xen_pt_conf_byte_write write; | |
136 | xen_pt_conf_byte_read read; | |
137 | } b; | |
138 | } u; | |
139 | }; | |
140 | ||
141 | /* emulated register management */ | |
142 | struct XenPTReg { | |
143 | QLIST_ENTRY(XenPTReg) entries; | |
144 | XenPTRegInfo *reg; | |
e2779de0 KRW |
145 | union { |
146 | uint8_t *byte; | |
147 | uint16_t *half_word; | |
148 | uint32_t *word; | |
149 | } ptr; /* pointer to dev.config. */ | |
eaab4d60 AK |
150 | }; |
151 | ||
74526eb0 | 152 | typedef const struct XenPTRegGroupInfo XenPTRegGroupInfo; |
eaab4d60 AK |
153 | |
154 | /* emul reg group size initialize method */ | |
155 | typedef int (*xen_pt_reg_size_init_fn) | |
74526eb0 | 156 | (XenPCIPassthroughState *, XenPTRegGroupInfo *, |
eaab4d60 AK |
157 | uint32_t base_offset, uint8_t *size); |
158 | ||
0546b8c2 | 159 | /* emulated register group information */ |
eaab4d60 AK |
160 | struct XenPTRegGroupInfo { |
161 | uint8_t grp_id; | |
162 | XenPTRegisterGroupType grp_type; | |
163 | uint8_t grp_size; | |
164 | xen_pt_reg_size_init_fn size_init; | |
165 | XenPTRegInfo *emu_regs; | |
166 | }; | |
167 | ||
168 | /* emul register group management table */ | |
169 | typedef struct XenPTRegGroup { | |
170 | QLIST_ENTRY(XenPTRegGroup) entries; | |
74526eb0 | 171 | XenPTRegGroupInfo *reg_grp; |
eaab4d60 AK |
172 | uint32_t base_offset; |
173 | uint8_t size; | |
174 | QLIST_HEAD(, XenPTReg) reg_tbl_list; | |
175 | } XenPTRegGroup; | |
176 | ||
177 | ||
178 | #define XEN_PT_UNASSIGNED_PIRQ (-1) | |
3854ca57 JY |
179 | typedef struct XenPTMSI { |
180 | uint16_t flags; | |
181 | uint32_t addr_lo; /* guest message address */ | |
182 | uint32_t addr_hi; /* guest message upper address */ | |
183 | uint16_t data; /* guest message data */ | |
184 | uint32_t ctrl_offset; /* saved control offset */ | |
a8036336 | 185 | uint32_t mask; /* guest mask bits */ |
3854ca57 JY |
186 | int pirq; /* guest pirq corresponding */ |
187 | bool initialized; /* when guest MSI is initialized */ | |
188 | bool mapped; /* when pirq is mapped */ | |
189 | } XenPTMSI; | |
190 | ||
191 | typedef struct XenPTMSIXEntry { | |
192 | int pirq; | |
193 | uint64_t addr; | |
194 | uint32_t data; | |
f0ada360 | 195 | uint32_t latch[4]; |
3854ca57 JY |
196 | bool updated; /* indicate whether MSI ADDR or DATA is updated */ |
197 | } XenPTMSIXEntry; | |
198 | typedef struct XenPTMSIX { | |
199 | uint32_t ctrl_offset; | |
200 | bool enabled; | |
f0ada360 | 201 | bool maskall; |
3854ca57 JY |
202 | int total_entries; |
203 | int bar_index; | |
204 | uint64_t table_base; | |
205 | uint32_t table_offset_adjust; /* page align mmap */ | |
206 | uint64_t mmio_base_addr; | |
207 | MemoryRegion mmio; | |
208 | void *phys_iomem_base; | |
f7795e40 | 209 | XenPTMSIXEntry msix_entry[]; |
3854ca57 | 210 | } XenPTMSIX; |
eaab4d60 AK |
211 | |
212 | struct XenPCIPassthroughState { | |
213 | PCIDevice dev; | |
214 | ||
215 | PCIHostDeviceAddress hostaddr; | |
216 | bool is_virtfn; | |
c25bbf15 JB |
217 | bool permissive; |
218 | bool permissive_warned; | |
eaab4d60 AK |
219 | XenHostPCIDevice real_device; |
220 | XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */ | |
221 | QLIST_HEAD(, XenPTRegGroup) reg_grps; | |
222 | ||
223 | uint32_t machine_irq; | |
224 | ||
3854ca57 JY |
225 | XenPTMSI *msi; |
226 | XenPTMSIX *msix; | |
227 | ||
eaab4d60 AK |
228 | MemoryRegion bar[PCI_NUM_REGIONS - 1]; |
229 | MemoryRegion rom; | |
230 | ||
231 | MemoryListener memory_listener; | |
12b40e47 | 232 | MemoryListener io_listener; |
bce33948 | 233 | bool listener_set; |
eaab4d60 AK |
234 | }; |
235 | ||
d50a6e58 | 236 | void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp); |
eaab4d60 AK |
237 | void xen_pt_config_delete(XenPCIPassthroughState *s); |
238 | XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address); | |
239 | XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address); | |
240 | int xen_pt_bar_offset_to_index(uint32_t offset); | |
241 | ||
242 | static inline pcibus_t xen_pt_get_emul_size(XenPTBarFlag flag, pcibus_t r_size) | |
243 | { | |
244 | /* align resource size (memory type only) */ | |
245 | if (flag == XEN_PT_BAR_FLAG_MEM) { | |
246 | return (r_size + XC_PAGE_SIZE - 1) & XC_PAGE_MASK; | |
247 | } else { | |
248 | return r_size; | |
249 | } | |
250 | } | |
251 | ||
252 | /* INTx */ | |
253 | /* The PCI Local Bus Specification, Rev. 3.0, | |
254 | * Section 6.2.4 Miscellaneous Registers, pp 223 | |
255 | * outlines 5 valid values for the interrupt pin (intx). | |
256 | * 0: For devices (or device functions) that don't use an interrupt in | |
257 | * 1: INTA# | |
258 | * 2: INTB# | |
259 | * 3: INTC# | |
260 | * 4: INTD# | |
261 | * | |
262 | * Xen uses the following 4 values for intx | |
263 | * 0: INTA# | |
264 | * 1: INTB# | |
265 | * 2: INTC# | |
266 | * 3: INTD# | |
267 | * | |
268 | * Observing that these list of values are not the same, xen_pt_pci_read_intx() | |
269 | * uses the following mapping from hw to xen values. | |
270 | * This seems to reflect the current usage within Xen. | |
271 | * | |
272 | * PCI hardware | Xen | Notes | |
273 | * ----------------+-----+---------------------------------------------------- | |
274 | * 0 | 0 | No interrupt | |
275 | * 1 | 0 | INTA# | |
276 | * 2 | 1 | INTB# | |
277 | * 3 | 2 | INTC# | |
278 | * 4 | 3 | INTD# | |
279 | * any other value | 0 | This should never happen, log error message | |
280 | */ | |
281 | ||
282 | static inline uint8_t xen_pt_pci_read_intx(XenPCIPassthroughState *s) | |
283 | { | |
284 | uint8_t v = 0; | |
285 | xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &v); | |
286 | return v; | |
287 | } | |
288 | ||
289 | static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s) | |
290 | { | |
291 | uint8_t r_val = xen_pt_pci_read_intx(s); | |
292 | ||
293 | XEN_PT_LOG(&s->dev, "intx=%i\n", r_val); | |
294 | if (r_val < 1 || r_val > 4) { | |
295 | XEN_PT_LOG(&s->dev, "Interrupt pin read from hardware is out of range:" | |
296 | " value=%i, acceptable range is 1 - 4\n", r_val); | |
297 | r_val = 0; | |
298 | } else { | |
bce33948 | 299 | /* Note that if s.real_device.config_fd is closed we make 0xff. */ |
eaab4d60 AK |
300 | r_val -= 1; |
301 | } | |
302 | ||
303 | return r_val; | |
304 | } | |
305 | ||
3854ca57 | 306 | /* MSI/MSI-X */ |
3854ca57 JY |
307 | int xen_pt_msi_setup(XenPCIPassthroughState *s); |
308 | int xen_pt_msi_update(XenPCIPassthroughState *d); | |
309 | void xen_pt_msi_disable(XenPCIPassthroughState *s); | |
310 | ||
311 | int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base); | |
312 | void xen_pt_msix_delete(XenPCIPassthroughState *s); | |
4e494de6 | 313 | void xen_pt_msix_unmap(XenPCIPassthroughState *s); |
3854ca57 JY |
314 | int xen_pt_msix_update(XenPCIPassthroughState *s); |
315 | int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index); | |
316 | void xen_pt_msix_disable(XenPCIPassthroughState *s); | |
317 | ||
318 | static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar) | |
319 | { | |
320 | return s->msix && s->msix->bar_index == bar; | |
321 | } | |
322 | ||
881213f1 | 323 | extern void *pci_assign_dev_load_option_rom(PCIDevice *dev, |
6dad8260 | 324 | int *size, |
881213f1 TC |
325 | unsigned int domain, |
326 | unsigned int bus, unsigned int slot, | |
327 | unsigned int function); | |
79814179 TC |
328 | static inline bool is_igd_vga_passthrough(XenHostPCIDevice *dev) |
329 | { | |
acd0c941 | 330 | return (xen_igd_gfx_pt_enabled() |
79814179 TC |
331 | && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA)); |
332 | } | |
333 | int xen_pt_register_vga_regions(XenHostPCIDevice *dev); | |
334 | int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev); | |
5226bb59 C |
335 | void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev, |
336 | Error **errp); | |
175de524 | 337 | #endif /* XEN_PT_H */ |