]>
Commit | Line | Data |
---|---|---|
de9768f0 DC |
1 | package PVE::QemuServer::PCI; |
2 | ||
74c17b7a SR |
3 | use PVE::JSONSchema; |
4 | use PVE::SysFSTools; | |
5 | ||
de9768f0 DC |
6 | use base 'Exporter'; |
7 | ||
8 | our @EXPORT_OK = qw( | |
9 | print_pci_addr | |
10 | print_pcie_addr | |
c4e16381 | 11 | print_pcie_root_port |
74c17b7a | 12 | parse_hostpci |
de9768f0 DC |
13 | ); |
14 | ||
74c17b7a SR |
15 | our $MAX_HOSTPCI_DEVICES = 16; |
16 | ||
17 | my $PCIRE = qr/([a-f0-9]{4}:)?[a-f0-9]{2}:[a-f0-9]{2}(?:\.[a-f0-9])?/; | |
18 | my $hostpci_fmt = { | |
19 | host => { | |
20 | default_key => 1, | |
21 | type => 'string', | |
22 | pattern => qr/$PCIRE(;$PCIRE)*/, | |
23 | format_description => 'HOSTPCIID[;HOSTPCIID2...]', | |
24 | description => <<EODESCR, | |
25 | Host PCI device pass through. The PCI ID of a host's PCI device or a list | |
26 | of PCI virtual functions of the host. HOSTPCIID syntax is: | |
27 | ||
28 | 'bus:dev.func' (hexadecimal numbers) | |
29 | ||
30 | You can us the 'lspci' command to list existing PCI devices. | |
31 | EODESCR | |
32 | }, | |
33 | rombar => { | |
34 | type => 'boolean', | |
1fac3a0b TL |
35 | description => "Specify whether or not the device's ROM will be visible in the" |
36 | ." guest's memory map.", | |
74c17b7a SR |
37 | optional => 1, |
38 | default => 1, | |
39 | }, | |
40 | romfile => { | |
1fac3a0b TL |
41 | type => 'string', |
42 | pattern => '[^,;]+', | |
43 | format_description => 'string', | |
44 | description => "Custom pci device rom filename (must be located in /usr/share/kvm/).", | |
45 | optional => 1, | |
74c17b7a SR |
46 | }, |
47 | pcie => { | |
48 | type => 'boolean', | |
1fac3a0b | 49 | description => "Choose the PCI-express bus (needs the 'q35' machine model).", |
74c17b7a SR |
50 | optional => 1, |
51 | default => 0, | |
52 | }, | |
53 | 'x-vga' => { | |
54 | type => 'boolean', | |
1fac3a0b | 55 | description => "Enable vfio-vga device support.", |
74c17b7a SR |
56 | optional => 1, |
57 | default => 0, | |
58 | }, | |
13d68979 SR |
59 | 'legacy-igd' => { |
60 | type => 'boolean', | |
1fac3a0b TL |
61 | description => "Pass this device in legacy IGD mode, making it the primary and exclusive" |
62 | ." graphics device in the VM. Requires 'pc-i440fx' machine type and VGA set to 'none'.", | |
13d68979 SR |
63 | optional => 1, |
64 | default => 0, | |
65 | }, | |
74c17b7a SR |
66 | 'mdev' => { |
67 | type => 'string', | |
1fac3a0b | 68 | format_description => 'string', |
74c17b7a SR |
69 | pattern => '[^/\.:]+', |
70 | optional => 1, | |
71 | description => <<EODESCR | |
72 | The type of mediated device to use. | |
73 | An instance of this type will be created on startup of the VM and | |
74 | will be cleaned up when the VM stops. | |
75 | EODESCR | |
76 | } | |
77 | }; | |
78 | PVE::JSONSchema::register_format('pve-qm-hostpci', $hostpci_fmt); | |
79 | ||
80 | our $hostpcidesc = { | |
1fac3a0b TL |
81 | optional => 1, |
82 | type => 'string', format => 'pve-qm-hostpci', | |
83 | description => "Map host PCI devices into guest.", | |
74c17b7a SR |
84 | verbose_description => <<EODESCR, |
85 | Map host PCI devices into guest. | |
86 | ||
87 | NOTE: This option allows direct access to host hardware. So it is no longer | |
88 | possible to migrate such machines - use with special care. | |
89 | ||
90 | CAUTION: Experimental! User reported problems with this option. | |
91 | EODESCR | |
92 | }; | |
93 | PVE::JSONSchema::register_standard_option("pve-qm-hostpci", $hostpcidesc); | |
94 | ||
d7d698f6 TL |
95 | my $pci_addr_map; |
96 | sub get_pci_addr_map { | |
97 | $pci_addr_map = { | |
98 | piix3 => { bus => 0, addr => 1, conflict_ok => qw(ehci) }, | |
99 | ehci => { bus => 0, addr => 1, conflict_ok => qw(piix3) }, # instead of piix3 on arm | |
13d68979 SR |
100 | vga => { bus => 0, addr => 2, conflict_ok => qw(legacy-igd) }, |
101 | 'legacy-igd' => { bus => 0, addr => 2, conflict_ok => qw(vga) }, # legacy-igd requires vga=none | |
d7d698f6 TL |
102 | balloon0 => { bus => 0, addr => 3 }, |
103 | watchdog => { bus => 0, addr => 4 }, | |
104 | scsihw0 => { bus => 0, addr => 5, conflict_ok => qw(pci.3) }, | |
105 | 'pci.3' => { bus => 0, addr => 5, conflict_ok => qw(scsihw0) }, # also used for virtio-scsi-single bridge | |
106 | scsihw1 => { bus => 0, addr => 6 }, | |
107 | ahci0 => { bus => 0, addr => 7 }, | |
108 | qga0 => { bus => 0, addr => 8 }, | |
109 | spice => { bus => 0, addr => 9 }, | |
110 | virtio0 => { bus => 0, addr => 10 }, | |
111 | virtio1 => { bus => 0, addr => 11 }, | |
112 | virtio2 => { bus => 0, addr => 12 }, | |
113 | virtio3 => { bus => 0, addr => 13 }, | |
114 | virtio4 => { bus => 0, addr => 14 }, | |
115 | virtio5 => { bus => 0, addr => 15 }, | |
116 | hostpci0 => { bus => 0, addr => 16 }, | |
117 | hostpci1 => { bus => 0, addr => 17 }, | |
118 | net0 => { bus => 0, addr => 18 }, | |
119 | net1 => { bus => 0, addr => 19 }, | |
120 | net2 => { bus => 0, addr => 20 }, | |
121 | net3 => { bus => 0, addr => 21 }, | |
122 | net4 => { bus => 0, addr => 22 }, | |
123 | net5 => { bus => 0, addr => 23 }, | |
124 | vga1 => { bus => 0, addr => 24 }, | |
125 | vga2 => { bus => 0, addr => 25 }, | |
126 | vga3 => { bus => 0, addr => 26 }, | |
127 | hostpci2 => { bus => 0, addr => 27 }, | |
128 | hostpci3 => { bus => 0, addr => 28 }, | |
129 | #addr29 : usb-host (pve-usb.cfg) | |
130 | 'pci.1' => { bus => 0, addr => 30 }, | |
131 | 'pci.2' => { bus => 0, addr => 31 }, | |
132 | 'net6' => { bus => 1, addr => 1 }, | |
133 | 'net7' => { bus => 1, addr => 2 }, | |
134 | 'net8' => { bus => 1, addr => 3 }, | |
135 | 'net9' => { bus => 1, addr => 4 }, | |
136 | 'net10' => { bus => 1, addr => 5 }, | |
137 | 'net11' => { bus => 1, addr => 6 }, | |
138 | 'net12' => { bus => 1, addr => 7 }, | |
139 | 'net13' => { bus => 1, addr => 8 }, | |
140 | 'net14' => { bus => 1, addr => 9 }, | |
141 | 'net15' => { bus => 1, addr => 10 }, | |
142 | 'net16' => { bus => 1, addr => 11 }, | |
143 | 'net17' => { bus => 1, addr => 12 }, | |
144 | 'net18' => { bus => 1, addr => 13 }, | |
145 | 'net19' => { bus => 1, addr => 14 }, | |
146 | 'net20' => { bus => 1, addr => 15 }, | |
147 | 'net21' => { bus => 1, addr => 16 }, | |
148 | 'net22' => { bus => 1, addr => 17 }, | |
149 | 'net23' => { bus => 1, addr => 18 }, | |
150 | 'net24' => { bus => 1, addr => 19 }, | |
151 | 'net25' => { bus => 1, addr => 20 }, | |
152 | 'net26' => { bus => 1, addr => 21 }, | |
153 | 'net27' => { bus => 1, addr => 22 }, | |
154 | 'net28' => { bus => 1, addr => 23 }, | |
155 | 'net29' => { bus => 1, addr => 24 }, | |
156 | 'net30' => { bus => 1, addr => 25 }, | |
157 | 'net31' => { bus => 1, addr => 26 }, | |
158 | 'xhci' => { bus => 1, addr => 27 }, | |
2513b862 | 159 | 'pci.4' => { bus => 1, addr => 28 }, |
2cf61f33 | 160 | 'rng0' => { bus => 1, addr => 29 }, |
13d68979 | 161 | 'pci.2-igd' => { bus => 1, addr => 30 }, # replaces pci.2 in case a legacy IGD device is passed through |
d7d698f6 TL |
162 | 'virtio6' => { bus => 2, addr => 1 }, |
163 | 'virtio7' => { bus => 2, addr => 2 }, | |
164 | 'virtio8' => { bus => 2, addr => 3 }, | |
165 | 'virtio9' => { bus => 2, addr => 4 }, | |
166 | 'virtio10' => { bus => 2, addr => 5 }, | |
167 | 'virtio11' => { bus => 2, addr => 6 }, | |
168 | 'virtio12' => { bus => 2, addr => 7 }, | |
169 | 'virtio13' => { bus => 2, addr => 8 }, | |
170 | 'virtio14' => { bus => 2, addr => 9 }, | |
171 | 'virtio15' => { bus => 2, addr => 10 }, | |
172 | 'ivshmem' => { bus => 2, addr => 11 }, | |
173 | 'audio0' => { bus => 2, addr => 12 }, | |
174 | hostpci4 => { bus => 2, addr => 13 }, | |
175 | hostpci5 => { bus => 2, addr => 14 }, | |
176 | hostpci6 => { bus => 2, addr => 15 }, | |
177 | hostpci7 => { bus => 2, addr => 16 }, | |
178 | hostpci8 => { bus => 2, addr => 17 }, | |
179 | hostpci9 => { bus => 2, addr => 18 }, | |
180 | hostpci10 => { bus => 2, addr => 19 }, | |
181 | hostpci11 => { bus => 2, addr => 20 }, | |
182 | hostpci12 => { bus => 2, addr => 21 }, | |
183 | hostpci13 => { bus => 2, addr => 22 }, | |
184 | hostpci14 => { bus => 2, addr => 23 }, | |
185 | hostpci15 => { bus => 2, addr => 24 }, | |
186 | 'virtioscsi0' => { bus => 3, addr => 1 }, | |
187 | 'virtioscsi1' => { bus => 3, addr => 2 }, | |
188 | 'virtioscsi2' => { bus => 3, addr => 3 }, | |
189 | 'virtioscsi3' => { bus => 3, addr => 4 }, | |
190 | 'virtioscsi4' => { bus => 3, addr => 5 }, | |
191 | 'virtioscsi5' => { bus => 3, addr => 6 }, | |
192 | 'virtioscsi6' => { bus => 3, addr => 7 }, | |
193 | 'virtioscsi7' => { bus => 3, addr => 8 }, | |
194 | 'virtioscsi8' => { bus => 3, addr => 9 }, | |
195 | 'virtioscsi9' => { bus => 3, addr => 10 }, | |
196 | 'virtioscsi10' => { bus => 3, addr => 11 }, | |
197 | 'virtioscsi11' => { bus => 3, addr => 12 }, | |
198 | 'virtioscsi12' => { bus => 3, addr => 13 }, | |
199 | 'virtioscsi13' => { bus => 3, addr => 14 }, | |
200 | 'virtioscsi14' => { bus => 3, addr => 15 }, | |
201 | 'virtioscsi15' => { bus => 3, addr => 16 }, | |
202 | 'virtioscsi16' => { bus => 3, addr => 17 }, | |
203 | 'virtioscsi17' => { bus => 3, addr => 18 }, | |
204 | 'virtioscsi18' => { bus => 3, addr => 19 }, | |
205 | 'virtioscsi19' => { bus => 3, addr => 20 }, | |
206 | 'virtioscsi20' => { bus => 3, addr => 21 }, | |
207 | 'virtioscsi21' => { bus => 3, addr => 22 }, | |
208 | 'virtioscsi22' => { bus => 3, addr => 23 }, | |
209 | 'virtioscsi23' => { bus => 3, addr => 24 }, | |
210 | 'virtioscsi24' => { bus => 3, addr => 25 }, | |
211 | 'virtioscsi25' => { bus => 3, addr => 26 }, | |
212 | 'virtioscsi26' => { bus => 3, addr => 27 }, | |
213 | 'virtioscsi27' => { bus => 3, addr => 28 }, | |
214 | 'virtioscsi28' => { bus => 3, addr => 29 }, | |
215 | 'virtioscsi29' => { bus => 3, addr => 30 }, | |
216 | 'virtioscsi30' => { bus => 3, addr => 31 }, | |
2513b862 DC |
217 | 'scsihw2' => { bus => 4, addr => 1 }, |
218 | 'scsihw3' => { bus => 4, addr => 2 }, | |
219 | 'scsihw4' => { bus => 4, addr => 3 }, | |
d7d698f6 TL |
220 | } if !defined($pci_addr_map); |
221 | return $pci_addr_map; | |
222 | } | |
223 | ||
224 | my $get_addr_mapping_from_id = sub { | |
225 | my ($map, $id) = @_; | |
226 | ||
227 | my $d = $map->{$id}; | |
228 | return undef if !defined($d) || !defined($d->{bus}) || !defined($d->{addr}); | |
229 | ||
230 | return { bus => $d->{bus}, addr => sprintf("0x%x", $d->{addr}) }; | |
de9768f0 DC |
231 | }; |
232 | ||
233 | sub print_pci_addr { | |
d559309f | 234 | my ($id, $bridges, $arch, $machine) = @_; |
de9768f0 DC |
235 | |
236 | my $res = ''; | |
237 | ||
d7d698f6 | 238 | # using same bus slots on all HW, so we need to check special cases here: |
d559309f WB |
239 | my $busname = 'pci'; |
240 | if ($arch eq 'aarch64' && $machine =~ /^virt/) { | |
d7d698f6 | 241 | die "aarch64/virt cannot use IDE devices\n" if $id =~ /^ide/; |
d559309f WB |
242 | $busname = 'pcie'; |
243 | } | |
244 | ||
d7d698f6 TL |
245 | my $map = get_pci_addr_map(); |
246 | if (my $d = $get_addr_mapping_from_id->($map, $id)) { | |
247 | $res = ",bus=$busname.$d->{bus},addr=$d->{addr}"; | |
248 | $bridges->{$d->{bus}} = 1 if $bridges; | |
de9768f0 | 249 | } |
de9768f0 | 250 | |
d7d698f6 | 251 | return $res; |
de9768f0 DC |
252 | } |
253 | ||
d7d698f6 TL |
254 | my $pcie_addr_map; |
255 | sub get_pcie_addr_map { | |
256 | $pcie_addr_map = { | |
55655ebc | 257 | vga => { bus => 'pcie.0', addr => 1 }, |
de9768f0 DC |
258 | hostpci0 => { bus => "ich9-pcie-port-1", addr => 0 }, |
259 | hostpci1 => { bus => "ich9-pcie-port-2", addr => 0 }, | |
260 | hostpci2 => { bus => "ich9-pcie-port-3", addr => 0 }, | |
261 | hostpci3 => { bus => "ich9-pcie-port-4", addr => 0 }, | |
c4e16381 AL |
262 | hostpci4 => { bus => "ich9-pcie-port-5", addr => 0 }, |
263 | hostpci5 => { bus => "ich9-pcie-port-6", addr => 0 }, | |
264 | hostpci6 => { bus => "ich9-pcie-port-7", addr => 0 }, | |
265 | hostpci7 => { bus => "ich9-pcie-port-8", addr => 0 }, | |
266 | hostpci8 => { bus => "ich9-pcie-port-9", addr => 0 }, | |
267 | hostpci9 => { bus => "ich9-pcie-port-10", addr => 0 }, | |
268 | hostpci10 => { bus => "ich9-pcie-port-11", addr => 0 }, | |
269 | hostpci11 => { bus => "ich9-pcie-port-12", addr => 0 }, | |
270 | hostpci12 => { bus => "ich9-pcie-port-13", addr => 0 }, | |
271 | hostpci13 => { bus => "ich9-pcie-port-14", addr => 0 }, | |
272 | hostpci14 => { bus => "ich9-pcie-port-15", addr => 0 }, | |
273 | hostpci15 => { bus => "ich9-pcie-port-16", addr => 0 }, | |
739ba340 DC |
274 | # win7 is picky about pcie assignments |
275 | hostpci0bus0 => { bus => "pcie.0", addr => 16 }, | |
276 | hostpci1bus0 => { bus => "pcie.0", addr => 17 }, | |
277 | hostpci2bus0 => { bus => "pcie.0", addr => 18 }, | |
278 | hostpci3bus0 => { bus => "pcie.0", addr => 19 }, | |
6dbcb073 | 279 | ivshmem => { bus => 'pcie.0', addr => 20 }, |
c4e16381 AL |
280 | hostpci4bus0 => { bus => "pcie.0", addr => 9 }, |
281 | hostpci5bus0 => { bus => "pcie.0", addr => 10 }, | |
282 | hostpci6bus0 => { bus => "pcie.0", addr => 11 }, | |
283 | hostpci7bus0 => { bus => "pcie.0", addr => 12 }, | |
284 | hostpci8bus0 => { bus => "pcie.0", addr => 13 }, | |
285 | hostpci9bus0 => { bus => "pcie.0", addr => 14 }, | |
286 | hostpci10bus0 => { bus => "pcie.0", addr => 15 }, | |
e2b0d85d TL |
287 | hostpci11bus0 => { bus => "pcie.0", addr => 21 }, |
288 | hostpci12bus0 => { bus => "pcie.0", addr => 22 }, | |
289 | hostpci13bus0 => { bus => "pcie.0", addr => 23 }, | |
290 | hostpci14bus0 => { bus => "pcie.0", addr => 24 }, | |
291 | hostpci15bus0 => { bus => "pcie.0", addr => 25 }, | |
d7d698f6 TL |
292 | } if !defined($pcie_addr_map); |
293 | ||
294 | return $pcie_addr_map; | |
295 | } | |
296 | ||
297 | sub print_pcie_addr { | |
298 | my ($id) = @_; | |
299 | ||
300 | my $res = ''; | |
de9768f0 | 301 | |
d7d698f6 TL |
302 | my $map = get_pcie_addr_map($id); |
303 | if (my $d = $get_addr_mapping_from_id->($map, $id)) { | |
304 | $res = ",bus=$d->{bus},addr=$d->{addr}"; | |
de9768f0 | 305 | } |
de9768f0 | 306 | |
d7d698f6 | 307 | return $res; |
de9768f0 | 308 | } |
b71351a7 | 309 | |
c4e16381 AL |
310 | # Generates the device strings for additional pcie root ports. The first 4 pcie |
311 | # root ports are defined in the pve-q35*.cfg files. | |
312 | sub print_pcie_root_port { | |
313 | my ($i) = @_; | |
314 | my $res = ''; | |
315 | ||
c4e16381 | 316 | my $root_port_addresses = { |
e2b0d85d TL |
317 | 4 => "10.0", |
318 | 5 => "10.1", | |
319 | 6 => "10.2", | |
320 | 7 => "10.3", | |
321 | 8 => "10.4", | |
322 | 9 => "10.5", | |
c4e16381 AL |
323 | 10 => "10.6", |
324 | 11 => "10.7", | |
325 | 12 => "11.0", | |
326 | 13 => "11.1", | |
327 | 14 => "11.2", | |
328 | 15 => "11.3", | |
329 | }; | |
330 | ||
331 | if (defined($root_port_addresses->{$i})) { | |
e2b0d85d | 332 | my $id = $i + 1; |
c4e16381 AL |
333 | $res = "pcie-root-port,id=ich9-pcie-port-${id}"; |
334 | $res .= ",addr=$root_port_addresses->{$i}"; | |
335 | $res .= ",x-speed=16,x-width=32,multifunction=on,bus=pcie.0"; | |
336 | $res .= ",port=${id},chassis=${id}"; | |
337 | } | |
338 | ||
339 | return $res; | |
340 | } | |
341 | ||
74c17b7a SR |
342 | sub parse_hostpci { |
343 | my ($value) = @_; | |
344 | ||
345 | return undef if !$value; | |
346 | ||
347 | my $res = PVE::JSONSchema::parse_property_string($hostpci_fmt, $value); | |
348 | ||
349 | my @idlist = split(/;/, $res->{host}); | |
350 | delete $res->{host}; | |
351 | foreach my $id (@idlist) { | |
352 | my $devs = PVE::SysFSTools::lspci($id); | |
353 | die "no PCI device found for '$id'\n" if !scalar(@$devs); | |
354 | push @{$res->{pciid}}, @$devs; | |
355 | } | |
356 | return $res; | |
357 | } | |
358 | ||
359 | sub print_hostpci_devices { | |
7de7f675 | 360 | my ($vmid, $conf, $devices, $winversion, $q35, $bridges, $arch, $machine_type) = @_; |
74c17b7a SR |
361 | |
362 | my $kvm_off = 0; | |
363 | my $gpu_passthrough = 0; | |
13d68979 | 364 | my $legacy_igd = 0; |
74c17b7a SR |
365 | |
366 | for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) { | |
367 | my $id = "hostpci$i"; | |
368 | my $d = parse_hostpci($conf->{$id}); | |
369 | next if !$d; | |
370 | ||
371 | if (my $pcie = $d->{pcie}) { | |
372 | die "q35 machine model is not enabled" if !$q35; | |
373 | # win7 wants to have the pcie devices directly on the pcie bus | |
374 | # instead of in the root port | |
375 | if ($winversion == 7) { | |
376 | $pciaddr = print_pcie_addr("${id}bus0"); | |
377 | } else { | |
378 | # add more root ports if needed, 4 are present by default | |
379 | # by pve-q35 cfgs, rest added here on demand. | |
380 | if ($i > 3) { | |
381 | push @$devices, '-device', print_pcie_root_port($i); | |
382 | } | |
383 | $pciaddr = print_pcie_addr($id); | |
384 | } | |
385 | } else { | |
13d68979 SR |
386 | my $pci_name = $d->{'legacy-igd'} ? 'legacy-igd' : $id; |
387 | $pciaddr = print_pci_addr($pci_name, $bridges, $arch, $machine_type); | |
388 | } | |
389 | ||
390 | my $pcidevices = $d->{pciid}; | |
391 | my $multifunction = 1 if @$pcidevices > 1; | |
392 | ||
393 | if ($d->{'legacy-igd'}) { | |
394 | die "only one device can be assigned in legacy-igd mode\n" | |
395 | if $legacy_igd; | |
396 | $legacy_igd = 1; | |
397 | ||
398 | die "legacy IGD assignment requires VGA mode to be 'none'\n" | |
399 | if !defined($conf->{'vga'}) || $conf->{'vga'} ne 'none'; | |
400 | die "legacy IGD assignment requires rombar to be enabled\n" | |
401 | if defined($d->{rombar}) && !$d->{rombar}; | |
402 | die "legacy IGD assignment is not compatible with x-vga\n" | |
403 | if $d->{'x-vga'}; | |
404 | die "legacy IGD assignment is not compatible with mdev\n" | |
405 | if $d->{mdev}; | |
406 | die "legacy IGD assignment is not compatible with q35\n" | |
407 | if $q35; | |
408 | die "legacy IGD assignment is not compatible with multifunction devices\n" | |
409 | if $multifunction; | |
410 | die "legacy IGD assignment only works for devices on host bus 00:02.0\n" | |
411 | if $pcidevices->[0]->{id} !~ m/02\.0$/; | |
74c17b7a SR |
412 | } |
413 | ||
414 | my $xvga = ''; | |
415 | if ($d->{'x-vga'}) { | |
416 | $xvga = ',x-vga=on' if !($conf->{bios} && $conf->{bios} eq 'ovmf'); | |
417 | $kvm_off = 1; | |
418 | $vga->{type} = 'none' if !defined($conf->{vga}); | |
419 | $gpu_passthrough = 1; | |
420 | } | |
421 | ||
74c17b7a SR |
422 | my $sysfspath; |
423 | if ($d->{mdev} && scalar(@$pcidevices) == 1) { | |
424 | my $pci_id = $pcidevices->[0]->{id}; | |
425 | my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i); | |
426 | $sysfspath = "/sys/bus/pci/devices/$pci_id/$uuid"; | |
427 | } elsif ($d->{mdev}) { | |
428 | warn "ignoring mediated device '$id' with multifunction device\n"; | |
429 | } | |
430 | ||
1fac3a0b | 431 | my $j = 0; |
74c17b7a SR |
432 | foreach my $pcidevice (@$pcidevices) { |
433 | my $devicestr = "vfio-pci"; | |
434 | ||
435 | if ($sysfspath) { | |
436 | $devicestr .= ",sysfsdev=$sysfspath"; | |
437 | } else { | |
438 | $devicestr .= ",host=$pcidevice->{id}"; | |
439 | } | |
440 | ||
441 | my $mf_addr = $multifunction ? ".$j" : ''; | |
442 | $devicestr .= ",id=${id}${mf_addr}${pciaddr}${mf_addr}"; | |
443 | ||
444 | if ($j == 0) { | |
445 | $devicestr .= ',rombar=0' if defined($d->{rombar}) && !$d->{rombar}; | |
446 | $devicestr .= "$xvga"; | |
447 | $devicestr .= ",multifunction=on" if $multifunction; | |
448 | $devicestr .= ",romfile=/usr/share/kvm/$d->{romfile}" if $d->{romfile}; | |
449 | } | |
450 | ||
451 | push @$devices, '-device', $devicestr; | |
452 | $j++; | |
453 | } | |
454 | } | |
455 | ||
13d68979 | 456 | return ($kvm_off, $gpu_passthrough, $legacy_igd); |
74c17b7a SR |
457 | } |
458 | ||
b71351a7 | 459 | 1; |