]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/qemu/PCIEdit.js
update shipped appliance info index
[pve-manager.git] / www / manager6 / qemu / PCIEdit.js
CommitLineData
c59fb4ee
DC
1Ext.define('PVE.qemu.PCIInputPanel', {
2 extend: 'Proxmox.panel.InputPanel',
3
4f0d4294 4 onlineHelp: 'qm_pci_passthrough_vm_config',
c59fb4ee 5
b1d42186
DC
6 controller: {
7 xclass: 'Ext.app.ViewController',
8
9 setVMConfig: function(vmconfig) {
10 let me = this;
11 let view = me.getView();
12 me.vmconfig = vmconfig;
c59fb4ee 13
b1d42186 14 let hostpci = me.vmconfig[view.confid] || '';
c59fb4ee 15
b1d42186
DC
16 let values = PVE.Parser.parsePropertyString(hostpci, 'host');
17 if (values.host) {
18 if (!values.host.match(/^[0-9a-f]{4}:/i)) { // add optional domain
19 values.host = "0000:" + values.host;
20 }
21 if (values.host.length < 11) { // 0000:00:00 format not 0000:00:00.0
22 values.host += ".0";
23 values.multifunction = true;
24 }
25 values.type = 'raw';
26 } else if (values.mapping) {
27 values.type = 'mapped';
5b23d683 28 }
b1d42186
DC
29
30 values['x-vga'] = PVE.Parser.parseBoolean(values['x-vga'], 0);
31 values.pcie = PVE.Parser.parseBoolean(values.pcie, 0);
32 values.rombar = PVE.Parser.parseBoolean(values.rombar, 1);
33
34 view.setValues(values);
35 if (!me.vmconfig.machine || me.vmconfig.machine.indexOf('q35') === -1) {
36 // machine is not set to some variant of q35, so we disable pcie
37 let pcie = me.lookup('pcie');
38 pcie.setDisabled(true);
39 pcie.setBoxLabel(gettext('Q35 only'));
5b23d683 40 }
5b23d683 41
b1d42186
DC
42 if (values.romfile) {
43 me.lookup('romfile').setVisible(true);
44 }
45 },
c59fb4ee 46
b1d42186
DC
47 selectorEnable: function(selector) {
48 let me = this;
49 me.pciDevChange(selector, selector.getValue());
50 },
c59fb4ee 51
b1d42186
DC
52 pciDevChange: function(pcisel, value) {
53 let me = this;
54 let mdevfield = me.lookup('mdev');
55 if (!value) {
56 if (!pcisel.isDisabled()) {
57 mdevfield.setDisabled(true);
58 }
59 return;
60 }
61 let pciDev = pcisel.getStore().getById(value);
c59fb4ee 62
b1d42186
DC
63 mdevfield.setDisabled(!pciDev || !pciDev.data.mdev);
64 if (!pciDev) {
65 return;
66 }
67
68 let path = value;
69 if (pciDev.data.map) {
70 // find local mapping
71 for (const entry of pciDev.data.map) {
72 let mapping = PVE.Parser.parsePropertyString(entry);
73 if (mapping.node === pcisel.up('inputpanel').nodename) {
74 path = mapping.path.split(';')[0];
75 break;
76 }
77 }
78 if (path.indexOf('.') === -1) {
79 path += '.0';
c59fb4ee
DC
80 }
81 }
a7ec3666 82
b1d42186
DC
83 if (pciDev.data.mdev) {
84 mdevfield.setPciID(path);
85 }
86 if (pcisel.reference === 'selector') {
87 let iommu = pciDev.data.iommugroup;
88 if (iommu === -1) {
89 return;
90 }
91 // try to find out if there are more devices in that iommu group
92 let id = path.substring(0, 5); // 00:00
93 let count = 0;
94 pcisel.getStore().each(({ data }) => {
95 if (data.iommugroup === iommu && data.id.substring(0, 5) !== id) {
96 count++;
97 return false;
98 }
99 return true;
100 });
101 me.lookup('group_warning').setVisible(count > 0);
102 }
103 },
c59fb4ee 104
b1d42186
DC
105 onGetValues: function(values) {
106 let me = this;
107 let view = me.getView();
108 if (!view.confid) {
109 for (let i = 0; i < PVE.Utils.hardware_counts.hostpci; i++) {
110 if (!me.vmconfig['hostpci' + i.toString()]) {
111 view.confid = 'hostpci' + i.toString();
112 break;
113 }
114 }
115 // FIXME: what if no confid was found??
116 }
c59fb4ee 117
b1d42186 118 values.host?.replace(/^0000:/, ''); // remove optional '0000' domain
2b25a905 119
b1d42186
DC
120 if (values.multifunction && values.host) {
121 values.host = values.host.substring(0, values.host.indexOf('.')); // skip the '.X'
122 delete values.multifunction;
123 }
124
125 if (values.rombar) {
126 delete values.rombar;
127 } else {
128 values.rombar = 0;
129 }
130
131 if (!values.romfile) {
132 delete values.romfile;
133 }
134
135 delete values.type;
136
137 let ret = {};
138 ret[view.confid] = PVE.Parser.printPropertyString(values, 'host');
139 return ret;
140 },
141 },
142
143 viewModel: {
144 data: {
145 isMapped: true,
146 },
147 },
148
149 setVMConfig: function(vmconfig) {
150 return this.getController().setVMConfig(vmconfig);
151 },
152
153 onGetValues: function(values) {
154 return this.getController().onGetValues(values);
c59fb4ee
DC
155 },
156
157 initComponent: function() {
a7ec3666 158 let me = this;
c59fb4ee
DC
159
160 me.nodename = me.pveSelNode.data.node;
161 if (!me.nodename) {
162 throw "no node name specified";
163 }
164
b1d42186
DC
165 me.columnT = [
166 {
167 xtype: 'displayfield',
168 reference: 'iommu_warning',
169 hidden: true,
170 columnWidth: 1,
171 padding: '0 0 10 0',
172 value: 'No IOMMU detected, please activate it.' +
173 'See Documentation for further information.',
174 userCls: 'pmx-hint',
175 },
176 {
177 xtype: 'displayfield',
178 reference: 'group_warning',
179 hidden: true,
180 columnWidth: 1,
181 padding: '0 0 10 0',
182 itemId: 'iommuwarning',
183 value: 'The selected Device is not in a seperate IOMMU group, make sure this is intended.',
184 userCls: 'pmx-hint',
185 },
186 ];
187
c59fb4ee 188 me.column1 = [
b1d42186
DC
189 {
190 xtype: 'radiofield',
191 name: 'type',
192 inputValue: 'mapped',
193 boxLabel: gettext('Mapped Device'),
194 bind: {
195 value: '{isMapped}',
196 },
197 },
198 {
199 xtype: 'pvePCIMapSelector',
200 fieldLabel: gettext('Device'),
201 reference: 'mapped_selector',
202 name: 'mapping',
203 labelAlign: 'right',
204 nodename: me.nodename,
205 allowBlank: false,
206 bind: {
207 disabled: '{!isMapped}',
208 },
209 listeners: {
210 change: 'pciDevChange',
211 enable: 'selectorEnable',
212 },
213 },
214 {
215 xtype: 'radiofield',
216 name: 'type',
217 inputValue: 'raw',
218 checked: true,
219 boxLabel: gettext('Raw Device'),
220 },
c59fb4ee
DC
221 {
222 xtype: 'pvePCISelector',
223 fieldLabel: gettext('Device'),
224 name: 'host',
b1d42186 225 reference: 'selector',
c59fb4ee 226 nodename: me.nodename,
b1d42186 227 labelAlign: 'right',
c59fb4ee 228 allowBlank: false,
b1d42186
DC
229 disabled: true,
230 bind: {
231 disabled: '{isMapped}',
232 },
c59fb4ee
DC
233 onLoadCallBack: function(store, records, success) {
234 if (!success || !records.length) {
235 return;
236 }
b1d42186
DC
237 me.lookup('iommu_warning').setVisible(
238 records.every((val) => val.data.iommugroup === -1),
239 );
c59fb4ee
DC
240 },
241 listeners: {
b1d42186
DC
242 change: 'pciDevChange',
243 enable: 'selectorEnable',
f6710aac 244 },
c59fb4ee
DC
245 },
246 {
247 xtype: 'proxmoxcheckbox',
248 fieldLabel: gettext('All Functions'),
b1d42186
DC
249 reference: 'all_functions',
250 disabled: true,
251 labelAlign: 'right',
f6710aac 252 name: 'multifunction',
b1d42186
DC
253 bind: {
254 disabled: '{isMapped}',
255 },
f6710aac 256 },
c59fb4ee
DC
257 ];
258
259 me.column2 = [
260 {
261 xtype: 'pveMDevSelector',
262 name: 'mdev',
b1d42186 263 reference: 'mdev',
c59fb4ee
DC
264 disabled: true,
265 fieldLabel: gettext('MDev Type'),
266 nodename: me.nodename,
267 listeners: {
268 change: function(field, value) {
a7ec3666 269 let multiFunction = me.down('field[name=multifunction]');
d2021707 270 if (value) {
a7ec3666 271 multiFunction.setValue(false);
c59fb4ee 272 }
a7ec3666 273 multiFunction.setDisabled(!!value);
f6710aac
TL
274 },
275 },
c59fb4ee
DC
276 },
277 {
278 xtype: 'proxmoxcheckbox',
279 fieldLabel: gettext('Primary GPU'),
f6710aac
TL
280 name: 'x-vga',
281 },
c59fb4ee
DC
282 ];
283
284 me.advancedColumn1 = [
285 {
286 xtype: 'proxmoxcheckbox',
287 fieldLabel: 'ROM-Bar',
f6710aac 288 name: 'rombar',
c59fb4ee
DC
289 },
290 {
291 xtype: 'displayfield',
292 submitValue: true,
293 hidden: true,
294 fieldLabel: 'ROM-File',
b1d42186 295 reference: 'romfile',
f6710aac
TL
296 name: 'romfile',
297 },
9a9be673
NS
298 {
299 xtype: 'textfield',
300 name: 'vendor-id',
d20113ef
TL
301 fieldLabel: Ext.String.format(gettext('{0} ID'), gettext('Vendor')),
302 emptyText: gettext('From Device'),
9a9be673
NS
303 vtype: 'PciId',
304 allowBlank: true,
9a9be673
NS
305 submitEmpty: false,
306 },
307 {
308 xtype: 'textfield',
309 name: 'device-id',
d20113ef
TL
310 fieldLabel: Ext.String.format(gettext('{0} ID'), gettext('Device')),
311 emptyText: gettext('From Device'),
9a9be673
NS
312 vtype: 'PciId',
313 allowBlank: true,
9a9be673
NS
314 submitEmpty: false,
315 },
c59fb4ee
DC
316 ];
317
318 me.advancedColumn2 = [
319 {
320 xtype: 'proxmoxcheckbox',
321 fieldLabel: 'PCI-Express',
b1d42186 322 reference: 'pcie',
f6710aac
TL
323 name: 'pcie',
324 },
9a9be673
NS
325 {
326 xtype: 'textfield',
327 name: 'sub-vendor-id',
d20113ef
TL
328 fieldLabel: Ext.String.format(gettext('{0} ID'), gettext('Sub-Vendor')),
329 emptyText: gettext('From Device'),
9a9be673
NS
330 vtype: 'PciId',
331 allowBlank: true,
9a9be673
NS
332 submitEmpty: false,
333 },
334 {
335 xtype: 'textfield',
336 name: 'sub-device-id',
d20113ef
TL
337 fieldLabel: Ext.String.format(gettext('{0} ID'), gettext('Sub-Device')),
338 emptyText: gettext('From Device'),
9a9be673
NS
339 vtype: 'PciId',
340 allowBlank: true,
9a9be673
NS
341 submitEmpty: false,
342 },
c59fb4ee
DC
343 ];
344
345 me.callParent();
f6710aac 346 },
c59fb4ee
DC
347});
348
349Ext.define('PVE.qemu.PCIEdit', {
350 extend: 'Proxmox.window.Edit',
351
c59fb4ee
DC
352 subject: gettext('PCI Device'),
353
a7ec3666
TL
354 vmconfig: undefined,
355 isAdd: true,
c59fb4ee 356
8058410f 357 initComponent: function() {
a7ec3666 358 let me = this;
c59fb4ee
DC
359
360 me.isCreate = !me.confid;
361
a7ec3666 362 let ipanel = Ext.create('PVE.qemu.PCIInputPanel', {
c59fb4ee 363 confid: me.confid,
f6710aac 364 pveSelNode: me.pveSelNode,
c59fb4ee
DC
365 });
366
367 Ext.apply(me, {
8058410f 368 items: [ipanel],
c59fb4ee
DC
369 });
370
371 me.callParent();
372
373 me.load({
a7ec3666 374 success: ({ result }) => ipanel.setVMConfig(result.data),
c59fb4ee 375 });
f6710aac 376 },
c59fb4ee 377});