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