Skip to content

Commit 2c269f4

Browse files
marmarekjgross1
authored andcommitted
xen-pciback: Consider INTx disabled when MSI/MSI-X is enabled
Linux enables MSI-X before disabling INTx, but keeps MSI-X masked until the table is filled. Then it disables INTx just before clearing MASKALL bit. Currently this approach is rejected by xen-pciback. According to the PCIe spec, device cannot use INTx when MSI/MSI-X is enabled (in other words: enabling MSI/MSI-X implicitly disables INTx). Change the logic to consider INTx disabled if MSI/MSI-X is enabled. This applies to three places: - checking currently enabled interrupts type, - transition to MSI/MSI-X - where INTx would be implicitly disabled, - clearing INTx disable bit - which can be allowed even if MSI/MSI-X is enabled, as device should consider INTx disabled anyway in that case Fixes: 5e29500 ("xen-pciback: Allow setting PCI_MSIX_FLAGS_MASKALL too") Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Acked-by: Juergen Gross <jgross@suse.com> Link: https://lore.kernel.org/r/20231016131348.1734721-1-marmarek@invisiblethingslab.com Signed-off-by: Juergen Gross <jgross@suse.com>
1 parent f0d7db7 commit 2c269f4

3 files changed

Lines changed: 23 additions & 25 deletions

File tree

drivers/xen/xen-pciback/conf_space.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -288,12 +288,6 @@ int xen_pcibk_get_interrupt_type(struct pci_dev *dev)
288288
u16 val;
289289
int ret = 0;
290290

291-
err = pci_read_config_word(dev, PCI_COMMAND, &val);
292-
if (err)
293-
return err;
294-
if (!(val & PCI_COMMAND_INTX_DISABLE))
295-
ret |= INTERRUPT_TYPE_INTX;
296-
297291
/*
298292
* Do not trust dev->msi(x)_enabled here, as enabling could be done
299293
* bypassing the pci_*msi* functions, by the qemu.
@@ -316,6 +310,19 @@ int xen_pcibk_get_interrupt_type(struct pci_dev *dev)
316310
if (val & PCI_MSIX_FLAGS_ENABLE)
317311
ret |= INTERRUPT_TYPE_MSIX;
318312
}
313+
314+
/*
315+
* PCIe spec says device cannot use INTx if MSI/MSI-X is enabled,
316+
* so check for INTx only when both are disabled.
317+
*/
318+
if (!ret) {
319+
err = pci_read_config_word(dev, PCI_COMMAND, &val);
320+
if (err)
321+
return err;
322+
if (!(val & PCI_COMMAND_INTX_DISABLE))
323+
ret |= INTERRUPT_TYPE_INTX;
324+
}
325+
319326
return ret ?: INTERRUPT_TYPE_NONE;
320327
}
321328

drivers/xen/xen-pciback/conf_space_capability.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,16 @@ static int msi_msix_flags_write(struct pci_dev *dev, int offset, u16 new_value,
236236
return PCIBIOS_SET_FAILED;
237237

238238
if (new_value & field_config->enable_bit) {
239-
/* don't allow enabling together with other interrupt types */
239+
/*
240+
* Don't allow enabling together with other interrupt type, but do
241+
* allow enabling MSI(-X) while INTx is still active to please Linuxes
242+
* MSI(-X) startup sequence. It is safe to do, as according to PCI
243+
* spec, device with enabled MSI(-X) shouldn't use INTx.
244+
*/
240245
int int_type = xen_pcibk_get_interrupt_type(dev);
241246

242247
if (int_type == INTERRUPT_TYPE_NONE ||
248+
int_type == INTERRUPT_TYPE_INTX ||
243249
int_type == field_config->int_type)
244250
goto write;
245251
return PCIBIOS_SET_FAILED;

drivers/xen/xen-pciback/conf_space_header.c

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -104,24 +104,9 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
104104
pci_clear_mwi(dev);
105105
}
106106

107-
if (dev_data && dev_data->allow_interrupt_control) {
108-
if ((cmd->val ^ value) & PCI_COMMAND_INTX_DISABLE) {
109-
if (value & PCI_COMMAND_INTX_DISABLE) {
110-
pci_intx(dev, 0);
111-
} else {
112-
/* Do not allow enabling INTx together with MSI or MSI-X. */
113-
switch (xen_pcibk_get_interrupt_type(dev)) {
114-
case INTERRUPT_TYPE_NONE:
115-
pci_intx(dev, 1);
116-
break;
117-
case INTERRUPT_TYPE_INTX:
118-
break;
119-
default:
120-
return PCIBIOS_SET_FAILED;
121-
}
122-
}
123-
}
124-
}
107+
if (dev_data && dev_data->allow_interrupt_control &&
108+
((cmd->val ^ value) & PCI_COMMAND_INTX_DISABLE))
109+
pci_intx(dev, !(value & PCI_COMMAND_INTX_DISABLE));
125110

126111
cmd->val = value;
127112

0 commit comments

Comments
 (0)