root / hw / xen_pt_config_init.c @ 5e22c276
History | View | Annotate | Download (57.2 kB)
1 | 93d7ae8e | Allen Kay | /*
|
---|---|---|---|
2 | 93d7ae8e | Allen Kay | * Copyright (c) 2007, Neocleus Corporation.
|
3 | 93d7ae8e | Allen Kay | * Copyright (c) 2007, Intel Corporation.
|
4 | 93d7ae8e | Allen Kay | *
|
5 | 93d7ae8e | Allen Kay | * This work is licensed under the terms of the GNU GPL, version 2. See
|
6 | 93d7ae8e | Allen Kay | * the COPYING file in the top-level directory.
|
7 | 93d7ae8e | Allen Kay | *
|
8 | 93d7ae8e | Allen Kay | * Alex Novik <alex@neocleus.com>
|
9 | 93d7ae8e | Allen Kay | * Allen Kay <allen.m.kay@intel.com>
|
10 | 93d7ae8e | Allen Kay | * Guy Zana <guy@neocleus.com>
|
11 | 93d7ae8e | Allen Kay | *
|
12 | 93d7ae8e | Allen Kay | * This file implements direct PCI assignment to a HVM guest
|
13 | 93d7ae8e | Allen Kay | */
|
14 | 93d7ae8e | Allen Kay | |
15 | 1de7afc9 | Paolo Bonzini | #include "qemu/timer.h" |
16 | 93d7ae8e | Allen Kay | #include "xen_backend.h" |
17 | eaab4d60 | Allen Kay | #include "xen_pt.h" |
18 | eaab4d60 | Allen Kay | |
19 | 93d7ae8e | Allen Kay | #define XEN_PT_MERGE_VALUE(value, data, val_mask) \
|
20 | 93d7ae8e | Allen Kay | (((value) & (val_mask)) | ((data) & ~(val_mask))) |
21 | 93d7ae8e | Allen Kay | |
22 | 93d7ae8e | Allen Kay | #define XEN_PT_INVALID_REG 0xFFFFFFFF /* invalid register value */ |
23 | 93d7ae8e | Allen Kay | |
24 | 93d7ae8e | Allen Kay | /* prototype */
|
25 | 93d7ae8e | Allen Kay | |
26 | 93d7ae8e | Allen Kay | static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg, |
27 | 93d7ae8e | Allen Kay | uint32_t real_offset, uint32_t *data); |
28 | 93d7ae8e | Allen Kay | |
29 | 93d7ae8e | Allen Kay | |
30 | 93d7ae8e | Allen Kay | /* helper */
|
31 | 93d7ae8e | Allen Kay | |
32 | 93d7ae8e | Allen Kay | /* A return value of 1 means the capability should NOT be exposed to guest. */
|
33 | 93d7ae8e | Allen Kay | static int xen_pt_hide_dev_cap(const XenHostPCIDevice *d, uint8_t grp_id) |
34 | 93d7ae8e | Allen Kay | { |
35 | 93d7ae8e | Allen Kay | switch (grp_id) {
|
36 | 93d7ae8e | Allen Kay | case PCI_CAP_ID_EXP:
|
37 | 93d7ae8e | Allen Kay | /* The PCI Express Capability Structure of the VF of Intel 82599 10GbE
|
38 | 93d7ae8e | Allen Kay | * Controller looks trivial, e.g., the PCI Express Capabilities
|
39 | 93d7ae8e | Allen Kay | * Register is 0. We should not try to expose it to guest.
|
40 | 93d7ae8e | Allen Kay | *
|
41 | 93d7ae8e | Allen Kay | * The datasheet is available at
|
42 | 93d7ae8e | Allen Kay | * http://download.intel.com/design/network/datashts/82599_datasheet.pdf
|
43 | 93d7ae8e | Allen Kay | *
|
44 | 93d7ae8e | Allen Kay | * See 'Table 9.7. VF PCIe Configuration Space' of the datasheet, the
|
45 | 93d7ae8e | Allen Kay | * PCI Express Capability Structure of the VF of Intel 82599 10GbE
|
46 | 93d7ae8e | Allen Kay | * Controller looks trivial, e.g., the PCI Express Capabilities
|
47 | 93d7ae8e | Allen Kay | * Register is 0, so the Capability Version is 0 and
|
48 | 93d7ae8e | Allen Kay | * xen_pt_pcie_size_init() would fail.
|
49 | 93d7ae8e | Allen Kay | */
|
50 | 93d7ae8e | Allen Kay | if (d->vendor_id == PCI_VENDOR_ID_INTEL &&
|
51 | 93d7ae8e | Allen Kay | d->device_id == PCI_DEVICE_ID_INTEL_82599_SFP_VF) { |
52 | 93d7ae8e | Allen Kay | return 1; |
53 | 93d7ae8e | Allen Kay | } |
54 | 93d7ae8e | Allen Kay | break;
|
55 | 93d7ae8e | Allen Kay | } |
56 | 93d7ae8e | Allen Kay | return 0; |
57 | 93d7ae8e | Allen Kay | } |
58 | 93d7ae8e | Allen Kay | |
59 | 93d7ae8e | Allen Kay | /* find emulate register group entry */
|
60 | eaab4d60 | Allen Kay | XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address) |
61 | eaab4d60 | Allen Kay | { |
62 | 93d7ae8e | Allen Kay | XenPTRegGroup *entry = NULL;
|
63 | 93d7ae8e | Allen Kay | |
64 | 93d7ae8e | Allen Kay | /* find register group entry */
|
65 | 93d7ae8e | Allen Kay | QLIST_FOREACH(entry, &s->reg_grps, entries) { |
66 | 93d7ae8e | Allen Kay | /* check address */
|
67 | 93d7ae8e | Allen Kay | if ((entry->base_offset <= address)
|
68 | 93d7ae8e | Allen Kay | && ((entry->base_offset + entry->size) > address)) { |
69 | 93d7ae8e | Allen Kay | return entry;
|
70 | 93d7ae8e | Allen Kay | } |
71 | 93d7ae8e | Allen Kay | } |
72 | 93d7ae8e | Allen Kay | |
73 | 93d7ae8e | Allen Kay | /* group entry not found */
|
74 | eaab4d60 | Allen Kay | return NULL; |
75 | eaab4d60 | Allen Kay | } |
76 | eaab4d60 | Allen Kay | |
77 | 93d7ae8e | Allen Kay | /* find emulate register entry */
|
78 | eaab4d60 | Allen Kay | XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address) |
79 | eaab4d60 | Allen Kay | { |
80 | 93d7ae8e | Allen Kay | XenPTReg *reg_entry = NULL;
|
81 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = NULL;
|
82 | 93d7ae8e | Allen Kay | uint32_t real_offset = 0;
|
83 | 93d7ae8e | Allen Kay | |
84 | 93d7ae8e | Allen Kay | /* find register entry */
|
85 | 93d7ae8e | Allen Kay | QLIST_FOREACH(reg_entry, ®_grp->reg_tbl_list, entries) { |
86 | 93d7ae8e | Allen Kay | reg = reg_entry->reg; |
87 | 93d7ae8e | Allen Kay | real_offset = reg_grp->base_offset + reg->offset; |
88 | 93d7ae8e | Allen Kay | /* check address */
|
89 | 93d7ae8e | Allen Kay | if ((real_offset <= address)
|
90 | 93d7ae8e | Allen Kay | && ((real_offset + reg->size) > address)) { |
91 | 93d7ae8e | Allen Kay | return reg_entry;
|
92 | 93d7ae8e | Allen Kay | } |
93 | 93d7ae8e | Allen Kay | } |
94 | 93d7ae8e | Allen Kay | |
95 | eaab4d60 | Allen Kay | return NULL; |
96 | eaab4d60 | Allen Kay | } |
97 | 93d7ae8e | Allen Kay | |
98 | 93d7ae8e | Allen Kay | |
99 | 93d7ae8e | Allen Kay | /****************
|
100 | 93d7ae8e | Allen Kay | * general register functions
|
101 | 93d7ae8e | Allen Kay | */
|
102 | 93d7ae8e | Allen Kay | |
103 | 93d7ae8e | Allen Kay | /* register initialization function */
|
104 | 93d7ae8e | Allen Kay | |
105 | 93d7ae8e | Allen Kay | static int xen_pt_common_reg_init(XenPCIPassthroughState *s, |
106 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg, uint32_t real_offset, |
107 | 93d7ae8e | Allen Kay | uint32_t *data) |
108 | 93d7ae8e | Allen Kay | { |
109 | 93d7ae8e | Allen Kay | *data = reg->init_val; |
110 | 93d7ae8e | Allen Kay | return 0; |
111 | 93d7ae8e | Allen Kay | } |
112 | 93d7ae8e | Allen Kay | |
113 | 93d7ae8e | Allen Kay | /* Read register functions */
|
114 | 93d7ae8e | Allen Kay | |
115 | 93d7ae8e | Allen Kay | static int xen_pt_byte_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry, |
116 | 93d7ae8e | Allen Kay | uint8_t *value, uint8_t valid_mask) |
117 | 93d7ae8e | Allen Kay | { |
118 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = cfg_entry->reg; |
119 | 93d7ae8e | Allen Kay | uint8_t valid_emu_mask = 0;
|
120 | 93d7ae8e | Allen Kay | |
121 | 93d7ae8e | Allen Kay | /* emulate byte register */
|
122 | 93d7ae8e | Allen Kay | valid_emu_mask = reg->emu_mask & valid_mask; |
123 | 93d7ae8e | Allen Kay | *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask); |
124 | 93d7ae8e | Allen Kay | |
125 | 93d7ae8e | Allen Kay | return 0; |
126 | 93d7ae8e | Allen Kay | } |
127 | 93d7ae8e | Allen Kay | static int xen_pt_word_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry, |
128 | 93d7ae8e | Allen Kay | uint16_t *value, uint16_t valid_mask) |
129 | 93d7ae8e | Allen Kay | { |
130 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = cfg_entry->reg; |
131 | 93d7ae8e | Allen Kay | uint16_t valid_emu_mask = 0;
|
132 | 93d7ae8e | Allen Kay | |
133 | 93d7ae8e | Allen Kay | /* emulate word register */
|
134 | 93d7ae8e | Allen Kay | valid_emu_mask = reg->emu_mask & valid_mask; |
135 | 93d7ae8e | Allen Kay | *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask); |
136 | 93d7ae8e | Allen Kay | |
137 | 93d7ae8e | Allen Kay | return 0; |
138 | 93d7ae8e | Allen Kay | } |
139 | 93d7ae8e | Allen Kay | static int xen_pt_long_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry, |
140 | 93d7ae8e | Allen Kay | uint32_t *value, uint32_t valid_mask) |
141 | 93d7ae8e | Allen Kay | { |
142 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = cfg_entry->reg; |
143 | 93d7ae8e | Allen Kay | uint32_t valid_emu_mask = 0;
|
144 | 93d7ae8e | Allen Kay | |
145 | 93d7ae8e | Allen Kay | /* emulate long register */
|
146 | 93d7ae8e | Allen Kay | valid_emu_mask = reg->emu_mask & valid_mask; |
147 | 93d7ae8e | Allen Kay | *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask); |
148 | 93d7ae8e | Allen Kay | |
149 | 93d7ae8e | Allen Kay | return 0; |
150 | 93d7ae8e | Allen Kay | } |
151 | 93d7ae8e | Allen Kay | |
152 | 93d7ae8e | Allen Kay | /* Write register functions */
|
153 | 93d7ae8e | Allen Kay | |
154 | 93d7ae8e | Allen Kay | static int xen_pt_byte_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, |
155 | 93d7ae8e | Allen Kay | uint8_t *val, uint8_t dev_value, |
156 | 93d7ae8e | Allen Kay | uint8_t valid_mask) |
157 | 93d7ae8e | Allen Kay | { |
158 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = cfg_entry->reg; |
159 | 93d7ae8e | Allen Kay | uint8_t writable_mask = 0;
|
160 | 93d7ae8e | Allen Kay | uint8_t throughable_mask = 0;
|
161 | 93d7ae8e | Allen Kay | |
162 | 93d7ae8e | Allen Kay | /* modify emulate register */
|
163 | 93d7ae8e | Allen Kay | writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; |
164 | 93d7ae8e | Allen Kay | cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); |
165 | 93d7ae8e | Allen Kay | |
166 | 93d7ae8e | Allen Kay | /* create value for writing to I/O device register */
|
167 | 93d7ae8e | Allen Kay | throughable_mask = ~reg->emu_mask & valid_mask; |
168 | 93d7ae8e | Allen Kay | *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); |
169 | 93d7ae8e | Allen Kay | |
170 | 93d7ae8e | Allen Kay | return 0; |
171 | 93d7ae8e | Allen Kay | } |
172 | 93d7ae8e | Allen Kay | static int xen_pt_word_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, |
173 | 93d7ae8e | Allen Kay | uint16_t *val, uint16_t dev_value, |
174 | 93d7ae8e | Allen Kay | uint16_t valid_mask) |
175 | 93d7ae8e | Allen Kay | { |
176 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = cfg_entry->reg; |
177 | 93d7ae8e | Allen Kay | uint16_t writable_mask = 0;
|
178 | 93d7ae8e | Allen Kay | uint16_t throughable_mask = 0;
|
179 | 93d7ae8e | Allen Kay | |
180 | 93d7ae8e | Allen Kay | /* modify emulate register */
|
181 | 93d7ae8e | Allen Kay | writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; |
182 | 93d7ae8e | Allen Kay | cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); |
183 | 93d7ae8e | Allen Kay | |
184 | 93d7ae8e | Allen Kay | /* create value for writing to I/O device register */
|
185 | 93d7ae8e | Allen Kay | throughable_mask = ~reg->emu_mask & valid_mask; |
186 | 93d7ae8e | Allen Kay | *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); |
187 | 93d7ae8e | Allen Kay | |
188 | 93d7ae8e | Allen Kay | return 0; |
189 | 93d7ae8e | Allen Kay | } |
190 | 93d7ae8e | Allen Kay | static int xen_pt_long_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, |
191 | 93d7ae8e | Allen Kay | uint32_t *val, uint32_t dev_value, |
192 | 93d7ae8e | Allen Kay | uint32_t valid_mask) |
193 | 93d7ae8e | Allen Kay | { |
194 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = cfg_entry->reg; |
195 | 93d7ae8e | Allen Kay | uint32_t writable_mask = 0;
|
196 | 93d7ae8e | Allen Kay | uint32_t throughable_mask = 0;
|
197 | 93d7ae8e | Allen Kay | |
198 | 93d7ae8e | Allen Kay | /* modify emulate register */
|
199 | 93d7ae8e | Allen Kay | writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; |
200 | 93d7ae8e | Allen Kay | cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); |
201 | 93d7ae8e | Allen Kay | |
202 | 93d7ae8e | Allen Kay | /* create value for writing to I/O device register */
|
203 | 93d7ae8e | Allen Kay | throughable_mask = ~reg->emu_mask & valid_mask; |
204 | 93d7ae8e | Allen Kay | *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); |
205 | 93d7ae8e | Allen Kay | |
206 | 93d7ae8e | Allen Kay | return 0; |
207 | 93d7ae8e | Allen Kay | } |
208 | 93d7ae8e | Allen Kay | |
209 | 93d7ae8e | Allen Kay | |
210 | 93d7ae8e | Allen Kay | /* XenPTRegInfo declaration
|
211 | 93d7ae8e | Allen Kay | * - only for emulated register (either a part or whole bit).
|
212 | 93d7ae8e | Allen Kay | * - for passthrough register that need special behavior (like interacting with
|
213 | 93d7ae8e | Allen Kay | * other component), set emu_mask to all 0 and specify r/w func properly.
|
214 | 93d7ae8e | Allen Kay | * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
|
215 | 93d7ae8e | Allen Kay | */
|
216 | 93d7ae8e | Allen Kay | |
217 | 93d7ae8e | Allen Kay | /********************
|
218 | 93d7ae8e | Allen Kay | * Header Type0
|
219 | 93d7ae8e | Allen Kay | */
|
220 | 93d7ae8e | Allen Kay | |
221 | 93d7ae8e | Allen Kay | static int xen_pt_vendor_reg_init(XenPCIPassthroughState *s, |
222 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg, uint32_t real_offset, |
223 | 93d7ae8e | Allen Kay | uint32_t *data) |
224 | 93d7ae8e | Allen Kay | { |
225 | 93d7ae8e | Allen Kay | *data = s->real_device.vendor_id; |
226 | 93d7ae8e | Allen Kay | return 0; |
227 | 93d7ae8e | Allen Kay | } |
228 | 93d7ae8e | Allen Kay | static int xen_pt_device_reg_init(XenPCIPassthroughState *s, |
229 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg, uint32_t real_offset, |
230 | 93d7ae8e | Allen Kay | uint32_t *data) |
231 | 93d7ae8e | Allen Kay | { |
232 | 93d7ae8e | Allen Kay | *data = s->real_device.device_id; |
233 | 93d7ae8e | Allen Kay | return 0; |
234 | 93d7ae8e | Allen Kay | } |
235 | 93d7ae8e | Allen Kay | static int xen_pt_status_reg_init(XenPCIPassthroughState *s, |
236 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg, uint32_t real_offset, |
237 | 93d7ae8e | Allen Kay | uint32_t *data) |
238 | 93d7ae8e | Allen Kay | { |
239 | 93d7ae8e | Allen Kay | XenPTRegGroup *reg_grp_entry = NULL;
|
240 | 93d7ae8e | Allen Kay | XenPTReg *reg_entry = NULL;
|
241 | 93d7ae8e | Allen Kay | uint32_t reg_field = 0;
|
242 | 93d7ae8e | Allen Kay | |
243 | 93d7ae8e | Allen Kay | /* find Header register group */
|
244 | 93d7ae8e | Allen Kay | reg_grp_entry = xen_pt_find_reg_grp(s, PCI_CAPABILITY_LIST); |
245 | 93d7ae8e | Allen Kay | if (reg_grp_entry) {
|
246 | 93d7ae8e | Allen Kay | /* find Capabilities Pointer register */
|
247 | 93d7ae8e | Allen Kay | reg_entry = xen_pt_find_reg(reg_grp_entry, PCI_CAPABILITY_LIST); |
248 | 93d7ae8e | Allen Kay | if (reg_entry) {
|
249 | 93d7ae8e | Allen Kay | /* check Capabilities Pointer register */
|
250 | 93d7ae8e | Allen Kay | if (reg_entry->data) {
|
251 | 93d7ae8e | Allen Kay | reg_field |= PCI_STATUS_CAP_LIST; |
252 | 93d7ae8e | Allen Kay | } else {
|
253 | 93d7ae8e | Allen Kay | reg_field &= ~PCI_STATUS_CAP_LIST; |
254 | 93d7ae8e | Allen Kay | } |
255 | 93d7ae8e | Allen Kay | } else {
|
256 | 93d7ae8e | Allen Kay | xen_shutdown_fatal_error("Internal error: Couldn't find XenPTReg*"
|
257 | 93d7ae8e | Allen Kay | " for Capabilities Pointer register."
|
258 | 93d7ae8e | Allen Kay | " (%s)\n", __func__);
|
259 | 93d7ae8e | Allen Kay | return -1; |
260 | 93d7ae8e | Allen Kay | } |
261 | 93d7ae8e | Allen Kay | } else {
|
262 | 93d7ae8e | Allen Kay | xen_shutdown_fatal_error("Internal error: Couldn't find XenPTRegGroup"
|
263 | 93d7ae8e | Allen Kay | " for Header. (%s)\n", __func__);
|
264 | 93d7ae8e | Allen Kay | return -1; |
265 | 93d7ae8e | Allen Kay | } |
266 | 93d7ae8e | Allen Kay | |
267 | 93d7ae8e | Allen Kay | *data = reg_field; |
268 | 93d7ae8e | Allen Kay | return 0; |
269 | 93d7ae8e | Allen Kay | } |
270 | 93d7ae8e | Allen Kay | static int xen_pt_header_type_reg_init(XenPCIPassthroughState *s, |
271 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg, uint32_t real_offset, |
272 | 93d7ae8e | Allen Kay | uint32_t *data) |
273 | 93d7ae8e | Allen Kay | { |
274 | 93d7ae8e | Allen Kay | /* read PCI_HEADER_TYPE */
|
275 | 93d7ae8e | Allen Kay | *data = reg->init_val | 0x80;
|
276 | 93d7ae8e | Allen Kay | return 0; |
277 | 93d7ae8e | Allen Kay | } |
278 | 93d7ae8e | Allen Kay | |
279 | 93d7ae8e | Allen Kay | /* initialize Interrupt Pin register */
|
280 | 93d7ae8e | Allen Kay | static int xen_pt_irqpin_reg_init(XenPCIPassthroughState *s, |
281 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg, uint32_t real_offset, |
282 | 93d7ae8e | Allen Kay | uint32_t *data) |
283 | 93d7ae8e | Allen Kay | { |
284 | 93d7ae8e | Allen Kay | *data = xen_pt_pci_read_intx(s); |
285 | 93d7ae8e | Allen Kay | return 0; |
286 | 93d7ae8e | Allen Kay | } |
287 | 93d7ae8e | Allen Kay | |
288 | 93d7ae8e | Allen Kay | /* Command register */
|
289 | 93d7ae8e | Allen Kay | static int xen_pt_cmd_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry, |
290 | 93d7ae8e | Allen Kay | uint16_t *value, uint16_t valid_mask) |
291 | 93d7ae8e | Allen Kay | { |
292 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = cfg_entry->reg; |
293 | 93d7ae8e | Allen Kay | uint16_t valid_emu_mask = 0;
|
294 | 93d7ae8e | Allen Kay | uint16_t emu_mask = reg->emu_mask; |
295 | 93d7ae8e | Allen Kay | |
296 | 93d7ae8e | Allen Kay | if (s->is_virtfn) {
|
297 | 93d7ae8e | Allen Kay | emu_mask |= PCI_COMMAND_MEMORY; |
298 | 93d7ae8e | Allen Kay | } |
299 | 93d7ae8e | Allen Kay | |
300 | 93d7ae8e | Allen Kay | /* emulate word register */
|
301 | 93d7ae8e | Allen Kay | valid_emu_mask = emu_mask & valid_mask; |
302 | 93d7ae8e | Allen Kay | *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask); |
303 | 93d7ae8e | Allen Kay | |
304 | 93d7ae8e | Allen Kay | return 0; |
305 | 93d7ae8e | Allen Kay | } |
306 | 93d7ae8e | Allen Kay | static int xen_pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, |
307 | 93d7ae8e | Allen Kay | uint16_t *val, uint16_t dev_value, |
308 | 93d7ae8e | Allen Kay | uint16_t valid_mask) |
309 | 93d7ae8e | Allen Kay | { |
310 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = cfg_entry->reg; |
311 | 93d7ae8e | Allen Kay | uint16_t writable_mask = 0;
|
312 | 93d7ae8e | Allen Kay | uint16_t throughable_mask = 0;
|
313 | 93d7ae8e | Allen Kay | uint16_t emu_mask = reg->emu_mask; |
314 | 93d7ae8e | Allen Kay | |
315 | 93d7ae8e | Allen Kay | if (s->is_virtfn) {
|
316 | 93d7ae8e | Allen Kay | emu_mask |= PCI_COMMAND_MEMORY; |
317 | 93d7ae8e | Allen Kay | } |
318 | 93d7ae8e | Allen Kay | |
319 | 93d7ae8e | Allen Kay | /* modify emulate register */
|
320 | 93d7ae8e | Allen Kay | writable_mask = ~reg->ro_mask & valid_mask; |
321 | 93d7ae8e | Allen Kay | cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); |
322 | 93d7ae8e | Allen Kay | |
323 | 93d7ae8e | Allen Kay | /* create value for writing to I/O device register */
|
324 | 93d7ae8e | Allen Kay | throughable_mask = ~emu_mask & valid_mask; |
325 | 93d7ae8e | Allen Kay | |
326 | 93d7ae8e | Allen Kay | if (*val & PCI_COMMAND_INTX_DISABLE) {
|
327 | 93d7ae8e | Allen Kay | throughable_mask |= PCI_COMMAND_INTX_DISABLE; |
328 | 93d7ae8e | Allen Kay | } else {
|
329 | 93d7ae8e | Allen Kay | if (s->machine_irq) {
|
330 | 93d7ae8e | Allen Kay | throughable_mask |= PCI_COMMAND_INTX_DISABLE; |
331 | 93d7ae8e | Allen Kay | } |
332 | 93d7ae8e | Allen Kay | } |
333 | 93d7ae8e | Allen Kay | |
334 | 93d7ae8e | Allen Kay | *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); |
335 | 93d7ae8e | Allen Kay | |
336 | 93d7ae8e | Allen Kay | return 0; |
337 | 93d7ae8e | Allen Kay | } |
338 | 93d7ae8e | Allen Kay | |
339 | 93d7ae8e | Allen Kay | /* BAR */
|
340 | 93d7ae8e | Allen Kay | #define XEN_PT_BAR_MEM_RO_MASK 0x0000000F /* BAR ReadOnly mask(Memory) */ |
341 | 93d7ae8e | Allen Kay | #define XEN_PT_BAR_MEM_EMU_MASK 0xFFFFFFF0 /* BAR emul mask(Memory) */ |
342 | 93d7ae8e | Allen Kay | #define XEN_PT_BAR_IO_RO_MASK 0x00000003 /* BAR ReadOnly mask(I/O) */ |
343 | 93d7ae8e | Allen Kay | #define XEN_PT_BAR_IO_EMU_MASK 0xFFFFFFFC /* BAR emul mask(I/O) */ |
344 | 93d7ae8e | Allen Kay | |
345 | aabc8530 | Xudong Hao | static bool is_64bit_bar(PCIIORegion *r) |
346 | aabc8530 | Xudong Hao | { |
347 | aabc8530 | Xudong Hao | return !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
|
348 | aabc8530 | Xudong Hao | } |
349 | aabc8530 | Xudong Hao | |
350 | aabc8530 | Xudong Hao | static uint64_t xen_pt_get_bar_size(PCIIORegion *r)
|
351 | aabc8530 | Xudong Hao | { |
352 | aabc8530 | Xudong Hao | if (is_64bit_bar(r)) {
|
353 | aabc8530 | Xudong Hao | uint64_t size64; |
354 | aabc8530 | Xudong Hao | size64 = (r + 1)->size;
|
355 | aabc8530 | Xudong Hao | size64 <<= 32;
|
356 | aabc8530 | Xudong Hao | size64 += r->size; |
357 | aabc8530 | Xudong Hao | return size64;
|
358 | aabc8530 | Xudong Hao | } |
359 | aabc8530 | Xudong Hao | return r->size;
|
360 | aabc8530 | Xudong Hao | } |
361 | aabc8530 | Xudong Hao | |
362 | 93d7ae8e | Allen Kay | static XenPTBarFlag xen_pt_bar_reg_parse(XenPCIPassthroughState *s,
|
363 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg) |
364 | 93d7ae8e | Allen Kay | { |
365 | 93d7ae8e | Allen Kay | PCIDevice *d = &s->dev; |
366 | 93d7ae8e | Allen Kay | XenPTRegion *region = NULL;
|
367 | 93d7ae8e | Allen Kay | PCIIORegion *r; |
368 | 93d7ae8e | Allen Kay | int index = 0; |
369 | 93d7ae8e | Allen Kay | |
370 | 93d7ae8e | Allen Kay | /* check 64bit BAR */
|
371 | 93d7ae8e | Allen Kay | index = xen_pt_bar_offset_to_index(reg->offset); |
372 | 93d7ae8e | Allen Kay | if ((0 < index) && (index < PCI_ROM_SLOT)) { |
373 | 93d7ae8e | Allen Kay | int type = s->real_device.io_regions[index - 1].type; |
374 | 93d7ae8e | Allen Kay | |
375 | 93d7ae8e | Allen Kay | if ((type & XEN_HOST_PCI_REGION_TYPE_MEM)
|
376 | 93d7ae8e | Allen Kay | && (type & XEN_HOST_PCI_REGION_TYPE_MEM_64)) { |
377 | 93d7ae8e | Allen Kay | region = &s->bases[index - 1];
|
378 | 93d7ae8e | Allen Kay | if (region->bar_flag != XEN_PT_BAR_FLAG_UPPER) {
|
379 | 93d7ae8e | Allen Kay | return XEN_PT_BAR_FLAG_UPPER;
|
380 | 93d7ae8e | Allen Kay | } |
381 | 93d7ae8e | Allen Kay | } |
382 | 93d7ae8e | Allen Kay | } |
383 | 93d7ae8e | Allen Kay | |
384 | 93d7ae8e | Allen Kay | /* check unused BAR */
|
385 | 93d7ae8e | Allen Kay | r = &d->io_regions[index]; |
386 | aabc8530 | Xudong Hao | if (!xen_pt_get_bar_size(r)) {
|
387 | 93d7ae8e | Allen Kay | return XEN_PT_BAR_FLAG_UNUSED;
|
388 | 93d7ae8e | Allen Kay | } |
389 | 93d7ae8e | Allen Kay | |
390 | 93d7ae8e | Allen Kay | /* for ExpROM BAR */
|
391 | 93d7ae8e | Allen Kay | if (index == PCI_ROM_SLOT) {
|
392 | 93d7ae8e | Allen Kay | return XEN_PT_BAR_FLAG_MEM;
|
393 | 93d7ae8e | Allen Kay | } |
394 | 93d7ae8e | Allen Kay | |
395 | 93d7ae8e | Allen Kay | /* check BAR I/O indicator */
|
396 | 93d7ae8e | Allen Kay | if (s->real_device.io_regions[index].type & XEN_HOST_PCI_REGION_TYPE_IO) {
|
397 | 93d7ae8e | Allen Kay | return XEN_PT_BAR_FLAG_IO;
|
398 | 93d7ae8e | Allen Kay | } else {
|
399 | 93d7ae8e | Allen Kay | return XEN_PT_BAR_FLAG_MEM;
|
400 | 93d7ae8e | Allen Kay | } |
401 | 93d7ae8e | Allen Kay | } |
402 | 93d7ae8e | Allen Kay | |
403 | 93d7ae8e | Allen Kay | static inline uint32_t base_address_with_flags(XenHostPCIIORegion *hr) |
404 | 93d7ae8e | Allen Kay | { |
405 | 93d7ae8e | Allen Kay | if (hr->type & XEN_HOST_PCI_REGION_TYPE_IO) {
|
406 | 93d7ae8e | Allen Kay | return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_IO_MASK);
|
407 | 93d7ae8e | Allen Kay | } else {
|
408 | 93d7ae8e | Allen Kay | return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_MEM_MASK);
|
409 | 93d7ae8e | Allen Kay | } |
410 | 93d7ae8e | Allen Kay | } |
411 | 93d7ae8e | Allen Kay | |
412 | 93d7ae8e | Allen Kay | static int xen_pt_bar_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg, |
413 | 93d7ae8e | Allen Kay | uint32_t real_offset, uint32_t *data) |
414 | 93d7ae8e | Allen Kay | { |
415 | 93d7ae8e | Allen Kay | uint32_t reg_field = 0;
|
416 | 93d7ae8e | Allen Kay | int index;
|
417 | 93d7ae8e | Allen Kay | |
418 | 93d7ae8e | Allen Kay | index = xen_pt_bar_offset_to_index(reg->offset); |
419 | 93d7ae8e | Allen Kay | if (index < 0 || index >= PCI_NUM_REGIONS) { |
420 | 93d7ae8e | Allen Kay | XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
|
421 | 93d7ae8e | Allen Kay | return -1; |
422 | 93d7ae8e | Allen Kay | } |
423 | 93d7ae8e | Allen Kay | |
424 | 93d7ae8e | Allen Kay | /* set BAR flag */
|
425 | 93d7ae8e | Allen Kay | s->bases[index].bar_flag = xen_pt_bar_reg_parse(s, reg); |
426 | 93d7ae8e | Allen Kay | if (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED) {
|
427 | 93d7ae8e | Allen Kay | reg_field = XEN_PT_INVALID_REG; |
428 | 93d7ae8e | Allen Kay | } |
429 | 93d7ae8e | Allen Kay | |
430 | 93d7ae8e | Allen Kay | *data = reg_field; |
431 | 93d7ae8e | Allen Kay | return 0; |
432 | 93d7ae8e | Allen Kay | } |
433 | 93d7ae8e | Allen Kay | static int xen_pt_bar_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry, |
434 | 93d7ae8e | Allen Kay | uint32_t *value, uint32_t valid_mask) |
435 | 93d7ae8e | Allen Kay | { |
436 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = cfg_entry->reg; |
437 | 93d7ae8e | Allen Kay | uint32_t valid_emu_mask = 0;
|
438 | 93d7ae8e | Allen Kay | uint32_t bar_emu_mask = 0;
|
439 | 93d7ae8e | Allen Kay | int index;
|
440 | 93d7ae8e | Allen Kay | |
441 | 93d7ae8e | Allen Kay | /* get BAR index */
|
442 | 93d7ae8e | Allen Kay | index = xen_pt_bar_offset_to_index(reg->offset); |
443 | 93d7ae8e | Allen Kay | if (index < 0 || index >= PCI_NUM_REGIONS) { |
444 | 93d7ae8e | Allen Kay | XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
|
445 | 93d7ae8e | Allen Kay | return -1; |
446 | 93d7ae8e | Allen Kay | } |
447 | 93d7ae8e | Allen Kay | |
448 | 93d7ae8e | Allen Kay | /* use fixed-up value from kernel sysfs */
|
449 | 93d7ae8e | Allen Kay | *value = base_address_with_flags(&s->real_device.io_regions[index]); |
450 | 93d7ae8e | Allen Kay | |
451 | 93d7ae8e | Allen Kay | /* set emulate mask depend on BAR flag */
|
452 | 93d7ae8e | Allen Kay | switch (s->bases[index].bar_flag) {
|
453 | 93d7ae8e | Allen Kay | case XEN_PT_BAR_FLAG_MEM:
|
454 | 93d7ae8e | Allen Kay | bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK; |
455 | 93d7ae8e | Allen Kay | break;
|
456 | 93d7ae8e | Allen Kay | case XEN_PT_BAR_FLAG_IO:
|
457 | 93d7ae8e | Allen Kay | bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK; |
458 | 93d7ae8e | Allen Kay | break;
|
459 | 93d7ae8e | Allen Kay | case XEN_PT_BAR_FLAG_UPPER:
|
460 | 93d7ae8e | Allen Kay | bar_emu_mask = XEN_PT_BAR_ALLF; |
461 | 93d7ae8e | Allen Kay | break;
|
462 | 93d7ae8e | Allen Kay | default:
|
463 | 93d7ae8e | Allen Kay | break;
|
464 | 93d7ae8e | Allen Kay | } |
465 | 93d7ae8e | Allen Kay | |
466 | 93d7ae8e | Allen Kay | /* emulate BAR */
|
467 | 93d7ae8e | Allen Kay | valid_emu_mask = bar_emu_mask & valid_mask; |
468 | 93d7ae8e | Allen Kay | *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask); |
469 | 93d7ae8e | Allen Kay | |
470 | 93d7ae8e | Allen Kay | return 0; |
471 | 93d7ae8e | Allen Kay | } |
472 | 93d7ae8e | Allen Kay | static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, |
473 | 93d7ae8e | Allen Kay | uint32_t *val, uint32_t dev_value, |
474 | 93d7ae8e | Allen Kay | uint32_t valid_mask) |
475 | 93d7ae8e | Allen Kay | { |
476 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = cfg_entry->reg; |
477 | 93d7ae8e | Allen Kay | XenPTRegion *base = NULL;
|
478 | 93d7ae8e | Allen Kay | PCIDevice *d = &s->dev; |
479 | 93d7ae8e | Allen Kay | const PCIIORegion *r;
|
480 | 93d7ae8e | Allen Kay | uint32_t writable_mask = 0;
|
481 | 93d7ae8e | Allen Kay | uint32_t throughable_mask = 0;
|
482 | 93d7ae8e | Allen Kay | uint32_t bar_emu_mask = 0;
|
483 | 93d7ae8e | Allen Kay | uint32_t bar_ro_mask = 0;
|
484 | 93d7ae8e | Allen Kay | uint32_t r_size = 0;
|
485 | 93d7ae8e | Allen Kay | int index = 0; |
486 | 93d7ae8e | Allen Kay | |
487 | 93d7ae8e | Allen Kay | index = xen_pt_bar_offset_to_index(reg->offset); |
488 | 93d7ae8e | Allen Kay | if (index < 0 || index >= PCI_NUM_REGIONS) { |
489 | 93d7ae8e | Allen Kay | XEN_PT_ERR(d, "Internal error: Invalid BAR index [%d].\n", index);
|
490 | 93d7ae8e | Allen Kay | return -1; |
491 | 93d7ae8e | Allen Kay | } |
492 | 93d7ae8e | Allen Kay | |
493 | 93d7ae8e | Allen Kay | r = &d->io_regions[index]; |
494 | 93d7ae8e | Allen Kay | base = &s->bases[index]; |
495 | 93d7ae8e | Allen Kay | r_size = xen_pt_get_emul_size(base->bar_flag, r->size); |
496 | 93d7ae8e | Allen Kay | |
497 | 93d7ae8e | Allen Kay | /* set emulate mask and read-only mask values depend on the BAR flag */
|
498 | 93d7ae8e | Allen Kay | switch (s->bases[index].bar_flag) {
|
499 | 93d7ae8e | Allen Kay | case XEN_PT_BAR_FLAG_MEM:
|
500 | 93d7ae8e | Allen Kay | bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK; |
501 | aabc8530 | Xudong Hao | if (!r_size) {
|
502 | aabc8530 | Xudong Hao | /* low 32 bits mask for 64 bit bars */
|
503 | aabc8530 | Xudong Hao | bar_ro_mask = XEN_PT_BAR_ALLF; |
504 | aabc8530 | Xudong Hao | } else {
|
505 | aabc8530 | Xudong Hao | bar_ro_mask = XEN_PT_BAR_MEM_RO_MASK | (r_size - 1);
|
506 | aabc8530 | Xudong Hao | } |
507 | 93d7ae8e | Allen Kay | break;
|
508 | 93d7ae8e | Allen Kay | case XEN_PT_BAR_FLAG_IO:
|
509 | 93d7ae8e | Allen Kay | bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK; |
510 | 93d7ae8e | Allen Kay | bar_ro_mask = XEN_PT_BAR_IO_RO_MASK | (r_size - 1);
|
511 | 93d7ae8e | Allen Kay | break;
|
512 | 93d7ae8e | Allen Kay | case XEN_PT_BAR_FLAG_UPPER:
|
513 | 93d7ae8e | Allen Kay | bar_emu_mask = XEN_PT_BAR_ALLF; |
514 | aabc8530 | Xudong Hao | bar_ro_mask = r_size ? r_size - 1 : 0; |
515 | 93d7ae8e | Allen Kay | break;
|
516 | 93d7ae8e | Allen Kay | default:
|
517 | 93d7ae8e | Allen Kay | break;
|
518 | 93d7ae8e | Allen Kay | } |
519 | 93d7ae8e | Allen Kay | |
520 | 93d7ae8e | Allen Kay | /* modify emulate register */
|
521 | 93d7ae8e | Allen Kay | writable_mask = bar_emu_mask & ~bar_ro_mask & valid_mask; |
522 | 93d7ae8e | Allen Kay | cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); |
523 | 93d7ae8e | Allen Kay | |
524 | 93d7ae8e | Allen Kay | /* check whether we need to update the virtual region address or not */
|
525 | 93d7ae8e | Allen Kay | switch (s->bases[index].bar_flag) {
|
526 | aabc8530 | Xudong Hao | case XEN_PT_BAR_FLAG_UPPER:
|
527 | 93d7ae8e | Allen Kay | case XEN_PT_BAR_FLAG_MEM:
|
528 | 93d7ae8e | Allen Kay | /* nothing to do */
|
529 | 93d7ae8e | Allen Kay | break;
|
530 | 93d7ae8e | Allen Kay | case XEN_PT_BAR_FLAG_IO:
|
531 | 93d7ae8e | Allen Kay | /* nothing to do */
|
532 | 93d7ae8e | Allen Kay | break;
|
533 | 93d7ae8e | Allen Kay | default:
|
534 | 93d7ae8e | Allen Kay | break;
|
535 | 93d7ae8e | Allen Kay | } |
536 | 93d7ae8e | Allen Kay | |
537 | 93d7ae8e | Allen Kay | /* create value for writing to I/O device register */
|
538 | 93d7ae8e | Allen Kay | throughable_mask = ~bar_emu_mask & valid_mask; |
539 | 93d7ae8e | Allen Kay | *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); |
540 | 93d7ae8e | Allen Kay | |
541 | 93d7ae8e | Allen Kay | return 0; |
542 | 93d7ae8e | Allen Kay | } |
543 | 93d7ae8e | Allen Kay | |
544 | 93d7ae8e | Allen Kay | /* write Exp ROM BAR */
|
545 | 93d7ae8e | Allen Kay | static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s, |
546 | 93d7ae8e | Allen Kay | XenPTReg *cfg_entry, uint32_t *val, |
547 | 93d7ae8e | Allen Kay | uint32_t dev_value, uint32_t valid_mask) |
548 | 93d7ae8e | Allen Kay | { |
549 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = cfg_entry->reg; |
550 | 93d7ae8e | Allen Kay | XenPTRegion *base = NULL;
|
551 | 93d7ae8e | Allen Kay | PCIDevice *d = (PCIDevice *)&s->dev; |
552 | 93d7ae8e | Allen Kay | uint32_t writable_mask = 0;
|
553 | 93d7ae8e | Allen Kay | uint32_t throughable_mask = 0;
|
554 | 93d7ae8e | Allen Kay | pcibus_t r_size = 0;
|
555 | 93d7ae8e | Allen Kay | uint32_t bar_emu_mask = 0;
|
556 | 93d7ae8e | Allen Kay | uint32_t bar_ro_mask = 0;
|
557 | 93d7ae8e | Allen Kay | |
558 | 93d7ae8e | Allen Kay | r_size = d->io_regions[PCI_ROM_SLOT].size; |
559 | 93d7ae8e | Allen Kay | base = &s->bases[PCI_ROM_SLOT]; |
560 | 93d7ae8e | Allen Kay | /* align memory type resource size */
|
561 | 93d7ae8e | Allen Kay | r_size = xen_pt_get_emul_size(base->bar_flag, r_size); |
562 | 93d7ae8e | Allen Kay | |
563 | 93d7ae8e | Allen Kay | /* set emulate mask and read-only mask */
|
564 | 93d7ae8e | Allen Kay | bar_emu_mask = reg->emu_mask; |
565 | 93d7ae8e | Allen Kay | bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
|
566 | 93d7ae8e | Allen Kay | |
567 | 93d7ae8e | Allen Kay | /* modify emulate register */
|
568 | 93d7ae8e | Allen Kay | writable_mask = ~bar_ro_mask & valid_mask; |
569 | 93d7ae8e | Allen Kay | cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); |
570 | 93d7ae8e | Allen Kay | |
571 | 93d7ae8e | Allen Kay | /* create value for writing to I/O device register */
|
572 | 93d7ae8e | Allen Kay | throughable_mask = ~bar_emu_mask & valid_mask; |
573 | 93d7ae8e | Allen Kay | *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); |
574 | 93d7ae8e | Allen Kay | |
575 | 93d7ae8e | Allen Kay | return 0; |
576 | 93d7ae8e | Allen Kay | } |
577 | 93d7ae8e | Allen Kay | |
578 | 0546b8c2 | Stefan Weil | /* Header Type0 reg static information table */
|
579 | 93d7ae8e | Allen Kay | static XenPTRegInfo xen_pt_emu_reg_header0[] = {
|
580 | 93d7ae8e | Allen Kay | /* Vendor ID reg */
|
581 | 93d7ae8e | Allen Kay | { |
582 | 93d7ae8e | Allen Kay | .offset = PCI_VENDOR_ID, |
583 | 93d7ae8e | Allen Kay | .size = 2,
|
584 | 93d7ae8e | Allen Kay | .init_val = 0x0000,
|
585 | 93d7ae8e | Allen Kay | .ro_mask = 0xFFFF,
|
586 | 93d7ae8e | Allen Kay | .emu_mask = 0xFFFF,
|
587 | 93d7ae8e | Allen Kay | .init = xen_pt_vendor_reg_init, |
588 | 93d7ae8e | Allen Kay | .u.w.read = xen_pt_word_reg_read, |
589 | 93d7ae8e | Allen Kay | .u.w.write = xen_pt_word_reg_write, |
590 | 93d7ae8e | Allen Kay | }, |
591 | 93d7ae8e | Allen Kay | /* Device ID reg */
|
592 | 93d7ae8e | Allen Kay | { |
593 | 93d7ae8e | Allen Kay | .offset = PCI_DEVICE_ID, |
594 | 93d7ae8e | Allen Kay | .size = 2,
|
595 | 93d7ae8e | Allen Kay | .init_val = 0x0000,
|
596 | 93d7ae8e | Allen Kay | .ro_mask = 0xFFFF,
|
597 | 93d7ae8e | Allen Kay | .emu_mask = 0xFFFF,
|
598 | 93d7ae8e | Allen Kay | .init = xen_pt_device_reg_init, |
599 | 93d7ae8e | Allen Kay | .u.w.read = xen_pt_word_reg_read, |
600 | 93d7ae8e | Allen Kay | .u.w.write = xen_pt_word_reg_write, |
601 | 93d7ae8e | Allen Kay | }, |
602 | 93d7ae8e | Allen Kay | /* Command reg */
|
603 | 93d7ae8e | Allen Kay | { |
604 | 93d7ae8e | Allen Kay | .offset = PCI_COMMAND, |
605 | 93d7ae8e | Allen Kay | .size = 2,
|
606 | 93d7ae8e | Allen Kay | .init_val = 0x0000,
|
607 | 93d7ae8e | Allen Kay | .ro_mask = 0xF880,
|
608 | 93d7ae8e | Allen Kay | .emu_mask = 0x0740,
|
609 | 93d7ae8e | Allen Kay | .init = xen_pt_common_reg_init, |
610 | 93d7ae8e | Allen Kay | .u.w.read = xen_pt_cmd_reg_read, |
611 | 93d7ae8e | Allen Kay | .u.w.write = xen_pt_cmd_reg_write, |
612 | 93d7ae8e | Allen Kay | }, |
613 | 93d7ae8e | Allen Kay | /* Capabilities Pointer reg */
|
614 | 93d7ae8e | Allen Kay | { |
615 | 93d7ae8e | Allen Kay | .offset = PCI_CAPABILITY_LIST, |
616 | 93d7ae8e | Allen Kay | .size = 1,
|
617 | 93d7ae8e | Allen Kay | .init_val = 0x00,
|
618 | 93d7ae8e | Allen Kay | .ro_mask = 0xFF,
|
619 | 93d7ae8e | Allen Kay | .emu_mask = 0xFF,
|
620 | 93d7ae8e | Allen Kay | .init = xen_pt_ptr_reg_init, |
621 | 93d7ae8e | Allen Kay | .u.b.read = xen_pt_byte_reg_read, |
622 | 93d7ae8e | Allen Kay | .u.b.write = xen_pt_byte_reg_write, |
623 | 93d7ae8e | Allen Kay | }, |
624 | 93d7ae8e | Allen Kay | /* Status reg */
|
625 | 93d7ae8e | Allen Kay | /* use emulated Cap Ptr value to initialize,
|
626 | 93d7ae8e | Allen Kay | * so need to be declared after Cap Ptr reg
|
627 | 93d7ae8e | Allen Kay | */
|
628 | 93d7ae8e | Allen Kay | { |
629 | 93d7ae8e | Allen Kay | .offset = PCI_STATUS, |
630 | 93d7ae8e | Allen Kay | .size = 2,
|
631 | 93d7ae8e | Allen Kay | .init_val = 0x0000,
|
632 | 93d7ae8e | Allen Kay | .ro_mask = 0x06FF,
|
633 | 93d7ae8e | Allen Kay | .emu_mask = 0x0010,
|
634 | 93d7ae8e | Allen Kay | .init = xen_pt_status_reg_init, |
635 | 93d7ae8e | Allen Kay | .u.w.read = xen_pt_word_reg_read, |
636 | 93d7ae8e | Allen Kay | .u.w.write = xen_pt_word_reg_write, |
637 | 93d7ae8e | Allen Kay | }, |
638 | 93d7ae8e | Allen Kay | /* Cache Line Size reg */
|
639 | 93d7ae8e | Allen Kay | { |
640 | 93d7ae8e | Allen Kay | .offset = PCI_CACHE_LINE_SIZE, |
641 | 93d7ae8e | Allen Kay | .size = 1,
|
642 | 93d7ae8e | Allen Kay | .init_val = 0x00,
|
643 | 93d7ae8e | Allen Kay | .ro_mask = 0x00,
|
644 | 93d7ae8e | Allen Kay | .emu_mask = 0xFF,
|
645 | 93d7ae8e | Allen Kay | .init = xen_pt_common_reg_init, |
646 | 93d7ae8e | Allen Kay | .u.b.read = xen_pt_byte_reg_read, |
647 | 93d7ae8e | Allen Kay | .u.b.write = xen_pt_byte_reg_write, |
648 | 93d7ae8e | Allen Kay | }, |
649 | 93d7ae8e | Allen Kay | /* Latency Timer reg */
|
650 | 93d7ae8e | Allen Kay | { |
651 | 93d7ae8e | Allen Kay | .offset = PCI_LATENCY_TIMER, |
652 | 93d7ae8e | Allen Kay | .size = 1,
|
653 | 93d7ae8e | Allen Kay | .init_val = 0x00,
|
654 | 93d7ae8e | Allen Kay | .ro_mask = 0x00,
|
655 | 93d7ae8e | Allen Kay | .emu_mask = 0xFF,
|
656 | 93d7ae8e | Allen Kay | .init = xen_pt_common_reg_init, |
657 | 93d7ae8e | Allen Kay | .u.b.read = xen_pt_byte_reg_read, |
658 | 93d7ae8e | Allen Kay | .u.b.write = xen_pt_byte_reg_write, |
659 | 93d7ae8e | Allen Kay | }, |
660 | 93d7ae8e | Allen Kay | /* Header Type reg */
|
661 | 93d7ae8e | Allen Kay | { |
662 | 93d7ae8e | Allen Kay | .offset = PCI_HEADER_TYPE, |
663 | 93d7ae8e | Allen Kay | .size = 1,
|
664 | 93d7ae8e | Allen Kay | .init_val = 0x00,
|
665 | 93d7ae8e | Allen Kay | .ro_mask = 0xFF,
|
666 | 93d7ae8e | Allen Kay | .emu_mask = 0x00,
|
667 | 93d7ae8e | Allen Kay | .init = xen_pt_header_type_reg_init, |
668 | 93d7ae8e | Allen Kay | .u.b.read = xen_pt_byte_reg_read, |
669 | 93d7ae8e | Allen Kay | .u.b.write = xen_pt_byte_reg_write, |
670 | 93d7ae8e | Allen Kay | }, |
671 | 93d7ae8e | Allen Kay | /* Interrupt Line reg */
|
672 | 93d7ae8e | Allen Kay | { |
673 | 93d7ae8e | Allen Kay | .offset = PCI_INTERRUPT_LINE, |
674 | 93d7ae8e | Allen Kay | .size = 1,
|
675 | 93d7ae8e | Allen Kay | .init_val = 0x00,
|
676 | 93d7ae8e | Allen Kay | .ro_mask = 0x00,
|
677 | 93d7ae8e | Allen Kay | .emu_mask = 0xFF,
|
678 | 93d7ae8e | Allen Kay | .init = xen_pt_common_reg_init, |
679 | 93d7ae8e | Allen Kay | .u.b.read = xen_pt_byte_reg_read, |
680 | 93d7ae8e | Allen Kay | .u.b.write = xen_pt_byte_reg_write, |
681 | 93d7ae8e | Allen Kay | }, |
682 | 93d7ae8e | Allen Kay | /* Interrupt Pin reg */
|
683 | 93d7ae8e | Allen Kay | { |
684 | 93d7ae8e | Allen Kay | .offset = PCI_INTERRUPT_PIN, |
685 | 93d7ae8e | Allen Kay | .size = 1,
|
686 | 93d7ae8e | Allen Kay | .init_val = 0x00,
|
687 | 93d7ae8e | Allen Kay | .ro_mask = 0xFF,
|
688 | 93d7ae8e | Allen Kay | .emu_mask = 0xFF,
|
689 | 93d7ae8e | Allen Kay | .init = xen_pt_irqpin_reg_init, |
690 | 93d7ae8e | Allen Kay | .u.b.read = xen_pt_byte_reg_read, |
691 | 93d7ae8e | Allen Kay | .u.b.write = xen_pt_byte_reg_write, |
692 | 93d7ae8e | Allen Kay | }, |
693 | 93d7ae8e | Allen Kay | /* BAR 0 reg */
|
694 | 93d7ae8e | Allen Kay | /* mask of BAR need to be decided later, depends on IO/MEM type */
|
695 | 93d7ae8e | Allen Kay | { |
696 | 93d7ae8e | Allen Kay | .offset = PCI_BASE_ADDRESS_0, |
697 | 93d7ae8e | Allen Kay | .size = 4,
|
698 | 93d7ae8e | Allen Kay | .init_val = 0x00000000,
|
699 | 93d7ae8e | Allen Kay | .init = xen_pt_bar_reg_init, |
700 | 93d7ae8e | Allen Kay | .u.dw.read = xen_pt_bar_reg_read, |
701 | 93d7ae8e | Allen Kay | .u.dw.write = xen_pt_bar_reg_write, |
702 | 93d7ae8e | Allen Kay | }, |
703 | 93d7ae8e | Allen Kay | /* BAR 1 reg */
|
704 | 93d7ae8e | Allen Kay | { |
705 | 93d7ae8e | Allen Kay | .offset = PCI_BASE_ADDRESS_1, |
706 | 93d7ae8e | Allen Kay | .size = 4,
|
707 | 93d7ae8e | Allen Kay | .init_val = 0x00000000,
|
708 | 93d7ae8e | Allen Kay | .init = xen_pt_bar_reg_init, |
709 | 93d7ae8e | Allen Kay | .u.dw.read = xen_pt_bar_reg_read, |
710 | 93d7ae8e | Allen Kay | .u.dw.write = xen_pt_bar_reg_write, |
711 | 93d7ae8e | Allen Kay | }, |
712 | 93d7ae8e | Allen Kay | /* BAR 2 reg */
|
713 | 93d7ae8e | Allen Kay | { |
714 | 93d7ae8e | Allen Kay | .offset = PCI_BASE_ADDRESS_2, |
715 | 93d7ae8e | Allen Kay | .size = 4,
|
716 | 93d7ae8e | Allen Kay | .init_val = 0x00000000,
|
717 | 93d7ae8e | Allen Kay | .init = xen_pt_bar_reg_init, |
718 | 93d7ae8e | Allen Kay | .u.dw.read = xen_pt_bar_reg_read, |
719 | 93d7ae8e | Allen Kay | .u.dw.write = xen_pt_bar_reg_write, |
720 | 93d7ae8e | Allen Kay | }, |
721 | 93d7ae8e | Allen Kay | /* BAR 3 reg */
|
722 | 93d7ae8e | Allen Kay | { |
723 | 93d7ae8e | Allen Kay | .offset = PCI_BASE_ADDRESS_3, |
724 | 93d7ae8e | Allen Kay | .size = 4,
|
725 | 93d7ae8e | Allen Kay | .init_val = 0x00000000,
|
726 | 93d7ae8e | Allen Kay | .init = xen_pt_bar_reg_init, |
727 | 93d7ae8e | Allen Kay | .u.dw.read = xen_pt_bar_reg_read, |
728 | 93d7ae8e | Allen Kay | .u.dw.write = xen_pt_bar_reg_write, |
729 | 93d7ae8e | Allen Kay | }, |
730 | 93d7ae8e | Allen Kay | /* BAR 4 reg */
|
731 | 93d7ae8e | Allen Kay | { |
732 | 93d7ae8e | Allen Kay | .offset = PCI_BASE_ADDRESS_4, |
733 | 93d7ae8e | Allen Kay | .size = 4,
|
734 | 93d7ae8e | Allen Kay | .init_val = 0x00000000,
|
735 | 93d7ae8e | Allen Kay | .init = xen_pt_bar_reg_init, |
736 | 93d7ae8e | Allen Kay | .u.dw.read = xen_pt_bar_reg_read, |
737 | 93d7ae8e | Allen Kay | .u.dw.write = xen_pt_bar_reg_write, |
738 | 93d7ae8e | Allen Kay | }, |
739 | 93d7ae8e | Allen Kay | /* BAR 5 reg */
|
740 | 93d7ae8e | Allen Kay | { |
741 | 93d7ae8e | Allen Kay | .offset = PCI_BASE_ADDRESS_5, |
742 | 93d7ae8e | Allen Kay | .size = 4,
|
743 | 93d7ae8e | Allen Kay | .init_val = 0x00000000,
|
744 | 93d7ae8e | Allen Kay | .init = xen_pt_bar_reg_init, |
745 | 93d7ae8e | Allen Kay | .u.dw.read = xen_pt_bar_reg_read, |
746 | 93d7ae8e | Allen Kay | .u.dw.write = xen_pt_bar_reg_write, |
747 | 93d7ae8e | Allen Kay | }, |
748 | 93d7ae8e | Allen Kay | /* Expansion ROM BAR reg */
|
749 | 93d7ae8e | Allen Kay | { |
750 | 93d7ae8e | Allen Kay | .offset = PCI_ROM_ADDRESS, |
751 | 93d7ae8e | Allen Kay | .size = 4,
|
752 | 93d7ae8e | Allen Kay | .init_val = 0x00000000,
|
753 | 93d7ae8e | Allen Kay | .ro_mask = 0x000007FE,
|
754 | 93d7ae8e | Allen Kay | .emu_mask = 0xFFFFF800,
|
755 | 93d7ae8e | Allen Kay | .init = xen_pt_bar_reg_init, |
756 | 93d7ae8e | Allen Kay | .u.dw.read = xen_pt_long_reg_read, |
757 | 93d7ae8e | Allen Kay | .u.dw.write = xen_pt_exp_rom_bar_reg_write, |
758 | 93d7ae8e | Allen Kay | }, |
759 | 93d7ae8e | Allen Kay | { |
760 | 93d7ae8e | Allen Kay | .size = 0,
|
761 | 93d7ae8e | Allen Kay | }, |
762 | 93d7ae8e | Allen Kay | }; |
763 | 93d7ae8e | Allen Kay | |
764 | 93d7ae8e | Allen Kay | |
765 | 93d7ae8e | Allen Kay | /*********************************
|
766 | 93d7ae8e | Allen Kay | * Vital Product Data Capability
|
767 | 93d7ae8e | Allen Kay | */
|
768 | 93d7ae8e | Allen Kay | |
769 | 0546b8c2 | Stefan Weil | /* Vital Product Data Capability Structure reg static information table */
|
770 | 93d7ae8e | Allen Kay | static XenPTRegInfo xen_pt_emu_reg_vpd[] = {
|
771 | 93d7ae8e | Allen Kay | { |
772 | 93d7ae8e | Allen Kay | .offset = PCI_CAP_LIST_NEXT, |
773 | 93d7ae8e | Allen Kay | .size = 1,
|
774 | 93d7ae8e | Allen Kay | .init_val = 0x00,
|
775 | 93d7ae8e | Allen Kay | .ro_mask = 0xFF,
|
776 | 93d7ae8e | Allen Kay | .emu_mask = 0xFF,
|
777 | 93d7ae8e | Allen Kay | .init = xen_pt_ptr_reg_init, |
778 | 93d7ae8e | Allen Kay | .u.b.read = xen_pt_byte_reg_read, |
779 | 93d7ae8e | Allen Kay | .u.b.write = xen_pt_byte_reg_write, |
780 | 93d7ae8e | Allen Kay | }, |
781 | 93d7ae8e | Allen Kay | { |
782 | 93d7ae8e | Allen Kay | .size = 0,
|
783 | 93d7ae8e | Allen Kay | }, |
784 | 93d7ae8e | Allen Kay | }; |
785 | 93d7ae8e | Allen Kay | |
786 | 93d7ae8e | Allen Kay | |
787 | 93d7ae8e | Allen Kay | /**************************************
|
788 | 93d7ae8e | Allen Kay | * Vendor Specific Capability
|
789 | 93d7ae8e | Allen Kay | */
|
790 | 93d7ae8e | Allen Kay | |
791 | 0546b8c2 | Stefan Weil | /* Vendor Specific Capability Structure reg static information table */
|
792 | 93d7ae8e | Allen Kay | static XenPTRegInfo xen_pt_emu_reg_vendor[] = {
|
793 | 93d7ae8e | Allen Kay | { |
794 | 93d7ae8e | Allen Kay | .offset = PCI_CAP_LIST_NEXT, |
795 | 93d7ae8e | Allen Kay | .size = 1,
|
796 | 93d7ae8e | Allen Kay | .init_val = 0x00,
|
797 | 93d7ae8e | Allen Kay | .ro_mask = 0xFF,
|
798 | 93d7ae8e | Allen Kay | .emu_mask = 0xFF,
|
799 | 93d7ae8e | Allen Kay | .init = xen_pt_ptr_reg_init, |
800 | 93d7ae8e | Allen Kay | .u.b.read = xen_pt_byte_reg_read, |
801 | 93d7ae8e | Allen Kay | .u.b.write = xen_pt_byte_reg_write, |
802 | 93d7ae8e | Allen Kay | }, |
803 | 93d7ae8e | Allen Kay | { |
804 | 93d7ae8e | Allen Kay | .size = 0,
|
805 | 93d7ae8e | Allen Kay | }, |
806 | 93d7ae8e | Allen Kay | }; |
807 | 93d7ae8e | Allen Kay | |
808 | 93d7ae8e | Allen Kay | |
809 | 93d7ae8e | Allen Kay | /*****************************
|
810 | 93d7ae8e | Allen Kay | * PCI Express Capability
|
811 | 93d7ae8e | Allen Kay | */
|
812 | 93d7ae8e | Allen Kay | |
813 | 93d7ae8e | Allen Kay | static inline uint8_t get_capability_version(XenPCIPassthroughState *s, |
814 | 93d7ae8e | Allen Kay | uint32_t offset) |
815 | 93d7ae8e | Allen Kay | { |
816 | 93d7ae8e | Allen Kay | uint8_t flags = pci_get_byte(s->dev.config + offset + PCI_EXP_FLAGS); |
817 | 93d7ae8e | Allen Kay | return flags & PCI_EXP_FLAGS_VERS;
|
818 | 93d7ae8e | Allen Kay | } |
819 | 93d7ae8e | Allen Kay | |
820 | 93d7ae8e | Allen Kay | static inline uint8_t get_device_type(XenPCIPassthroughState *s, |
821 | 93d7ae8e | Allen Kay | uint32_t offset) |
822 | 93d7ae8e | Allen Kay | { |
823 | 93d7ae8e | Allen Kay | uint8_t flags = pci_get_byte(s->dev.config + offset + PCI_EXP_FLAGS); |
824 | 93d7ae8e | Allen Kay | return (flags & PCI_EXP_FLAGS_TYPE) >> 4; |
825 | 93d7ae8e | Allen Kay | } |
826 | 93d7ae8e | Allen Kay | |
827 | 93d7ae8e | Allen Kay | /* initialize Link Control register */
|
828 | 93d7ae8e | Allen Kay | static int xen_pt_linkctrl_reg_init(XenPCIPassthroughState *s, |
829 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg, uint32_t real_offset, |
830 | 93d7ae8e | Allen Kay | uint32_t *data) |
831 | 93d7ae8e | Allen Kay | { |
832 | 93d7ae8e | Allen Kay | uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset); |
833 | 93d7ae8e | Allen Kay | uint8_t dev_type = get_device_type(s, real_offset - reg->offset); |
834 | 93d7ae8e | Allen Kay | |
835 | 93d7ae8e | Allen Kay | /* no need to initialize in case of Root Complex Integrated Endpoint
|
836 | 93d7ae8e | Allen Kay | * with cap_ver 1.x
|
837 | 93d7ae8e | Allen Kay | */
|
838 | 93d7ae8e | Allen Kay | if ((dev_type == PCI_EXP_TYPE_RC_END) && (cap_ver == 1)) { |
839 | 93d7ae8e | Allen Kay | *data = XEN_PT_INVALID_REG; |
840 | 93d7ae8e | Allen Kay | } |
841 | 93d7ae8e | Allen Kay | |
842 | 93d7ae8e | Allen Kay | *data = reg->init_val; |
843 | 93d7ae8e | Allen Kay | return 0; |
844 | 93d7ae8e | Allen Kay | } |
845 | 93d7ae8e | Allen Kay | /* initialize Device Control 2 register */
|
846 | 93d7ae8e | Allen Kay | static int xen_pt_devctrl2_reg_init(XenPCIPassthroughState *s, |
847 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg, uint32_t real_offset, |
848 | 93d7ae8e | Allen Kay | uint32_t *data) |
849 | 93d7ae8e | Allen Kay | { |
850 | 93d7ae8e | Allen Kay | uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset); |
851 | 93d7ae8e | Allen Kay | |
852 | 93d7ae8e | Allen Kay | /* no need to initialize in case of cap_ver 1.x */
|
853 | 93d7ae8e | Allen Kay | if (cap_ver == 1) { |
854 | 93d7ae8e | Allen Kay | *data = XEN_PT_INVALID_REG; |
855 | 93d7ae8e | Allen Kay | } |
856 | 93d7ae8e | Allen Kay | |
857 | 93d7ae8e | Allen Kay | *data = reg->init_val; |
858 | 93d7ae8e | Allen Kay | return 0; |
859 | 93d7ae8e | Allen Kay | } |
860 | 93d7ae8e | Allen Kay | /* initialize Link Control 2 register */
|
861 | 93d7ae8e | Allen Kay | static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s, |
862 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg, uint32_t real_offset, |
863 | 93d7ae8e | Allen Kay | uint32_t *data) |
864 | 93d7ae8e | Allen Kay | { |
865 | 93d7ae8e | Allen Kay | uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset); |
866 | 93d7ae8e | Allen Kay | uint32_t reg_field = 0;
|
867 | 93d7ae8e | Allen Kay | |
868 | 93d7ae8e | Allen Kay | /* no need to initialize in case of cap_ver 1.x */
|
869 | 93d7ae8e | Allen Kay | if (cap_ver == 1) { |
870 | 93d7ae8e | Allen Kay | reg_field = XEN_PT_INVALID_REG; |
871 | 93d7ae8e | Allen Kay | } else {
|
872 | 93d7ae8e | Allen Kay | /* set Supported Link Speed */
|
873 | 93d7ae8e | Allen Kay | uint8_t lnkcap = pci_get_byte(s->dev.config + real_offset - reg->offset |
874 | 93d7ae8e | Allen Kay | + PCI_EXP_LNKCAP); |
875 | 93d7ae8e | Allen Kay | reg_field |= PCI_EXP_LNKCAP_SLS & lnkcap; |
876 | 93d7ae8e | Allen Kay | } |
877 | 93d7ae8e | Allen Kay | |
878 | 93d7ae8e | Allen Kay | *data = reg_field; |
879 | 93d7ae8e | Allen Kay | return 0; |
880 | 93d7ae8e | Allen Kay | } |
881 | 93d7ae8e | Allen Kay | |
882 | 0546b8c2 | Stefan Weil | /* PCI Express Capability Structure reg static information table */
|
883 | 93d7ae8e | Allen Kay | static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
|
884 | 93d7ae8e | Allen Kay | /* Next Pointer reg */
|
885 | 93d7ae8e | Allen Kay | { |
886 | 93d7ae8e | Allen Kay | .offset = PCI_CAP_LIST_NEXT, |
887 | 93d7ae8e | Allen Kay | .size = 1,
|
888 | 93d7ae8e | Allen Kay | .init_val = 0x00,
|
889 | 93d7ae8e | Allen Kay | .ro_mask = 0xFF,
|
890 | 93d7ae8e | Allen Kay | .emu_mask = 0xFF,
|
891 | 93d7ae8e | Allen Kay | .init = xen_pt_ptr_reg_init, |
892 | 93d7ae8e | Allen Kay | .u.b.read = xen_pt_byte_reg_read, |
893 | 93d7ae8e | Allen Kay | .u.b.write = xen_pt_byte_reg_write, |
894 | 93d7ae8e | Allen Kay | }, |
895 | 93d7ae8e | Allen Kay | /* Device Capabilities reg */
|
896 | 93d7ae8e | Allen Kay | { |
897 | 93d7ae8e | Allen Kay | .offset = PCI_EXP_DEVCAP, |
898 | 93d7ae8e | Allen Kay | .size = 4,
|
899 | 93d7ae8e | Allen Kay | .init_val = 0x00000000,
|
900 | 93d7ae8e | Allen Kay | .ro_mask = 0x1FFCFFFF,
|
901 | 93d7ae8e | Allen Kay | .emu_mask = 0x10000000,
|
902 | 93d7ae8e | Allen Kay | .init = xen_pt_common_reg_init, |
903 | 93d7ae8e | Allen Kay | .u.dw.read = xen_pt_long_reg_read, |
904 | 93d7ae8e | Allen Kay | .u.dw.write = xen_pt_long_reg_write, |
905 | 93d7ae8e | Allen Kay | }, |
906 | 93d7ae8e | Allen Kay | /* Device Control reg */
|
907 | 93d7ae8e | Allen Kay | { |
908 | 93d7ae8e | Allen Kay | .offset = PCI_EXP_DEVCTL, |
909 | 93d7ae8e | Allen Kay | .size = 2,
|
910 | 93d7ae8e | Allen Kay | .init_val = 0x2810,
|
911 | 93d7ae8e | Allen Kay | .ro_mask = 0x8400,
|
912 | 93d7ae8e | Allen Kay | .emu_mask = 0xFFFF,
|
913 | 93d7ae8e | Allen Kay | .init = xen_pt_common_reg_init, |
914 | 93d7ae8e | Allen Kay | .u.w.read = xen_pt_word_reg_read, |
915 | 93d7ae8e | Allen Kay | .u.w.write = xen_pt_word_reg_write, |
916 | 93d7ae8e | Allen Kay | }, |
917 | 93d7ae8e | Allen Kay | /* Link Control reg */
|
918 | 93d7ae8e | Allen Kay | { |
919 | 93d7ae8e | Allen Kay | .offset = PCI_EXP_LNKCTL, |
920 | 93d7ae8e | Allen Kay | .size = 2,
|
921 | 93d7ae8e | Allen Kay | .init_val = 0x0000,
|
922 | 93d7ae8e | Allen Kay | .ro_mask = 0xFC34,
|
923 | 93d7ae8e | Allen Kay | .emu_mask = 0xFFFF,
|
924 | 93d7ae8e | Allen Kay | .init = xen_pt_linkctrl_reg_init, |
925 | 93d7ae8e | Allen Kay | .u.w.read = xen_pt_word_reg_read, |
926 | 93d7ae8e | Allen Kay | .u.w.write = xen_pt_word_reg_write, |
927 | 93d7ae8e | Allen Kay | }, |
928 | 93d7ae8e | Allen Kay | /* Device Control 2 reg */
|
929 | 93d7ae8e | Allen Kay | { |
930 | 93d7ae8e | Allen Kay | .offset = 0x28,
|
931 | 93d7ae8e | Allen Kay | .size = 2,
|
932 | 93d7ae8e | Allen Kay | .init_val = 0x0000,
|
933 | 93d7ae8e | Allen Kay | .ro_mask = 0xFFE0,
|
934 | 93d7ae8e | Allen Kay | .emu_mask = 0xFFFF,
|
935 | 93d7ae8e | Allen Kay | .init = xen_pt_devctrl2_reg_init, |
936 | 93d7ae8e | Allen Kay | .u.w.read = xen_pt_word_reg_read, |
937 | 93d7ae8e | Allen Kay | .u.w.write = xen_pt_word_reg_write, |
938 | 93d7ae8e | Allen Kay | }, |
939 | 93d7ae8e | Allen Kay | /* Link Control 2 reg */
|
940 | 93d7ae8e | Allen Kay | { |
941 | 93d7ae8e | Allen Kay | .offset = 0x30,
|
942 | 93d7ae8e | Allen Kay | .size = 2,
|
943 | 93d7ae8e | Allen Kay | .init_val = 0x0000,
|
944 | 93d7ae8e | Allen Kay | .ro_mask = 0xE040,
|
945 | 93d7ae8e | Allen Kay | .emu_mask = 0xFFFF,
|
946 | 93d7ae8e | Allen Kay | .init = xen_pt_linkctrl2_reg_init, |
947 | 93d7ae8e | Allen Kay | .u.w.read = xen_pt_word_reg_read, |
948 | 93d7ae8e | Allen Kay | .u.w.write = xen_pt_word_reg_write, |
949 | 93d7ae8e | Allen Kay | }, |
950 | 93d7ae8e | Allen Kay | { |
951 | 93d7ae8e | Allen Kay | .size = 0,
|
952 | 93d7ae8e | Allen Kay | }, |
953 | 93d7ae8e | Allen Kay | }; |
954 | 93d7ae8e | Allen Kay | |
955 | 93d7ae8e | Allen Kay | |
956 | 93d7ae8e | Allen Kay | /*********************************
|
957 | 93d7ae8e | Allen Kay | * Power Management Capability
|
958 | 93d7ae8e | Allen Kay | */
|
959 | 93d7ae8e | Allen Kay | |
960 | 93d7ae8e | Allen Kay | /* read Power Management Control/Status register */
|
961 | 93d7ae8e | Allen Kay | static int xen_pt_pmcsr_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry, |
962 | 93d7ae8e | Allen Kay | uint16_t *value, uint16_t valid_mask) |
963 | 93d7ae8e | Allen Kay | { |
964 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = cfg_entry->reg; |
965 | 93d7ae8e | Allen Kay | uint16_t valid_emu_mask = reg->emu_mask; |
966 | 93d7ae8e | Allen Kay | |
967 | 93d7ae8e | Allen Kay | valid_emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET; |
968 | 93d7ae8e | Allen Kay | |
969 | 93d7ae8e | Allen Kay | valid_emu_mask = valid_emu_mask & valid_mask; |
970 | 93d7ae8e | Allen Kay | *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask); |
971 | 93d7ae8e | Allen Kay | |
972 | 93d7ae8e | Allen Kay | return 0; |
973 | 93d7ae8e | Allen Kay | } |
974 | 93d7ae8e | Allen Kay | /* write Power Management Control/Status register */
|
975 | 93d7ae8e | Allen Kay | static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s, |
976 | 93d7ae8e | Allen Kay | XenPTReg *cfg_entry, uint16_t *val, |
977 | 93d7ae8e | Allen Kay | uint16_t dev_value, uint16_t valid_mask) |
978 | 93d7ae8e | Allen Kay | { |
979 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg = cfg_entry->reg; |
980 | 93d7ae8e | Allen Kay | uint16_t emu_mask = reg->emu_mask; |
981 | 93d7ae8e | Allen Kay | uint16_t writable_mask = 0;
|
982 | 93d7ae8e | Allen Kay | uint16_t throughable_mask = 0;
|
983 | 93d7ae8e | Allen Kay | |
984 | 93d7ae8e | Allen Kay | emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET; |
985 | 93d7ae8e | Allen Kay | |
986 | 93d7ae8e | Allen Kay | /* modify emulate register */
|
987 | 93d7ae8e | Allen Kay | writable_mask = emu_mask & ~reg->ro_mask & valid_mask; |
988 | 93d7ae8e | Allen Kay | cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); |
989 | 93d7ae8e | Allen Kay | |
990 | 93d7ae8e | Allen Kay | /* create value for writing to I/O device register */
|
991 | 93d7ae8e | Allen Kay | throughable_mask = ~emu_mask & valid_mask; |
992 | 93d7ae8e | Allen Kay | *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); |
993 | 93d7ae8e | Allen Kay | |
994 | 93d7ae8e | Allen Kay | return 0; |
995 | 93d7ae8e | Allen Kay | } |
996 | 93d7ae8e | Allen Kay | |
997 | 0546b8c2 | Stefan Weil | /* Power Management Capability reg static information table */
|
998 | 93d7ae8e | Allen Kay | static XenPTRegInfo xen_pt_emu_reg_pm[] = {
|
999 | 93d7ae8e | Allen Kay | /* Next Pointer reg */
|
1000 | 93d7ae8e | Allen Kay | { |
1001 | 93d7ae8e | Allen Kay | .offset = PCI_CAP_LIST_NEXT, |
1002 | 93d7ae8e | Allen Kay | .size = 1,
|
1003 | 93d7ae8e | Allen Kay | .init_val = 0x00,
|
1004 | 93d7ae8e | Allen Kay | .ro_mask = 0xFF,
|
1005 | 93d7ae8e | Allen Kay | .emu_mask = 0xFF,
|
1006 | 93d7ae8e | Allen Kay | .init = xen_pt_ptr_reg_init, |
1007 | 93d7ae8e | Allen Kay | .u.b.read = xen_pt_byte_reg_read, |
1008 | 93d7ae8e | Allen Kay | .u.b.write = xen_pt_byte_reg_write, |
1009 | 93d7ae8e | Allen Kay | }, |
1010 | 93d7ae8e | Allen Kay | /* Power Management Capabilities reg */
|
1011 | 93d7ae8e | Allen Kay | { |
1012 | 93d7ae8e | Allen Kay | .offset = PCI_CAP_FLAGS, |
1013 | 93d7ae8e | Allen Kay | .size = 2,
|
1014 | 93d7ae8e | Allen Kay | .init_val = 0x0000,
|
1015 | 93d7ae8e | Allen Kay | .ro_mask = 0xFFFF,
|
1016 | 93d7ae8e | Allen Kay | .emu_mask = 0xF9C8,
|
1017 | 93d7ae8e | Allen Kay | .init = xen_pt_common_reg_init, |
1018 | 93d7ae8e | Allen Kay | .u.w.read = xen_pt_word_reg_read, |
1019 | 93d7ae8e | Allen Kay | .u.w.write = xen_pt_word_reg_write, |
1020 | 93d7ae8e | Allen Kay | }, |
1021 | 93d7ae8e | Allen Kay | /* PCI Power Management Control/Status reg */
|
1022 | 93d7ae8e | Allen Kay | { |
1023 | 93d7ae8e | Allen Kay | .offset = PCI_PM_CTRL, |
1024 | 93d7ae8e | Allen Kay | .size = 2,
|
1025 | 93d7ae8e | Allen Kay | .init_val = 0x0008,
|
1026 | 93d7ae8e | Allen Kay | .ro_mask = 0xE1FC,
|
1027 | 93d7ae8e | Allen Kay | .emu_mask = 0x8100,
|
1028 | 93d7ae8e | Allen Kay | .init = xen_pt_common_reg_init, |
1029 | 93d7ae8e | Allen Kay | .u.w.read = xen_pt_pmcsr_reg_read, |
1030 | 93d7ae8e | Allen Kay | .u.w.write = xen_pt_pmcsr_reg_write, |
1031 | 93d7ae8e | Allen Kay | }, |
1032 | 93d7ae8e | Allen Kay | { |
1033 | 93d7ae8e | Allen Kay | .size = 0,
|
1034 | 93d7ae8e | Allen Kay | }, |
1035 | 93d7ae8e | Allen Kay | }; |
1036 | 93d7ae8e | Allen Kay | |
1037 | 93d7ae8e | Allen Kay | |
1038 | 3854ca57 | Jiang Yunhong | /********************************
|
1039 | 3854ca57 | Jiang Yunhong | * MSI Capability
|
1040 | 3854ca57 | Jiang Yunhong | */
|
1041 | 3854ca57 | Jiang Yunhong | |
1042 | 3854ca57 | Jiang Yunhong | /* Helper */
|
1043 | 3854ca57 | Jiang Yunhong | static bool xen_pt_msgdata_check_type(uint32_t offset, uint16_t flags) |
1044 | 3854ca57 | Jiang Yunhong | { |
1045 | 3854ca57 | Jiang Yunhong | /* check the offset whether matches the type or not */
|
1046 | 3854ca57 | Jiang Yunhong | bool is_32 = (offset == PCI_MSI_DATA_32) && !(flags & PCI_MSI_FLAGS_64BIT);
|
1047 | 3854ca57 | Jiang Yunhong | bool is_64 = (offset == PCI_MSI_DATA_64) && (flags & PCI_MSI_FLAGS_64BIT);
|
1048 | 3854ca57 | Jiang Yunhong | return is_32 || is_64;
|
1049 | 3854ca57 | Jiang Yunhong | } |
1050 | 3854ca57 | Jiang Yunhong | |
1051 | 3854ca57 | Jiang Yunhong | /* Message Control register */
|
1052 | 3854ca57 | Jiang Yunhong | static int xen_pt_msgctrl_reg_init(XenPCIPassthroughState *s, |
1053 | 3854ca57 | Jiang Yunhong | XenPTRegInfo *reg, uint32_t real_offset, |
1054 | 3854ca57 | Jiang Yunhong | uint32_t *data) |
1055 | 3854ca57 | Jiang Yunhong | { |
1056 | 3854ca57 | Jiang Yunhong | PCIDevice *d = &s->dev; |
1057 | 3854ca57 | Jiang Yunhong | XenPTMSI *msi = s->msi; |
1058 | 3854ca57 | Jiang Yunhong | uint16_t reg_field = 0;
|
1059 | 3854ca57 | Jiang Yunhong | |
1060 | 3854ca57 | Jiang Yunhong | /* use I/O device register's value as initial value */
|
1061 | 3854ca57 | Jiang Yunhong | reg_field = pci_get_word(d->config + real_offset); |
1062 | 3854ca57 | Jiang Yunhong | |
1063 | 3854ca57 | Jiang Yunhong | if (reg_field & PCI_MSI_FLAGS_ENABLE) {
|
1064 | 3854ca57 | Jiang Yunhong | XEN_PT_LOG(&s->dev, "MSI already enabled, disabling it first\n");
|
1065 | 3854ca57 | Jiang Yunhong | xen_host_pci_set_word(&s->real_device, real_offset, |
1066 | 3854ca57 | Jiang Yunhong | reg_field & ~PCI_MSI_FLAGS_ENABLE); |
1067 | 3854ca57 | Jiang Yunhong | } |
1068 | 3854ca57 | Jiang Yunhong | msi->flags |= reg_field; |
1069 | 3854ca57 | Jiang Yunhong | msi->ctrl_offset = real_offset; |
1070 | 3854ca57 | Jiang Yunhong | msi->initialized = false;
|
1071 | 3854ca57 | Jiang Yunhong | msi->mapped = false;
|
1072 | 3854ca57 | Jiang Yunhong | |
1073 | 3854ca57 | Jiang Yunhong | *data = reg->init_val; |
1074 | 3854ca57 | Jiang Yunhong | return 0; |
1075 | 3854ca57 | Jiang Yunhong | } |
1076 | 3854ca57 | Jiang Yunhong | static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s, |
1077 | 3854ca57 | Jiang Yunhong | XenPTReg *cfg_entry, uint16_t *val, |
1078 | 3854ca57 | Jiang Yunhong | uint16_t dev_value, uint16_t valid_mask) |
1079 | 3854ca57 | Jiang Yunhong | { |
1080 | 3854ca57 | Jiang Yunhong | XenPTRegInfo *reg = cfg_entry->reg; |
1081 | 3854ca57 | Jiang Yunhong | XenPTMSI *msi = s->msi; |
1082 | 3854ca57 | Jiang Yunhong | uint16_t writable_mask = 0;
|
1083 | 3854ca57 | Jiang Yunhong | uint16_t throughable_mask = 0;
|
1084 | 3854ca57 | Jiang Yunhong | uint16_t raw_val; |
1085 | 3854ca57 | Jiang Yunhong | |
1086 | 3854ca57 | Jiang Yunhong | /* Currently no support for multi-vector */
|
1087 | 3854ca57 | Jiang Yunhong | if (*val & PCI_MSI_FLAGS_QSIZE) {
|
1088 | 3854ca57 | Jiang Yunhong | XEN_PT_WARN(&s->dev, "Tries to set more than 1 vector ctrl %x\n", *val);
|
1089 | 3854ca57 | Jiang Yunhong | } |
1090 | 3854ca57 | Jiang Yunhong | |
1091 | 3854ca57 | Jiang Yunhong | /* modify emulate register */
|
1092 | 3854ca57 | Jiang Yunhong | writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; |
1093 | 3854ca57 | Jiang Yunhong | cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); |
1094 | 3854ca57 | Jiang Yunhong | msi->flags |= cfg_entry->data & ~PCI_MSI_FLAGS_ENABLE; |
1095 | 3854ca57 | Jiang Yunhong | |
1096 | 3854ca57 | Jiang Yunhong | /* create value for writing to I/O device register */
|
1097 | 3854ca57 | Jiang Yunhong | raw_val = *val; |
1098 | 3854ca57 | Jiang Yunhong | throughable_mask = ~reg->emu_mask & valid_mask; |
1099 | 3854ca57 | Jiang Yunhong | *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); |
1100 | 3854ca57 | Jiang Yunhong | |
1101 | 3854ca57 | Jiang Yunhong | /* update MSI */
|
1102 | 3854ca57 | Jiang Yunhong | if (raw_val & PCI_MSI_FLAGS_ENABLE) {
|
1103 | 3854ca57 | Jiang Yunhong | /* setup MSI pirq for the first time */
|
1104 | 3854ca57 | Jiang Yunhong | if (!msi->initialized) {
|
1105 | 3854ca57 | Jiang Yunhong | /* Init physical one */
|
1106 | 3854ca57 | Jiang Yunhong | XEN_PT_LOG(&s->dev, "setup MSI\n");
|
1107 | 3854ca57 | Jiang Yunhong | if (xen_pt_msi_setup(s)) {
|
1108 | 3854ca57 | Jiang Yunhong | /* We do not broadcast the error to the framework code, so
|
1109 | 3854ca57 | Jiang Yunhong | * that MSI errors are contained in MSI emulation code and
|
1110 | 3854ca57 | Jiang Yunhong | * QEMU can go on running.
|
1111 | 3854ca57 | Jiang Yunhong | * Guest MSI would be actually not working.
|
1112 | 3854ca57 | Jiang Yunhong | */
|
1113 | 3854ca57 | Jiang Yunhong | *val &= ~PCI_MSI_FLAGS_ENABLE; |
1114 | 3854ca57 | Jiang Yunhong | XEN_PT_WARN(&s->dev, "Can not map MSI.\n");
|
1115 | 3854ca57 | Jiang Yunhong | return 0; |
1116 | 3854ca57 | Jiang Yunhong | } |
1117 | 3854ca57 | Jiang Yunhong | if (xen_pt_msi_update(s)) {
|
1118 | 3854ca57 | Jiang Yunhong | *val &= ~PCI_MSI_FLAGS_ENABLE; |
1119 | 3854ca57 | Jiang Yunhong | XEN_PT_WARN(&s->dev, "Can not bind MSI\n");
|
1120 | 3854ca57 | Jiang Yunhong | return 0; |
1121 | 3854ca57 | Jiang Yunhong | } |
1122 | 3854ca57 | Jiang Yunhong | msi->initialized = true;
|
1123 | 3854ca57 | Jiang Yunhong | msi->mapped = true;
|
1124 | 3854ca57 | Jiang Yunhong | } |
1125 | 3854ca57 | Jiang Yunhong | msi->flags |= PCI_MSI_FLAGS_ENABLE; |
1126 | 3854ca57 | Jiang Yunhong | } else {
|
1127 | 3854ca57 | Jiang Yunhong | msi->flags &= ~PCI_MSI_FLAGS_ENABLE; |
1128 | 3854ca57 | Jiang Yunhong | } |
1129 | 3854ca57 | Jiang Yunhong | |
1130 | 3854ca57 | Jiang Yunhong | /* pass through MSI_ENABLE bit */
|
1131 | 3854ca57 | Jiang Yunhong | *val &= ~PCI_MSI_FLAGS_ENABLE; |
1132 | 3854ca57 | Jiang Yunhong | *val |= raw_val & PCI_MSI_FLAGS_ENABLE; |
1133 | 3854ca57 | Jiang Yunhong | |
1134 | 3854ca57 | Jiang Yunhong | return 0; |
1135 | 3854ca57 | Jiang Yunhong | } |
1136 | 3854ca57 | Jiang Yunhong | |
1137 | 3854ca57 | Jiang Yunhong | /* initialize Message Upper Address register */
|
1138 | 3854ca57 | Jiang Yunhong | static int xen_pt_msgaddr64_reg_init(XenPCIPassthroughState *s, |
1139 | 3854ca57 | Jiang Yunhong | XenPTRegInfo *reg, uint32_t real_offset, |
1140 | 3854ca57 | Jiang Yunhong | uint32_t *data) |
1141 | 3854ca57 | Jiang Yunhong | { |
1142 | 3854ca57 | Jiang Yunhong | /* no need to initialize in case of 32 bit type */
|
1143 | 3854ca57 | Jiang Yunhong | if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) {
|
1144 | 3854ca57 | Jiang Yunhong | *data = XEN_PT_INVALID_REG; |
1145 | 3854ca57 | Jiang Yunhong | } else {
|
1146 | 3854ca57 | Jiang Yunhong | *data = reg->init_val; |
1147 | 3854ca57 | Jiang Yunhong | } |
1148 | 3854ca57 | Jiang Yunhong | |
1149 | 3854ca57 | Jiang Yunhong | return 0; |
1150 | 3854ca57 | Jiang Yunhong | } |
1151 | 3854ca57 | Jiang Yunhong | /* this function will be called twice (for 32 bit and 64 bit type) */
|
1152 | 3854ca57 | Jiang Yunhong | /* initialize Message Data register */
|
1153 | 3854ca57 | Jiang Yunhong | static int xen_pt_msgdata_reg_init(XenPCIPassthroughState *s, |
1154 | 3854ca57 | Jiang Yunhong | XenPTRegInfo *reg, uint32_t real_offset, |
1155 | 3854ca57 | Jiang Yunhong | uint32_t *data) |
1156 | 3854ca57 | Jiang Yunhong | { |
1157 | 3854ca57 | Jiang Yunhong | uint32_t flags = s->msi->flags; |
1158 | 3854ca57 | Jiang Yunhong | uint32_t offset = reg->offset; |
1159 | 3854ca57 | Jiang Yunhong | |
1160 | 3854ca57 | Jiang Yunhong | /* check the offset whether matches the type or not */
|
1161 | 3854ca57 | Jiang Yunhong | if (xen_pt_msgdata_check_type(offset, flags)) {
|
1162 | 3854ca57 | Jiang Yunhong | *data = reg->init_val; |
1163 | 3854ca57 | Jiang Yunhong | } else {
|
1164 | 3854ca57 | Jiang Yunhong | *data = XEN_PT_INVALID_REG; |
1165 | 3854ca57 | Jiang Yunhong | } |
1166 | 3854ca57 | Jiang Yunhong | return 0; |
1167 | 3854ca57 | Jiang Yunhong | } |
1168 | 3854ca57 | Jiang Yunhong | |
1169 | 3854ca57 | Jiang Yunhong | /* write Message Address register */
|
1170 | 3854ca57 | Jiang Yunhong | static int xen_pt_msgaddr32_reg_write(XenPCIPassthroughState *s, |
1171 | 3854ca57 | Jiang Yunhong | XenPTReg *cfg_entry, uint32_t *val, |
1172 | 3854ca57 | Jiang Yunhong | uint32_t dev_value, uint32_t valid_mask) |
1173 | 3854ca57 | Jiang Yunhong | { |
1174 | 3854ca57 | Jiang Yunhong | XenPTRegInfo *reg = cfg_entry->reg; |
1175 | 3854ca57 | Jiang Yunhong | uint32_t writable_mask = 0;
|
1176 | 3854ca57 | Jiang Yunhong | uint32_t throughable_mask = 0;
|
1177 | 3854ca57 | Jiang Yunhong | uint32_t old_addr = cfg_entry->data; |
1178 | 3854ca57 | Jiang Yunhong | |
1179 | 3854ca57 | Jiang Yunhong | /* modify emulate register */
|
1180 | 3854ca57 | Jiang Yunhong | writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; |
1181 | 3854ca57 | Jiang Yunhong | cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); |
1182 | 3854ca57 | Jiang Yunhong | s->msi->addr_lo = cfg_entry->data; |
1183 | 3854ca57 | Jiang Yunhong | |
1184 | 3854ca57 | Jiang Yunhong | /* create value for writing to I/O device register */
|
1185 | 3854ca57 | Jiang Yunhong | throughable_mask = ~reg->emu_mask & valid_mask; |
1186 | 3854ca57 | Jiang Yunhong | *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); |
1187 | 3854ca57 | Jiang Yunhong | |
1188 | 3854ca57 | Jiang Yunhong | /* update MSI */
|
1189 | 3854ca57 | Jiang Yunhong | if (cfg_entry->data != old_addr) {
|
1190 | 3854ca57 | Jiang Yunhong | if (s->msi->mapped) {
|
1191 | 3854ca57 | Jiang Yunhong | xen_pt_msi_update(s); |
1192 | 3854ca57 | Jiang Yunhong | } |
1193 | 3854ca57 | Jiang Yunhong | } |
1194 | 3854ca57 | Jiang Yunhong | |
1195 | 3854ca57 | Jiang Yunhong | return 0; |
1196 | 3854ca57 | Jiang Yunhong | } |
1197 | 3854ca57 | Jiang Yunhong | /* write Message Upper Address register */
|
1198 | 3854ca57 | Jiang Yunhong | static int xen_pt_msgaddr64_reg_write(XenPCIPassthroughState *s, |
1199 | 3854ca57 | Jiang Yunhong | XenPTReg *cfg_entry, uint32_t *val, |
1200 | 3854ca57 | Jiang Yunhong | uint32_t dev_value, uint32_t valid_mask) |
1201 | 3854ca57 | Jiang Yunhong | { |
1202 | 3854ca57 | Jiang Yunhong | XenPTRegInfo *reg = cfg_entry->reg; |
1203 | 3854ca57 | Jiang Yunhong | uint32_t writable_mask = 0;
|
1204 | 3854ca57 | Jiang Yunhong | uint32_t throughable_mask = 0;
|
1205 | 3854ca57 | Jiang Yunhong | uint32_t old_addr = cfg_entry->data; |
1206 | 3854ca57 | Jiang Yunhong | |
1207 | 3854ca57 | Jiang Yunhong | /* check whether the type is 64 bit or not */
|
1208 | 3854ca57 | Jiang Yunhong | if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) {
|
1209 | 3854ca57 | Jiang Yunhong | XEN_PT_ERR(&s->dev, |
1210 | 3854ca57 | Jiang Yunhong | "Can't write to the upper address without 64 bit support\n");
|
1211 | 3854ca57 | Jiang Yunhong | return -1; |
1212 | 3854ca57 | Jiang Yunhong | } |
1213 | 3854ca57 | Jiang Yunhong | |
1214 | 3854ca57 | Jiang Yunhong | /* modify emulate register */
|
1215 | 3854ca57 | Jiang Yunhong | writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; |
1216 | 3854ca57 | Jiang Yunhong | cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); |
1217 | 3854ca57 | Jiang Yunhong | /* update the msi_info too */
|
1218 | 3854ca57 | Jiang Yunhong | s->msi->addr_hi = cfg_entry->data; |
1219 | 3854ca57 | Jiang Yunhong | |
1220 | 3854ca57 | Jiang Yunhong | /* create value for writing to I/O device register */
|
1221 | 3854ca57 | Jiang Yunhong | throughable_mask = ~reg->emu_mask & valid_mask; |
1222 | 3854ca57 | Jiang Yunhong | *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); |
1223 | 3854ca57 | Jiang Yunhong | |
1224 | 3854ca57 | Jiang Yunhong | /* update MSI */
|
1225 | 3854ca57 | Jiang Yunhong | if (cfg_entry->data != old_addr) {
|
1226 | 3854ca57 | Jiang Yunhong | if (s->msi->mapped) {
|
1227 | 3854ca57 | Jiang Yunhong | xen_pt_msi_update(s); |
1228 | 3854ca57 | Jiang Yunhong | } |
1229 | 3854ca57 | Jiang Yunhong | } |
1230 | 3854ca57 | Jiang Yunhong | |
1231 | 3854ca57 | Jiang Yunhong | return 0; |
1232 | 3854ca57 | Jiang Yunhong | } |
1233 | 3854ca57 | Jiang Yunhong | |
1234 | 3854ca57 | Jiang Yunhong | |
1235 | 3854ca57 | Jiang Yunhong | /* this function will be called twice (for 32 bit and 64 bit type) */
|
1236 | 3854ca57 | Jiang Yunhong | /* write Message Data register */
|
1237 | 3854ca57 | Jiang Yunhong | static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s, |
1238 | 3854ca57 | Jiang Yunhong | XenPTReg *cfg_entry, uint16_t *val, |
1239 | 3854ca57 | Jiang Yunhong | uint16_t dev_value, uint16_t valid_mask) |
1240 | 3854ca57 | Jiang Yunhong | { |
1241 | 3854ca57 | Jiang Yunhong | XenPTRegInfo *reg = cfg_entry->reg; |
1242 | 3854ca57 | Jiang Yunhong | XenPTMSI *msi = s->msi; |
1243 | 3854ca57 | Jiang Yunhong | uint16_t writable_mask = 0;
|
1244 | 3854ca57 | Jiang Yunhong | uint16_t throughable_mask = 0;
|
1245 | 3854ca57 | Jiang Yunhong | uint16_t old_data = cfg_entry->data; |
1246 | 3854ca57 | Jiang Yunhong | uint32_t offset = reg->offset; |
1247 | 3854ca57 | Jiang Yunhong | |
1248 | 3854ca57 | Jiang Yunhong | /* check the offset whether matches the type or not */
|
1249 | 3854ca57 | Jiang Yunhong | if (!xen_pt_msgdata_check_type(offset, msi->flags)) {
|
1250 | 3854ca57 | Jiang Yunhong | /* exit I/O emulator */
|
1251 | 3854ca57 | Jiang Yunhong | XEN_PT_ERR(&s->dev, "the offset does not match the 32/64 bit type!\n");
|
1252 | 3854ca57 | Jiang Yunhong | return -1; |
1253 | 3854ca57 | Jiang Yunhong | } |
1254 | 3854ca57 | Jiang Yunhong | |
1255 | 3854ca57 | Jiang Yunhong | /* modify emulate register */
|
1256 | 3854ca57 | Jiang Yunhong | writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; |
1257 | 3854ca57 | Jiang Yunhong | cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); |
1258 | 3854ca57 | Jiang Yunhong | /* update the msi_info too */
|
1259 | 3854ca57 | Jiang Yunhong | msi->data = cfg_entry->data; |
1260 | 3854ca57 | Jiang Yunhong | |
1261 | 3854ca57 | Jiang Yunhong | /* create value for writing to I/O device register */
|
1262 | 3854ca57 | Jiang Yunhong | throughable_mask = ~reg->emu_mask & valid_mask; |
1263 | 3854ca57 | Jiang Yunhong | *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); |
1264 | 3854ca57 | Jiang Yunhong | |
1265 | 3854ca57 | Jiang Yunhong | /* update MSI */
|
1266 | 3854ca57 | Jiang Yunhong | if (cfg_entry->data != old_data) {
|
1267 | 3854ca57 | Jiang Yunhong | if (msi->mapped) {
|
1268 | 3854ca57 | Jiang Yunhong | xen_pt_msi_update(s); |
1269 | 3854ca57 | Jiang Yunhong | } |
1270 | 3854ca57 | Jiang Yunhong | } |
1271 | 3854ca57 | Jiang Yunhong | |
1272 | 3854ca57 | Jiang Yunhong | return 0; |
1273 | 3854ca57 | Jiang Yunhong | } |
1274 | 3854ca57 | Jiang Yunhong | |
1275 | 0546b8c2 | Stefan Weil | /* MSI Capability Structure reg static information table */
|
1276 | 3854ca57 | Jiang Yunhong | static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
1277 | 3854ca57 | Jiang Yunhong | /* Next Pointer reg */
|
1278 | 3854ca57 | Jiang Yunhong | { |
1279 | 3854ca57 | Jiang Yunhong | .offset = PCI_CAP_LIST_NEXT, |
1280 | 3854ca57 | Jiang Yunhong | .size = 1,
|
1281 | 3854ca57 | Jiang Yunhong | .init_val = 0x00,
|
1282 | 3854ca57 | Jiang Yunhong | .ro_mask = 0xFF,
|
1283 | 3854ca57 | Jiang Yunhong | .emu_mask = 0xFF,
|
1284 | 3854ca57 | Jiang Yunhong | .init = xen_pt_ptr_reg_init, |
1285 | 3854ca57 | Jiang Yunhong | .u.b.read = xen_pt_byte_reg_read, |
1286 | 3854ca57 | Jiang Yunhong | .u.b.write = xen_pt_byte_reg_write, |
1287 | 3854ca57 | Jiang Yunhong | }, |
1288 | 3854ca57 | Jiang Yunhong | /* Message Control reg */
|
1289 | 3854ca57 | Jiang Yunhong | { |
1290 | 3854ca57 | Jiang Yunhong | .offset = PCI_MSI_FLAGS, |
1291 | 3854ca57 | Jiang Yunhong | .size = 2,
|
1292 | 3854ca57 | Jiang Yunhong | .init_val = 0x0000,
|
1293 | 3854ca57 | Jiang Yunhong | .ro_mask = 0xFF8E,
|
1294 | 3854ca57 | Jiang Yunhong | .emu_mask = 0x007F,
|
1295 | 3854ca57 | Jiang Yunhong | .init = xen_pt_msgctrl_reg_init, |
1296 | 3854ca57 | Jiang Yunhong | .u.w.read = xen_pt_word_reg_read, |
1297 | 3854ca57 | Jiang Yunhong | .u.w.write = xen_pt_msgctrl_reg_write, |
1298 | 3854ca57 | Jiang Yunhong | }, |
1299 | 3854ca57 | Jiang Yunhong | /* Message Address reg */
|
1300 | 3854ca57 | Jiang Yunhong | { |
1301 | 3854ca57 | Jiang Yunhong | .offset = PCI_MSI_ADDRESS_LO, |
1302 | 3854ca57 | Jiang Yunhong | .size = 4,
|
1303 | 3854ca57 | Jiang Yunhong | .init_val = 0x00000000,
|
1304 | 3854ca57 | Jiang Yunhong | .ro_mask = 0x00000003,
|
1305 | 3854ca57 | Jiang Yunhong | .emu_mask = 0xFFFFFFFF,
|
1306 | 3854ca57 | Jiang Yunhong | .no_wb = 1,
|
1307 | 3854ca57 | Jiang Yunhong | .init = xen_pt_common_reg_init, |
1308 | 3854ca57 | Jiang Yunhong | .u.dw.read = xen_pt_long_reg_read, |
1309 | 3854ca57 | Jiang Yunhong | .u.dw.write = xen_pt_msgaddr32_reg_write, |
1310 | 3854ca57 | Jiang Yunhong | }, |
1311 | 3854ca57 | Jiang Yunhong | /* Message Upper Address reg (if PCI_MSI_FLAGS_64BIT set) */
|
1312 | 3854ca57 | Jiang Yunhong | { |
1313 | 3854ca57 | Jiang Yunhong | .offset = PCI_MSI_ADDRESS_HI, |
1314 | 3854ca57 | Jiang Yunhong | .size = 4,
|
1315 | 3854ca57 | Jiang Yunhong | .init_val = 0x00000000,
|
1316 | 3854ca57 | Jiang Yunhong | .ro_mask = 0x00000000,
|
1317 | 3854ca57 | Jiang Yunhong | .emu_mask = 0xFFFFFFFF,
|
1318 | 3854ca57 | Jiang Yunhong | .no_wb = 1,
|
1319 | 3854ca57 | Jiang Yunhong | .init = xen_pt_msgaddr64_reg_init, |
1320 | 3854ca57 | Jiang Yunhong | .u.dw.read = xen_pt_long_reg_read, |
1321 | 3854ca57 | Jiang Yunhong | .u.dw.write = xen_pt_msgaddr64_reg_write, |
1322 | 3854ca57 | Jiang Yunhong | }, |
1323 | 3854ca57 | Jiang Yunhong | /* Message Data reg (16 bits of data for 32-bit devices) */
|
1324 | 3854ca57 | Jiang Yunhong | { |
1325 | 3854ca57 | Jiang Yunhong | .offset = PCI_MSI_DATA_32, |
1326 | 3854ca57 | Jiang Yunhong | .size = 2,
|
1327 | 3854ca57 | Jiang Yunhong | .init_val = 0x0000,
|
1328 | 3854ca57 | Jiang Yunhong | .ro_mask = 0x0000,
|
1329 | 3854ca57 | Jiang Yunhong | .emu_mask = 0xFFFF,
|
1330 | 3854ca57 | Jiang Yunhong | .no_wb = 1,
|
1331 | 3854ca57 | Jiang Yunhong | .init = xen_pt_msgdata_reg_init, |
1332 | 3854ca57 | Jiang Yunhong | .u.w.read = xen_pt_word_reg_read, |
1333 | 3854ca57 | Jiang Yunhong | .u.w.write = xen_pt_msgdata_reg_write, |
1334 | 3854ca57 | Jiang Yunhong | }, |
1335 | 3854ca57 | Jiang Yunhong | /* Message Data reg (16 bits of data for 64-bit devices) */
|
1336 | 3854ca57 | Jiang Yunhong | { |
1337 | 3854ca57 | Jiang Yunhong | .offset = PCI_MSI_DATA_64, |
1338 | 3854ca57 | Jiang Yunhong | .size = 2,
|
1339 | 3854ca57 | Jiang Yunhong | .init_val = 0x0000,
|
1340 | 3854ca57 | Jiang Yunhong | .ro_mask = 0x0000,
|
1341 | 3854ca57 | Jiang Yunhong | .emu_mask = 0xFFFF,
|
1342 | 3854ca57 | Jiang Yunhong | .no_wb = 1,
|
1343 | 3854ca57 | Jiang Yunhong | .init = xen_pt_msgdata_reg_init, |
1344 | 3854ca57 | Jiang Yunhong | .u.w.read = xen_pt_word_reg_read, |
1345 | 3854ca57 | Jiang Yunhong | .u.w.write = xen_pt_msgdata_reg_write, |
1346 | 3854ca57 | Jiang Yunhong | }, |
1347 | 3854ca57 | Jiang Yunhong | { |
1348 | 3854ca57 | Jiang Yunhong | .size = 0,
|
1349 | 3854ca57 | Jiang Yunhong | }, |
1350 | 3854ca57 | Jiang Yunhong | }; |
1351 | 3854ca57 | Jiang Yunhong | |
1352 | 3854ca57 | Jiang Yunhong | |
1353 | 3854ca57 | Jiang Yunhong | /**************************************
|
1354 | 3854ca57 | Jiang Yunhong | * MSI-X Capability
|
1355 | 3854ca57 | Jiang Yunhong | */
|
1356 | 3854ca57 | Jiang Yunhong | |
1357 | 3854ca57 | Jiang Yunhong | /* Message Control register for MSI-X */
|
1358 | 3854ca57 | Jiang Yunhong | static int xen_pt_msixctrl_reg_init(XenPCIPassthroughState *s, |
1359 | 3854ca57 | Jiang Yunhong | XenPTRegInfo *reg, uint32_t real_offset, |
1360 | 3854ca57 | Jiang Yunhong | uint32_t *data) |
1361 | 3854ca57 | Jiang Yunhong | { |
1362 | 3854ca57 | Jiang Yunhong | PCIDevice *d = &s->dev; |
1363 | 3854ca57 | Jiang Yunhong | uint16_t reg_field = 0;
|
1364 | 3854ca57 | Jiang Yunhong | |
1365 | 3854ca57 | Jiang Yunhong | /* use I/O device register's value as initial value */
|
1366 | 3854ca57 | Jiang Yunhong | reg_field = pci_get_word(d->config + real_offset); |
1367 | 3854ca57 | Jiang Yunhong | |
1368 | 3854ca57 | Jiang Yunhong | if (reg_field & PCI_MSIX_FLAGS_ENABLE) {
|
1369 | 3854ca57 | Jiang Yunhong | XEN_PT_LOG(d, "MSIX already enabled, disabling it first\n");
|
1370 | 3854ca57 | Jiang Yunhong | xen_host_pci_set_word(&s->real_device, real_offset, |
1371 | 3854ca57 | Jiang Yunhong | reg_field & ~PCI_MSIX_FLAGS_ENABLE); |
1372 | 3854ca57 | Jiang Yunhong | } |
1373 | 3854ca57 | Jiang Yunhong | |
1374 | 3854ca57 | Jiang Yunhong | s->msix->ctrl_offset = real_offset; |
1375 | 3854ca57 | Jiang Yunhong | |
1376 | 3854ca57 | Jiang Yunhong | *data = reg->init_val; |
1377 | 3854ca57 | Jiang Yunhong | return 0; |
1378 | 3854ca57 | Jiang Yunhong | } |
1379 | 3854ca57 | Jiang Yunhong | static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s, |
1380 | 3854ca57 | Jiang Yunhong | XenPTReg *cfg_entry, uint16_t *val, |
1381 | 3854ca57 | Jiang Yunhong | uint16_t dev_value, uint16_t valid_mask) |
1382 | 3854ca57 | Jiang Yunhong | { |
1383 | 3854ca57 | Jiang Yunhong | XenPTRegInfo *reg = cfg_entry->reg; |
1384 | 3854ca57 | Jiang Yunhong | uint16_t writable_mask = 0;
|
1385 | 3854ca57 | Jiang Yunhong | uint16_t throughable_mask = 0;
|
1386 | 3854ca57 | Jiang Yunhong | int debug_msix_enabled_old;
|
1387 | 3854ca57 | Jiang Yunhong | |
1388 | 3854ca57 | Jiang Yunhong | /* modify emulate register */
|
1389 | 3854ca57 | Jiang Yunhong | writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; |
1390 | 3854ca57 | Jiang Yunhong | cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); |
1391 | 3854ca57 | Jiang Yunhong | |
1392 | 3854ca57 | Jiang Yunhong | /* create value for writing to I/O device register */
|
1393 | 3854ca57 | Jiang Yunhong | throughable_mask = ~reg->emu_mask & valid_mask; |
1394 | 3854ca57 | Jiang Yunhong | *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); |
1395 | 3854ca57 | Jiang Yunhong | |
1396 | 3854ca57 | Jiang Yunhong | /* update MSI-X */
|
1397 | 3854ca57 | Jiang Yunhong | if ((*val & PCI_MSIX_FLAGS_ENABLE)
|
1398 | 3854ca57 | Jiang Yunhong | && !(*val & PCI_MSIX_FLAGS_MASKALL)) { |
1399 | 3854ca57 | Jiang Yunhong | xen_pt_msix_update(s); |
1400 | 3854ca57 | Jiang Yunhong | } |
1401 | 3854ca57 | Jiang Yunhong | |
1402 | 3854ca57 | Jiang Yunhong | debug_msix_enabled_old = s->msix->enabled; |
1403 | 3854ca57 | Jiang Yunhong | s->msix->enabled = !!(*val & PCI_MSIX_FLAGS_ENABLE); |
1404 | 3854ca57 | Jiang Yunhong | if (s->msix->enabled != debug_msix_enabled_old) {
|
1405 | 3854ca57 | Jiang Yunhong | XEN_PT_LOG(&s->dev, "%s MSI-X\n",
|
1406 | 3854ca57 | Jiang Yunhong | s->msix->enabled ? "enable" : "disable"); |
1407 | 3854ca57 | Jiang Yunhong | } |
1408 | 3854ca57 | Jiang Yunhong | |
1409 | 3854ca57 | Jiang Yunhong | return 0; |
1410 | 3854ca57 | Jiang Yunhong | } |
1411 | 3854ca57 | Jiang Yunhong | |
1412 | 0546b8c2 | Stefan Weil | /* MSI-X Capability Structure reg static information table */
|
1413 | 3854ca57 | Jiang Yunhong | static XenPTRegInfo xen_pt_emu_reg_msix[] = {
|
1414 | 3854ca57 | Jiang Yunhong | /* Next Pointer reg */
|
1415 | 3854ca57 | Jiang Yunhong | { |
1416 | 3854ca57 | Jiang Yunhong | .offset = PCI_CAP_LIST_NEXT, |
1417 | 3854ca57 | Jiang Yunhong | .size = 1,
|
1418 | 3854ca57 | Jiang Yunhong | .init_val = 0x00,
|
1419 | 3854ca57 | Jiang Yunhong | .ro_mask = 0xFF,
|
1420 | 3854ca57 | Jiang Yunhong | .emu_mask = 0xFF,
|
1421 | 3854ca57 | Jiang Yunhong | .init = xen_pt_ptr_reg_init, |
1422 | 3854ca57 | Jiang Yunhong | .u.b.read = xen_pt_byte_reg_read, |
1423 | 3854ca57 | Jiang Yunhong | .u.b.write = xen_pt_byte_reg_write, |
1424 | 3854ca57 | Jiang Yunhong | }, |
1425 | 3854ca57 | Jiang Yunhong | /* Message Control reg */
|
1426 | 3854ca57 | Jiang Yunhong | { |
1427 | 3854ca57 | Jiang Yunhong | .offset = PCI_MSI_FLAGS, |
1428 | 3854ca57 | Jiang Yunhong | .size = 2,
|
1429 | 3854ca57 | Jiang Yunhong | .init_val = 0x0000,
|
1430 | 3854ca57 | Jiang Yunhong | .ro_mask = 0x3FFF,
|
1431 | 3854ca57 | Jiang Yunhong | .emu_mask = 0x0000,
|
1432 | 3854ca57 | Jiang Yunhong | .init = xen_pt_msixctrl_reg_init, |
1433 | 3854ca57 | Jiang Yunhong | .u.w.read = xen_pt_word_reg_read, |
1434 | 3854ca57 | Jiang Yunhong | .u.w.write = xen_pt_msixctrl_reg_write, |
1435 | 3854ca57 | Jiang Yunhong | }, |
1436 | 3854ca57 | Jiang Yunhong | { |
1437 | 3854ca57 | Jiang Yunhong | .size = 0,
|
1438 | 3854ca57 | Jiang Yunhong | }, |
1439 | 3854ca57 | Jiang Yunhong | }; |
1440 | 3854ca57 | Jiang Yunhong | |
1441 | 3854ca57 | Jiang Yunhong | |
1442 | 93d7ae8e | Allen Kay | /****************************
|
1443 | 93d7ae8e | Allen Kay | * Capabilities
|
1444 | 93d7ae8e | Allen Kay | */
|
1445 | 93d7ae8e | Allen Kay | |
1446 | 93d7ae8e | Allen Kay | /* capability structure register group size functions */
|
1447 | 93d7ae8e | Allen Kay | |
1448 | 93d7ae8e | Allen Kay | static int xen_pt_reg_grp_size_init(XenPCIPassthroughState *s, |
1449 | 93d7ae8e | Allen Kay | const XenPTRegGroupInfo *grp_reg,
|
1450 | 93d7ae8e | Allen Kay | uint32_t base_offset, uint8_t *size) |
1451 | 93d7ae8e | Allen Kay | { |
1452 | 93d7ae8e | Allen Kay | *size = grp_reg->grp_size; |
1453 | 93d7ae8e | Allen Kay | return 0; |
1454 | 93d7ae8e | Allen Kay | } |
1455 | 93d7ae8e | Allen Kay | /* get Vendor Specific Capability Structure register group size */
|
1456 | 93d7ae8e | Allen Kay | static int xen_pt_vendor_size_init(XenPCIPassthroughState *s, |
1457 | 93d7ae8e | Allen Kay | const XenPTRegGroupInfo *grp_reg,
|
1458 | 93d7ae8e | Allen Kay | uint32_t base_offset, uint8_t *size) |
1459 | 93d7ae8e | Allen Kay | { |
1460 | 93d7ae8e | Allen Kay | *size = pci_get_byte(s->dev.config + base_offset + 0x02);
|
1461 | 93d7ae8e | Allen Kay | return 0; |
1462 | 93d7ae8e | Allen Kay | } |
1463 | 93d7ae8e | Allen Kay | /* get PCI Express Capability Structure register group size */
|
1464 | 93d7ae8e | Allen Kay | static int xen_pt_pcie_size_init(XenPCIPassthroughState *s, |
1465 | 93d7ae8e | Allen Kay | const XenPTRegGroupInfo *grp_reg,
|
1466 | 93d7ae8e | Allen Kay | uint32_t base_offset, uint8_t *size) |
1467 | 93d7ae8e | Allen Kay | { |
1468 | 93d7ae8e | Allen Kay | PCIDevice *d = &s->dev; |
1469 | 93d7ae8e | Allen Kay | uint8_t version = get_capability_version(s, base_offset); |
1470 | 93d7ae8e | Allen Kay | uint8_t type = get_device_type(s, base_offset); |
1471 | 93d7ae8e | Allen Kay | uint8_t pcie_size = 0;
|
1472 | 93d7ae8e | Allen Kay | |
1473 | 93d7ae8e | Allen Kay | |
1474 | 93d7ae8e | Allen Kay | /* calculate size depend on capability version and device/port type */
|
1475 | 93d7ae8e | Allen Kay | /* in case of PCI Express Base Specification Rev 1.x */
|
1476 | 93d7ae8e | Allen Kay | if (version == 1) { |
1477 | 93d7ae8e | Allen Kay | /* The PCI Express Capabilities, Device Capabilities, and Device
|
1478 | 93d7ae8e | Allen Kay | * Status/Control registers are required for all PCI Express devices.
|
1479 | 93d7ae8e | Allen Kay | * The Link Capabilities and Link Status/Control are required for all
|
1480 | 93d7ae8e | Allen Kay | * Endpoints that are not Root Complex Integrated Endpoints. Endpoints
|
1481 | 93d7ae8e | Allen Kay | * are not required to implement registers other than those listed
|
1482 | 93d7ae8e | Allen Kay | * above and terminate the capability structure.
|
1483 | 93d7ae8e | Allen Kay | */
|
1484 | 93d7ae8e | Allen Kay | switch (type) {
|
1485 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_ENDPOINT:
|
1486 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_LEG_END:
|
1487 | 93d7ae8e | Allen Kay | pcie_size = 0x14;
|
1488 | 93d7ae8e | Allen Kay | break;
|
1489 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_RC_END:
|
1490 | 93d7ae8e | Allen Kay | /* has no link */
|
1491 | 93d7ae8e | Allen Kay | pcie_size = 0x0C;
|
1492 | 93d7ae8e | Allen Kay | break;
|
1493 | 93d7ae8e | Allen Kay | /* only EndPoint passthrough is supported */
|
1494 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_ROOT_PORT:
|
1495 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_UPSTREAM:
|
1496 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_DOWNSTREAM:
|
1497 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_PCI_BRIDGE:
|
1498 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_PCIE_BRIDGE:
|
1499 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_RC_EC:
|
1500 | 93d7ae8e | Allen Kay | default:
|
1501 | 93d7ae8e | Allen Kay | XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type);
|
1502 | 93d7ae8e | Allen Kay | return -1; |
1503 | 93d7ae8e | Allen Kay | } |
1504 | 93d7ae8e | Allen Kay | } |
1505 | 93d7ae8e | Allen Kay | /* in case of PCI Express Base Specification Rev 2.0 */
|
1506 | 93d7ae8e | Allen Kay | else if (version == 2) { |
1507 | 93d7ae8e | Allen Kay | switch (type) {
|
1508 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_ENDPOINT:
|
1509 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_LEG_END:
|
1510 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_RC_END:
|
1511 | 93d7ae8e | Allen Kay | /* For Functions that do not implement the registers,
|
1512 | 93d7ae8e | Allen Kay | * these spaces must be hardwired to 0b.
|
1513 | 93d7ae8e | Allen Kay | */
|
1514 | 93d7ae8e | Allen Kay | pcie_size = 0x3C;
|
1515 | 93d7ae8e | Allen Kay | break;
|
1516 | 93d7ae8e | Allen Kay | /* only EndPoint passthrough is supported */
|
1517 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_ROOT_PORT:
|
1518 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_UPSTREAM:
|
1519 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_DOWNSTREAM:
|
1520 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_PCI_BRIDGE:
|
1521 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_PCIE_BRIDGE:
|
1522 | 93d7ae8e | Allen Kay | case PCI_EXP_TYPE_RC_EC:
|
1523 | 93d7ae8e | Allen Kay | default:
|
1524 | 93d7ae8e | Allen Kay | XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type);
|
1525 | 93d7ae8e | Allen Kay | return -1; |
1526 | 93d7ae8e | Allen Kay | } |
1527 | 93d7ae8e | Allen Kay | } else {
|
1528 | 93d7ae8e | Allen Kay | XEN_PT_ERR(d, "Unsupported capability version %#x.\n", version);
|
1529 | 93d7ae8e | Allen Kay | return -1; |
1530 | 93d7ae8e | Allen Kay | } |
1531 | 93d7ae8e | Allen Kay | |
1532 | 93d7ae8e | Allen Kay | *size = pcie_size; |
1533 | 93d7ae8e | Allen Kay | return 0; |
1534 | 93d7ae8e | Allen Kay | } |
1535 | 3854ca57 | Jiang Yunhong | /* get MSI Capability Structure register group size */
|
1536 | 3854ca57 | Jiang Yunhong | static int xen_pt_msi_size_init(XenPCIPassthroughState *s, |
1537 | 3854ca57 | Jiang Yunhong | const XenPTRegGroupInfo *grp_reg,
|
1538 | 3854ca57 | Jiang Yunhong | uint32_t base_offset, uint8_t *size) |
1539 | 3854ca57 | Jiang Yunhong | { |
1540 | 3854ca57 | Jiang Yunhong | PCIDevice *d = &s->dev; |
1541 | 3854ca57 | Jiang Yunhong | uint16_t msg_ctrl = 0;
|
1542 | 3854ca57 | Jiang Yunhong | uint8_t msi_size = 0xa;
|
1543 | 3854ca57 | Jiang Yunhong | |
1544 | 3854ca57 | Jiang Yunhong | msg_ctrl = pci_get_word(d->config + (base_offset + PCI_MSI_FLAGS)); |
1545 | 3854ca57 | Jiang Yunhong | |
1546 | 3854ca57 | Jiang Yunhong | /* check if 64-bit address is capable of per-vector masking */
|
1547 | 3854ca57 | Jiang Yunhong | if (msg_ctrl & PCI_MSI_FLAGS_64BIT) {
|
1548 | 3854ca57 | Jiang Yunhong | msi_size += 4;
|
1549 | 3854ca57 | Jiang Yunhong | } |
1550 | 3854ca57 | Jiang Yunhong | if (msg_ctrl & PCI_MSI_FLAGS_MASKBIT) {
|
1551 | 3854ca57 | Jiang Yunhong | msi_size += 10;
|
1552 | 3854ca57 | Jiang Yunhong | } |
1553 | 3854ca57 | Jiang Yunhong | |
1554 | 3854ca57 | Jiang Yunhong | s->msi = g_new0(XenPTMSI, 1);
|
1555 | 3854ca57 | Jiang Yunhong | s->msi->pirq = XEN_PT_UNASSIGNED_PIRQ; |
1556 | 3854ca57 | Jiang Yunhong | |
1557 | 3854ca57 | Jiang Yunhong | *size = msi_size; |
1558 | 3854ca57 | Jiang Yunhong | return 0; |
1559 | 3854ca57 | Jiang Yunhong | } |
1560 | 3854ca57 | Jiang Yunhong | /* get MSI-X Capability Structure register group size */
|
1561 | 3854ca57 | Jiang Yunhong | static int xen_pt_msix_size_init(XenPCIPassthroughState *s, |
1562 | 3854ca57 | Jiang Yunhong | const XenPTRegGroupInfo *grp_reg,
|
1563 | 3854ca57 | Jiang Yunhong | uint32_t base_offset, uint8_t *size) |
1564 | 3854ca57 | Jiang Yunhong | { |
1565 | 3854ca57 | Jiang Yunhong | int rc = 0; |
1566 | 3854ca57 | Jiang Yunhong | |
1567 | 3854ca57 | Jiang Yunhong | rc = xen_pt_msix_init(s, base_offset); |
1568 | 3854ca57 | Jiang Yunhong | |
1569 | 3854ca57 | Jiang Yunhong | if (rc < 0) { |
1570 | 3854ca57 | Jiang Yunhong | XEN_PT_ERR(&s->dev, "Internal error: Invalid xen_pt_msix_init.\n");
|
1571 | 3854ca57 | Jiang Yunhong | return rc;
|
1572 | 3854ca57 | Jiang Yunhong | } |
1573 | 3854ca57 | Jiang Yunhong | |
1574 | 3854ca57 | Jiang Yunhong | *size = grp_reg->grp_size; |
1575 | 3854ca57 | Jiang Yunhong | return 0; |
1576 | 3854ca57 | Jiang Yunhong | } |
1577 | 3854ca57 | Jiang Yunhong | |
1578 | 93d7ae8e | Allen Kay | |
1579 | 93d7ae8e | Allen Kay | static const XenPTRegGroupInfo xen_pt_emu_reg_grps[] = { |
1580 | 93d7ae8e | Allen Kay | /* Header Type0 reg group */
|
1581 | 93d7ae8e | Allen Kay | { |
1582 | 93d7ae8e | Allen Kay | .grp_id = 0xFF,
|
1583 | 93d7ae8e | Allen Kay | .grp_type = XEN_PT_GRP_TYPE_EMU, |
1584 | 93d7ae8e | Allen Kay | .grp_size = 0x40,
|
1585 | 93d7ae8e | Allen Kay | .size_init = xen_pt_reg_grp_size_init, |
1586 | 93d7ae8e | Allen Kay | .emu_regs = xen_pt_emu_reg_header0, |
1587 | 93d7ae8e | Allen Kay | }, |
1588 | 93d7ae8e | Allen Kay | /* PCI PowerManagement Capability reg group */
|
1589 | 93d7ae8e | Allen Kay | { |
1590 | 93d7ae8e | Allen Kay | .grp_id = PCI_CAP_ID_PM, |
1591 | 93d7ae8e | Allen Kay | .grp_type = XEN_PT_GRP_TYPE_EMU, |
1592 | 93d7ae8e | Allen Kay | .grp_size = PCI_PM_SIZEOF, |
1593 | 93d7ae8e | Allen Kay | .size_init = xen_pt_reg_grp_size_init, |
1594 | 93d7ae8e | Allen Kay | .emu_regs = xen_pt_emu_reg_pm, |
1595 | 93d7ae8e | Allen Kay | }, |
1596 | 93d7ae8e | Allen Kay | /* AGP Capability Structure reg group */
|
1597 | 93d7ae8e | Allen Kay | { |
1598 | 93d7ae8e | Allen Kay | .grp_id = PCI_CAP_ID_AGP, |
1599 | 93d7ae8e | Allen Kay | .grp_type = XEN_PT_GRP_TYPE_HARDWIRED, |
1600 | 93d7ae8e | Allen Kay | .grp_size = 0x30,
|
1601 | 93d7ae8e | Allen Kay | .size_init = xen_pt_reg_grp_size_init, |
1602 | 93d7ae8e | Allen Kay | }, |
1603 | 93d7ae8e | Allen Kay | /* Vital Product Data Capability Structure reg group */
|
1604 | 93d7ae8e | Allen Kay | { |
1605 | 93d7ae8e | Allen Kay | .grp_id = PCI_CAP_ID_VPD, |
1606 | 93d7ae8e | Allen Kay | .grp_type = XEN_PT_GRP_TYPE_EMU, |
1607 | 93d7ae8e | Allen Kay | .grp_size = 0x08,
|
1608 | 93d7ae8e | Allen Kay | .size_init = xen_pt_reg_grp_size_init, |
1609 | 93d7ae8e | Allen Kay | .emu_regs = xen_pt_emu_reg_vpd, |
1610 | 93d7ae8e | Allen Kay | }, |
1611 | 93d7ae8e | Allen Kay | /* Slot Identification reg group */
|
1612 | 93d7ae8e | Allen Kay | { |
1613 | 93d7ae8e | Allen Kay | .grp_id = PCI_CAP_ID_SLOTID, |
1614 | 93d7ae8e | Allen Kay | .grp_type = XEN_PT_GRP_TYPE_HARDWIRED, |
1615 | 93d7ae8e | Allen Kay | .grp_size = 0x04,
|
1616 | 93d7ae8e | Allen Kay | .size_init = xen_pt_reg_grp_size_init, |
1617 | 93d7ae8e | Allen Kay | }, |
1618 | 3854ca57 | Jiang Yunhong | /* MSI Capability Structure reg group */
|
1619 | 3854ca57 | Jiang Yunhong | { |
1620 | 3854ca57 | Jiang Yunhong | .grp_id = PCI_CAP_ID_MSI, |
1621 | 3854ca57 | Jiang Yunhong | .grp_type = XEN_PT_GRP_TYPE_EMU, |
1622 | 3854ca57 | Jiang Yunhong | .grp_size = 0xFF,
|
1623 | 3854ca57 | Jiang Yunhong | .size_init = xen_pt_msi_size_init, |
1624 | 3854ca57 | Jiang Yunhong | .emu_regs = xen_pt_emu_reg_msi, |
1625 | 3854ca57 | Jiang Yunhong | }, |
1626 | 93d7ae8e | Allen Kay | /* PCI-X Capabilities List Item reg group */
|
1627 | 93d7ae8e | Allen Kay | { |
1628 | 93d7ae8e | Allen Kay | .grp_id = PCI_CAP_ID_PCIX, |
1629 | 93d7ae8e | Allen Kay | .grp_type = XEN_PT_GRP_TYPE_HARDWIRED, |
1630 | 93d7ae8e | Allen Kay | .grp_size = 0x18,
|
1631 | 93d7ae8e | Allen Kay | .size_init = xen_pt_reg_grp_size_init, |
1632 | 93d7ae8e | Allen Kay | }, |
1633 | 93d7ae8e | Allen Kay | /* Vendor Specific Capability Structure reg group */
|
1634 | 93d7ae8e | Allen Kay | { |
1635 | 93d7ae8e | Allen Kay | .grp_id = PCI_CAP_ID_VNDR, |
1636 | 93d7ae8e | Allen Kay | .grp_type = XEN_PT_GRP_TYPE_EMU, |
1637 | 93d7ae8e | Allen Kay | .grp_size = 0xFF,
|
1638 | 93d7ae8e | Allen Kay | .size_init = xen_pt_vendor_size_init, |
1639 | 93d7ae8e | Allen Kay | .emu_regs = xen_pt_emu_reg_vendor, |
1640 | 93d7ae8e | Allen Kay | }, |
1641 | 93d7ae8e | Allen Kay | /* SHPC Capability List Item reg group */
|
1642 | 93d7ae8e | Allen Kay | { |
1643 | 93d7ae8e | Allen Kay | .grp_id = PCI_CAP_ID_SHPC, |
1644 | 93d7ae8e | Allen Kay | .grp_type = XEN_PT_GRP_TYPE_HARDWIRED, |
1645 | 93d7ae8e | Allen Kay | .grp_size = 0x08,
|
1646 | 93d7ae8e | Allen Kay | .size_init = xen_pt_reg_grp_size_init, |
1647 | 93d7ae8e | Allen Kay | }, |
1648 | 93d7ae8e | Allen Kay | /* Subsystem ID and Subsystem Vendor ID Capability List Item reg group */
|
1649 | 93d7ae8e | Allen Kay | { |
1650 | 93d7ae8e | Allen Kay | .grp_id = PCI_CAP_ID_SSVID, |
1651 | 93d7ae8e | Allen Kay | .grp_type = XEN_PT_GRP_TYPE_HARDWIRED, |
1652 | 93d7ae8e | Allen Kay | .grp_size = 0x08,
|
1653 | 93d7ae8e | Allen Kay | .size_init = xen_pt_reg_grp_size_init, |
1654 | 93d7ae8e | Allen Kay | }, |
1655 | 93d7ae8e | Allen Kay | /* AGP 8x Capability Structure reg group */
|
1656 | 93d7ae8e | Allen Kay | { |
1657 | 93d7ae8e | Allen Kay | .grp_id = PCI_CAP_ID_AGP3, |
1658 | 93d7ae8e | Allen Kay | .grp_type = XEN_PT_GRP_TYPE_HARDWIRED, |
1659 | 93d7ae8e | Allen Kay | .grp_size = 0x30,
|
1660 | 93d7ae8e | Allen Kay | .size_init = xen_pt_reg_grp_size_init, |
1661 | 93d7ae8e | Allen Kay | }, |
1662 | 93d7ae8e | Allen Kay | /* PCI Express Capability Structure reg group */
|
1663 | 93d7ae8e | Allen Kay | { |
1664 | 93d7ae8e | Allen Kay | .grp_id = PCI_CAP_ID_EXP, |
1665 | 93d7ae8e | Allen Kay | .grp_type = XEN_PT_GRP_TYPE_EMU, |
1666 | 93d7ae8e | Allen Kay | .grp_size = 0xFF,
|
1667 | 93d7ae8e | Allen Kay | .size_init = xen_pt_pcie_size_init, |
1668 | 93d7ae8e | Allen Kay | .emu_regs = xen_pt_emu_reg_pcie, |
1669 | 93d7ae8e | Allen Kay | }, |
1670 | 3854ca57 | Jiang Yunhong | /* MSI-X Capability Structure reg group */
|
1671 | 3854ca57 | Jiang Yunhong | { |
1672 | 3854ca57 | Jiang Yunhong | .grp_id = PCI_CAP_ID_MSIX, |
1673 | 3854ca57 | Jiang Yunhong | .grp_type = XEN_PT_GRP_TYPE_EMU, |
1674 | 3854ca57 | Jiang Yunhong | .grp_size = 0x0C,
|
1675 | 3854ca57 | Jiang Yunhong | .size_init = xen_pt_msix_size_init, |
1676 | 3854ca57 | Jiang Yunhong | .emu_regs = xen_pt_emu_reg_msix, |
1677 | 3854ca57 | Jiang Yunhong | }, |
1678 | 93d7ae8e | Allen Kay | { |
1679 | 93d7ae8e | Allen Kay | .grp_size = 0,
|
1680 | 93d7ae8e | Allen Kay | }, |
1681 | 93d7ae8e | Allen Kay | }; |
1682 | 93d7ae8e | Allen Kay | |
1683 | 93d7ae8e | Allen Kay | /* initialize Capabilities Pointer or Next Pointer register */
|
1684 | 93d7ae8e | Allen Kay | static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s, |
1685 | 93d7ae8e | Allen Kay | XenPTRegInfo *reg, uint32_t real_offset, |
1686 | 93d7ae8e | Allen Kay | uint32_t *data) |
1687 | 93d7ae8e | Allen Kay | { |
1688 | 93d7ae8e | Allen Kay | int i;
|
1689 | 93d7ae8e | Allen Kay | uint8_t *config = s->dev.config; |
1690 | 93d7ae8e | Allen Kay | uint32_t reg_field = pci_get_byte(config + real_offset); |
1691 | 93d7ae8e | Allen Kay | uint8_t cap_id = 0;
|
1692 | 93d7ae8e | Allen Kay | |
1693 | 93d7ae8e | Allen Kay | /* find capability offset */
|
1694 | 93d7ae8e | Allen Kay | while (reg_field) {
|
1695 | 93d7ae8e | Allen Kay | for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) { |
1696 | 93d7ae8e | Allen Kay | if (xen_pt_hide_dev_cap(&s->real_device,
|
1697 | 93d7ae8e | Allen Kay | xen_pt_emu_reg_grps[i].grp_id)) { |
1698 | 93d7ae8e | Allen Kay | continue;
|
1699 | 93d7ae8e | Allen Kay | } |
1700 | 93d7ae8e | Allen Kay | |
1701 | 93d7ae8e | Allen Kay | cap_id = pci_get_byte(config + reg_field + PCI_CAP_LIST_ID); |
1702 | 93d7ae8e | Allen Kay | if (xen_pt_emu_reg_grps[i].grp_id == cap_id) {
|
1703 | 93d7ae8e | Allen Kay | if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) {
|
1704 | 93d7ae8e | Allen Kay | goto out;
|
1705 | 93d7ae8e | Allen Kay | } |
1706 | 93d7ae8e | Allen Kay | /* ignore the 0 hardwired capability, find next one */
|
1707 | 93d7ae8e | Allen Kay | break;
|
1708 | 93d7ae8e | Allen Kay | } |
1709 | 93d7ae8e | Allen Kay | } |
1710 | 93d7ae8e | Allen Kay | |
1711 | 93d7ae8e | Allen Kay | /* next capability */
|
1712 | 93d7ae8e | Allen Kay | reg_field = pci_get_byte(config + reg_field + PCI_CAP_LIST_NEXT); |
1713 | 93d7ae8e | Allen Kay | } |
1714 | 93d7ae8e | Allen Kay | |
1715 | 93d7ae8e | Allen Kay | out:
|
1716 | 93d7ae8e | Allen Kay | *data = reg_field; |
1717 | 93d7ae8e | Allen Kay | return 0; |
1718 | 93d7ae8e | Allen Kay | } |
1719 | 93d7ae8e | Allen Kay | |
1720 | 93d7ae8e | Allen Kay | |
1721 | 93d7ae8e | Allen Kay | /*************
|
1722 | 93d7ae8e | Allen Kay | * Main
|
1723 | 93d7ae8e | Allen Kay | */
|
1724 | 93d7ae8e | Allen Kay | |
1725 | 93d7ae8e | Allen Kay | static uint8_t find_cap_offset(XenPCIPassthroughState *s, uint8_t cap)
|
1726 | 93d7ae8e | Allen Kay | { |
1727 | 93d7ae8e | Allen Kay | uint8_t id; |
1728 | 93d7ae8e | Allen Kay | unsigned max_cap = PCI_CAP_MAX;
|
1729 | 93d7ae8e | Allen Kay | uint8_t pos = PCI_CAPABILITY_LIST; |
1730 | 93d7ae8e | Allen Kay | uint8_t status = 0;
|
1731 | 93d7ae8e | Allen Kay | |
1732 | 93d7ae8e | Allen Kay | if (xen_host_pci_get_byte(&s->real_device, PCI_STATUS, &status)) {
|
1733 | 93d7ae8e | Allen Kay | return 0; |
1734 | 93d7ae8e | Allen Kay | } |
1735 | 93d7ae8e | Allen Kay | if ((status & PCI_STATUS_CAP_LIST) == 0) { |
1736 | 93d7ae8e | Allen Kay | return 0; |
1737 | 93d7ae8e | Allen Kay | } |
1738 | 93d7ae8e | Allen Kay | |
1739 | 93d7ae8e | Allen Kay | while (max_cap--) {
|
1740 | 93d7ae8e | Allen Kay | if (xen_host_pci_get_byte(&s->real_device, pos, &pos)) {
|
1741 | 93d7ae8e | Allen Kay | break;
|
1742 | 93d7ae8e | Allen Kay | } |
1743 | 93d7ae8e | Allen Kay | if (pos < PCI_CONFIG_HEADER_SIZE) {
|
1744 | 93d7ae8e | Allen Kay | break;
|
1745 | 93d7ae8e | Allen Kay | } |
1746 | 93d7ae8e | Allen Kay | |
1747 | 93d7ae8e | Allen Kay | pos &= ~3;
|
1748 | 93d7ae8e | Allen Kay | if (xen_host_pci_get_byte(&s->real_device,
|
1749 | 93d7ae8e | Allen Kay | pos + PCI_CAP_LIST_ID, &id)) { |
1750 | 93d7ae8e | Allen Kay | break;
|
1751 | 93d7ae8e | Allen Kay | } |
1752 | 93d7ae8e | Allen Kay | |
1753 | 93d7ae8e | Allen Kay | if (id == 0xff) { |
1754 | 93d7ae8e | Allen Kay | break;
|
1755 | 93d7ae8e | Allen Kay | } |
1756 | 93d7ae8e | Allen Kay | if (id == cap) {
|
1757 | 93d7ae8e | Allen Kay | return pos;
|
1758 | 93d7ae8e | Allen Kay | } |
1759 | 93d7ae8e | Allen Kay | |
1760 | 93d7ae8e | Allen Kay | pos += PCI_CAP_LIST_NEXT; |
1761 | 93d7ae8e | Allen Kay | } |
1762 | 93d7ae8e | Allen Kay | return 0; |
1763 | 93d7ae8e | Allen Kay | } |
1764 | 93d7ae8e | Allen Kay | |
1765 | 93d7ae8e | Allen Kay | static int xen_pt_config_reg_init(XenPCIPassthroughState *s, |
1766 | 93d7ae8e | Allen Kay | XenPTRegGroup *reg_grp, XenPTRegInfo *reg) |
1767 | 93d7ae8e | Allen Kay | { |
1768 | 93d7ae8e | Allen Kay | XenPTReg *reg_entry; |
1769 | 93d7ae8e | Allen Kay | uint32_t data = 0;
|
1770 | 93d7ae8e | Allen Kay | int rc = 0; |
1771 | 93d7ae8e | Allen Kay | |
1772 | 93d7ae8e | Allen Kay | reg_entry = g_new0(XenPTReg, 1);
|
1773 | 93d7ae8e | Allen Kay | reg_entry->reg = reg; |
1774 | 93d7ae8e | Allen Kay | |
1775 | 93d7ae8e | Allen Kay | if (reg->init) {
|
1776 | 93d7ae8e | Allen Kay | /* initialize emulate register */
|
1777 | 93d7ae8e | Allen Kay | rc = reg->init(s, reg_entry->reg, |
1778 | 93d7ae8e | Allen Kay | reg_grp->base_offset + reg->offset, &data); |
1779 | 93d7ae8e | Allen Kay | if (rc < 0) { |
1780 | 93d7ae8e | Allen Kay | free(reg_entry); |
1781 | 93d7ae8e | Allen Kay | return rc;
|
1782 | 93d7ae8e | Allen Kay | } |
1783 | 93d7ae8e | Allen Kay | if (data == XEN_PT_INVALID_REG) {
|
1784 | 93d7ae8e | Allen Kay | /* free unused BAR register entry */
|
1785 | 93d7ae8e | Allen Kay | free(reg_entry); |
1786 | 93d7ae8e | Allen Kay | return 0; |
1787 | 93d7ae8e | Allen Kay | } |
1788 | 93d7ae8e | Allen Kay | /* set register value */
|
1789 | 93d7ae8e | Allen Kay | reg_entry->data = data; |
1790 | 93d7ae8e | Allen Kay | } |
1791 | 93d7ae8e | Allen Kay | /* list add register entry */
|
1792 | 93d7ae8e | Allen Kay | QLIST_INSERT_HEAD(®_grp->reg_tbl_list, reg_entry, entries); |
1793 | 93d7ae8e | Allen Kay | |
1794 | 93d7ae8e | Allen Kay | return 0; |
1795 | 93d7ae8e | Allen Kay | } |
1796 | 93d7ae8e | Allen Kay | |
1797 | 93d7ae8e | Allen Kay | int xen_pt_config_init(XenPCIPassthroughState *s)
|
1798 | 93d7ae8e | Allen Kay | { |
1799 | 93d7ae8e | Allen Kay | int i, rc;
|
1800 | 93d7ae8e | Allen Kay | |
1801 | 93d7ae8e | Allen Kay | QLIST_INIT(&s->reg_grps); |
1802 | 93d7ae8e | Allen Kay | |
1803 | 93d7ae8e | Allen Kay | for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) { |
1804 | 93d7ae8e | Allen Kay | uint32_t reg_grp_offset = 0;
|
1805 | 93d7ae8e | Allen Kay | XenPTRegGroup *reg_grp_entry = NULL;
|
1806 | 93d7ae8e | Allen Kay | |
1807 | 93d7ae8e | Allen Kay | if (xen_pt_emu_reg_grps[i].grp_id != 0xFF) { |
1808 | 93d7ae8e | Allen Kay | if (xen_pt_hide_dev_cap(&s->real_device,
|
1809 | 93d7ae8e | Allen Kay | xen_pt_emu_reg_grps[i].grp_id)) { |
1810 | 93d7ae8e | Allen Kay | continue;
|
1811 | 93d7ae8e | Allen Kay | } |
1812 | 93d7ae8e | Allen Kay | |
1813 | 93d7ae8e | Allen Kay | reg_grp_offset = find_cap_offset(s, xen_pt_emu_reg_grps[i].grp_id); |
1814 | 93d7ae8e | Allen Kay | |
1815 | 93d7ae8e | Allen Kay | if (!reg_grp_offset) {
|
1816 | 93d7ae8e | Allen Kay | continue;
|
1817 | 93d7ae8e | Allen Kay | } |
1818 | 93d7ae8e | Allen Kay | } |
1819 | 93d7ae8e | Allen Kay | |
1820 | 93d7ae8e | Allen Kay | reg_grp_entry = g_new0(XenPTRegGroup, 1);
|
1821 | 93d7ae8e | Allen Kay | QLIST_INIT(®_grp_entry->reg_tbl_list); |
1822 | 93d7ae8e | Allen Kay | QLIST_INSERT_HEAD(&s->reg_grps, reg_grp_entry, entries); |
1823 | 93d7ae8e | Allen Kay | |
1824 | 93d7ae8e | Allen Kay | reg_grp_entry->base_offset = reg_grp_offset; |
1825 | 93d7ae8e | Allen Kay | reg_grp_entry->reg_grp = xen_pt_emu_reg_grps + i; |
1826 | 93d7ae8e | Allen Kay | if (xen_pt_emu_reg_grps[i].size_init) {
|
1827 | 93d7ae8e | Allen Kay | /* get register group size */
|
1828 | 93d7ae8e | Allen Kay | rc = xen_pt_emu_reg_grps[i].size_init(s, reg_grp_entry->reg_grp, |
1829 | 93d7ae8e | Allen Kay | reg_grp_offset, |
1830 | 93d7ae8e | Allen Kay | ®_grp_entry->size); |
1831 | 93d7ae8e | Allen Kay | if (rc < 0) { |
1832 | 93d7ae8e | Allen Kay | xen_pt_config_delete(s); |
1833 | 93d7ae8e | Allen Kay | return rc;
|
1834 | 93d7ae8e | Allen Kay | } |
1835 | 93d7ae8e | Allen Kay | } |
1836 | 93d7ae8e | Allen Kay | |
1837 | 93d7ae8e | Allen Kay | if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) {
|
1838 | 93d7ae8e | Allen Kay | if (xen_pt_emu_reg_grps[i].emu_regs) {
|
1839 | 93d7ae8e | Allen Kay | int j = 0; |
1840 | 93d7ae8e | Allen Kay | XenPTRegInfo *regs = xen_pt_emu_reg_grps[i].emu_regs; |
1841 | 93d7ae8e | Allen Kay | /* initialize capability register */
|
1842 | 93d7ae8e | Allen Kay | for (j = 0; regs->size != 0; j++, regs++) { |
1843 | 93d7ae8e | Allen Kay | /* initialize capability register */
|
1844 | 93d7ae8e | Allen Kay | rc = xen_pt_config_reg_init(s, reg_grp_entry, regs); |
1845 | 93d7ae8e | Allen Kay | if (rc < 0) { |
1846 | 93d7ae8e | Allen Kay | xen_pt_config_delete(s); |
1847 | 93d7ae8e | Allen Kay | return rc;
|
1848 | 93d7ae8e | Allen Kay | } |
1849 | 93d7ae8e | Allen Kay | } |
1850 | 93d7ae8e | Allen Kay | } |
1851 | 93d7ae8e | Allen Kay | } |
1852 | 93d7ae8e | Allen Kay | } |
1853 | 93d7ae8e | Allen Kay | |
1854 | 93d7ae8e | Allen Kay | return 0; |
1855 | 93d7ae8e | Allen Kay | } |
1856 | 93d7ae8e | Allen Kay | |
1857 | 93d7ae8e | Allen Kay | /* delete all emulate register */
|
1858 | 93d7ae8e | Allen Kay | void xen_pt_config_delete(XenPCIPassthroughState *s)
|
1859 | 93d7ae8e | Allen Kay | { |
1860 | 93d7ae8e | Allen Kay | struct XenPTRegGroup *reg_group, *next_grp;
|
1861 | 93d7ae8e | Allen Kay | struct XenPTReg *reg, *next_reg;
|
1862 | 93d7ae8e | Allen Kay | |
1863 | 3854ca57 | Jiang Yunhong | /* free MSI/MSI-X info table */
|
1864 | 3854ca57 | Jiang Yunhong | if (s->msix) {
|
1865 | 3854ca57 | Jiang Yunhong | xen_pt_msix_delete(s); |
1866 | 3854ca57 | Jiang Yunhong | } |
1867 | 3854ca57 | Jiang Yunhong | if (s->msi) {
|
1868 | 3854ca57 | Jiang Yunhong | g_free(s->msi); |
1869 | 3854ca57 | Jiang Yunhong | } |
1870 | 3854ca57 | Jiang Yunhong | |
1871 | 93d7ae8e | Allen Kay | /* free all register group entry */
|
1872 | 93d7ae8e | Allen Kay | QLIST_FOREACH_SAFE(reg_group, &s->reg_grps, entries, next_grp) { |
1873 | 93d7ae8e | Allen Kay | /* free all register entry */
|
1874 | 93d7ae8e | Allen Kay | QLIST_FOREACH_SAFE(reg, ®_group->reg_tbl_list, entries, next_reg) { |
1875 | 93d7ae8e | Allen Kay | QLIST_REMOVE(reg, entries); |
1876 | 93d7ae8e | Allen Kay | g_free(reg); |
1877 | 93d7ae8e | Allen Kay | } |
1878 | 93d7ae8e | Allen Kay | |
1879 | 93d7ae8e | Allen Kay | QLIST_REMOVE(reg_group, entries); |
1880 | 93d7ae8e | Allen Kay | g_free(reg_group); |
1881 | 93d7ae8e | Allen Kay | } |
1882 | 93d7ae8e | Allen Kay | } |