]> git.proxmox.com Git - pve-manager.git/blame - www/manager6/qemu/PCIEdit.js
ui: pci passthrough: editor for pci-id overrides
[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
DC
5
6 setVMConfig: function(vmconfig) {
7 var me = this;
8 me.vmconfig = vmconfig;
9
10 var hostpci = me.vmconfig[me.confid] || '';
11
12 var values = PVE.Parser.parsePropertyString(hostpci, 'host');
5b23d683
SR
13 if (values.host) {
14 if (!values.host.match(/^[0-9a-f]{4}:/i)) { // add optional domain
15 values.host = "0000:" + values.host;
16 }
17 if (values.host.length < 11) { // 0000:00:00 format not 0000:00:00.0
18 values.host += ".0";
19 values.multifunction = true;
20 }
c59fb4ee 21 }
5b23d683 22
c59fb4ee
DC
23 values['x-vga'] = PVE.Parser.parseBoolean(values['x-vga'], 0);
24 values.pcie = PVE.Parser.parseBoolean(values.pcie, 0);
25 values.rombar = PVE.Parser.parseBoolean(values.rombar, 1);
26
27 me.setValues(values);
28 if (!me.vmconfig.machine || me.vmconfig.machine.indexOf('q35') === -1) {
29 // machine is not set to some variant of q35, so we disable pcie
30 var pcie = me.down('field[name=pcie]');
31 pcie.setDisabled(true);
32 pcie.setBoxLabel(gettext('Q35 only'));
33 }
34
35 if (values.romfile) {
36 me.down('field[name=romfile]').setVisible(true);
37 }
38 },
39
40 onGetValues: function(values) {
a7ec3666 41 let me = this;
8058410f 42 if (!me.confid) {
a7ec3666 43 for (let i = 0; i < 5; i++) {
8058410f 44 if (!me.vmconfig['hostpci' + i.toString()]) {
c59fb4ee
DC
45 me.confid = 'hostpci' + i.toString();
46 break;
47 }
48 }
a7ec3666 49 // FIXME: what if no confid was found??
c59fb4ee 50 }
a7ec3666
TL
51 values.host.replace(/^0000:/, ''); // remove optional '0000' domain
52
c59fb4ee 53 if (values.multifunction) {
a7ec3666 54 values.host = values.host.substring(0, values.host.indexOf('.')); // skip the '.X'
c59fb4ee
DC
55 delete values.multifunction;
56 }
57
58 if (values.rombar) {
59 delete values.rombar;
60 } else {
61 values.rombar = 0;
62 }
63
2b25a905
DC
64 if (!values.romfile) {
65 delete values.romfile;
66 }
67
a7ec3666 68 let ret = {};
c59fb4ee
DC
69 ret[me.confid] = PVE.Parser.printPropertyString(values, 'host');
70 return ret;
71 },
72
73 initComponent: function() {
a7ec3666 74 let me = this;
c59fb4ee
DC
75
76 me.nodename = me.pveSelNode.data.node;
77 if (!me.nodename) {
78 throw "no node name specified";
79 }
80
81 me.column1 = [
82 {
83 xtype: 'pvePCISelector',
84 fieldLabel: gettext('Device'),
85 name: 'host',
86 nodename: me.nodename,
87 allowBlank: false,
88 onLoadCallBack: function(store, records, success) {
89 if (!success || !records.length) {
90 return;
91 }
a7ec3666
TL
92 if (records.every((val) => val.data.iommugroup === -1)) { // no IOMMU groups
93 let warning = Ext.create('Ext.form.field.Display', {
c59fb4ee
DC
94 columnWidth: 1,
95 padding: '0 0 10 0',
96 value: 'No IOMMU detected, please activate it.' +
97 'See Documentation for further information.',
f6710aac 98 userCls: 'pmx-hint',
c59fb4ee
DC
99 });
100 me.items.insert(0, warning);
101 me.updateLayout(); // insert does not trigger that
102 }
103 },
104 listeners: {
105 change: function(pcisel, value) {
106 if (!value) {
107 return;
108 }
a7ec3666
TL
109 let pciDev = pcisel.getStore().getById(value);
110 let mdevfield = me.down('field[name=mdev]');
111 mdevfield.setDisabled(!pciDev || !pciDev.data.mdev);
112 if (!pciDev) {
c59fb4ee
DC
113 return;
114 }
a7ec3666 115 if (pciDev.data.mdev) {
c59fb4ee
DC
116 mdevfield.setPciID(value);
117 }
a7ec3666
TL
118 let iommu = pciDev.data.iommugroup;
119 if (iommu === -1) {
120 return;
121 }
122 // try to find out if there are more devices in that iommu group
123 let id = pciDev.data.id.substring(0, 5); // 00:00
124 let count = 0;
125 pcisel.getStore().each(({ data }) => {
126 if (data.iommugroup === iommu && data.id.substring(0, 5) !== id) {
127 count++;
128 return false;
129 }
130 return true;
131 });
132 let warning = me.down('#iommuwarning');
133 if (count && !warning) {
134 warning = Ext.create('Ext.form.field.Display', {
135 columnWidth: 1,
136 padding: '0 0 10 0',
137 itemId: 'iommuwarning',
138 value: 'The selected Device is not in a seperate IOMMU group, make sure this is intended.',
139 userCls: 'pmx-hint',
140 });
141 me.items.insert(0, warning);
142 me.updateLayout(); // insert does not trigger that
143 } else if (!count && warning) {
144 me.remove(warning);
145 }
f6710aac
TL
146 },
147 },
c59fb4ee
DC
148 },
149 {
150 xtype: 'proxmoxcheckbox',
151 fieldLabel: gettext('All Functions'),
f6710aac
TL
152 name: 'multifunction',
153 },
c59fb4ee
DC
154 ];
155
156 me.column2 = [
157 {
158 xtype: 'pveMDevSelector',
159 name: 'mdev',
160 disabled: true,
161 fieldLabel: gettext('MDev Type'),
162 nodename: me.nodename,
163 listeners: {
164 change: function(field, value) {
a7ec3666 165 let multiFunction = me.down('field[name=multifunction]');
d2021707 166 if (value) {
a7ec3666 167 multiFunction.setValue(false);
c59fb4ee 168 }
a7ec3666 169 multiFunction.setDisabled(!!value);
f6710aac
TL
170 },
171 },
c59fb4ee
DC
172 },
173 {
174 xtype: 'proxmoxcheckbox',
175 fieldLabel: gettext('Primary GPU'),
f6710aac
TL
176 name: 'x-vga',
177 },
c59fb4ee
DC
178 ];
179
180 me.advancedColumn1 = [
181 {
182 xtype: 'proxmoxcheckbox',
183 fieldLabel: 'ROM-Bar',
f6710aac 184 name: 'rombar',
c59fb4ee
DC
185 },
186 {
187 xtype: 'displayfield',
188 submitValue: true,
189 hidden: true,
190 fieldLabel: 'ROM-File',
f6710aac
TL
191 name: 'romfile',
192 },
9a9be673
NS
193 {
194 xtype: 'textfield',
195 name: 'vendor-id',
196 fieldLabel: gettext('Set vendor ID'),
197 vtype: 'PciId',
198 allowBlank: true,
199 emptyText: Proxmox.Utils.defaultText,
200 submitEmpty: false,
201 },
202 {
203 xtype: 'textfield',
204 name: 'device-id',
205 fieldLabel: gettext('Set device ID'),
206 vtype: 'PciId',
207 allowBlank: true,
208 emptyText: Proxmox.Utils.defaultText,
209 submitEmpty: false,
210 },
c59fb4ee
DC
211 ];
212
213 me.advancedColumn2 = [
214 {
215 xtype: 'proxmoxcheckbox',
216 fieldLabel: 'PCI-Express',
f6710aac
TL
217 name: 'pcie',
218 },
9a9be673
NS
219 {
220 xtype: 'textfield',
221 name: 'sub-vendor-id',
222 fieldLabel: gettext('Set sub-vendor ID'),
223 vtype: 'PciId',
224 allowBlank: true,
225 emptyText: Proxmox.Utils.defaultText,
226 submitEmpty: false,
227 },
228 {
229 xtype: 'textfield',
230 name: 'sub-device-id',
231 fieldLabel: gettext('Set sub-device ID'),
232 vtype: 'PciId',
233 allowBlank: true,
234 emptyText: Proxmox.Utils.defaultText,
235 submitEmpty: false,
236 },
c59fb4ee
DC
237 ];
238
239 me.callParent();
f6710aac 240 },
c59fb4ee
DC
241});
242
243Ext.define('PVE.qemu.PCIEdit', {
244 extend: 'Proxmox.window.Edit',
245
c59fb4ee
DC
246 subject: gettext('PCI Device'),
247
a7ec3666
TL
248 vmconfig: undefined,
249 isAdd: true,
c59fb4ee 250
8058410f 251 initComponent: function() {
a7ec3666 252 let me = this;
c59fb4ee
DC
253
254 me.isCreate = !me.confid;
255
a7ec3666 256 let ipanel = Ext.create('PVE.qemu.PCIInputPanel', {
c59fb4ee 257 confid: me.confid,
f6710aac 258 pveSelNode: me.pveSelNode,
c59fb4ee
DC
259 });
260
261 Ext.apply(me, {
8058410f 262 items: [ipanel],
c59fb4ee
DC
263 });
264
265 me.callParent();
266
267 me.load({
a7ec3666 268 success: ({ result }) => ipanel.setVMConfig(result.data),
c59fb4ee 269 });
f6710aac 270 },
c59fb4ee 271});