mirror of https://github.com/xemu-project/xemu.git
pci/aer: fix error injection
Fix the injection logic upon aer message to follow 6.2.4.1.2 more closely: specifically only send an msi interrupt when the logical or of the enabled bits changed, not when a bit which was previously clear becomes set. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
This commit is contained in:
parent
624c716cc5
commit
c3f33667a6
|
@ -257,6 +257,22 @@ static unsigned int pcie_aer_root_get_vector(PCIDevice *dev)
|
||||||
return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT;
|
return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Given a status register, get corresponding bits in the command register */
|
||||||
|
static uint32_t pcie_aer_status_to_cmd(uint32_t status)
|
||||||
|
{
|
||||||
|
uint32_t cmd = 0;
|
||||||
|
if (status & PCI_ERR_ROOT_COR_RCV) {
|
||||||
|
cmd |= PCI_ERR_ROOT_CMD_COR_EN;
|
||||||
|
}
|
||||||
|
if (status & PCI_ERR_ROOT_NONFATAL_RCV) {
|
||||||
|
cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN;
|
||||||
|
}
|
||||||
|
if (status & PCI_ERR_ROOT_FATAL_RCV) {
|
||||||
|
cmd |= PCI_ERR_ROOT_CMD_FATAL_EN;
|
||||||
|
}
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* return value:
|
* return value:
|
||||||
* true: error message is sent up
|
* true: error message is sent up
|
||||||
|
@ -272,14 +288,14 @@ static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
|
||||||
uint16_t cmd;
|
uint16_t cmd;
|
||||||
uint8_t *aer_cap;
|
uint8_t *aer_cap;
|
||||||
uint32_t root_cmd;
|
uint32_t root_cmd;
|
||||||
uint32_t root_status;
|
uint32_t root_status, prev_status;
|
||||||
bool msi_trigger;
|
bool msi_trigger;
|
||||||
|
|
||||||
msg_sent = false;
|
msg_sent = false;
|
||||||
cmd = pci_get_word(dev->config + PCI_COMMAND);
|
cmd = pci_get_word(dev->config + PCI_COMMAND);
|
||||||
aer_cap = dev->config + dev->exp.aer_cap;
|
aer_cap = dev->config + dev->exp.aer_cap;
|
||||||
root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
|
root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
|
||||||
root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
|
prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
|
||||||
msi_trigger = false;
|
msi_trigger = false;
|
||||||
|
|
||||||
if (cmd & PCI_COMMAND_SERR) {
|
if (cmd & PCI_COMMAND_SERR) {
|
||||||
|
@ -337,20 +353,23 @@ static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
|
||||||
}
|
}
|
||||||
pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status);
|
pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status);
|
||||||
|
|
||||||
if (root_cmd & msg->severity) {
|
/* 6.2.4.1.2 Interrupt Generation */
|
||||||
/* 6.2.4.1.2 Interrupt Generation */
|
/* All the above did was set some bits in the status register.
|
||||||
if (msix_enabled(dev)) {
|
* Specifically these that match message severity.
|
||||||
if (msi_trigger) {
|
* The below code relies on this fact. */
|
||||||
msix_notify(dev, pcie_aer_root_get_vector(dev));
|
if (!(root_cmd & msg->severity) ||
|
||||||
}
|
(pcie_aer_status_to_cmd(prev_status) & root_cmd)) {
|
||||||
} else if (msi_enabled(dev)) {
|
/* Condition is not being set or was already true so nothing to do. */
|
||||||
if (msi_trigger) {
|
return msg_sent;
|
||||||
msi_notify(dev, pcie_aer_root_get_vector(dev));
|
}
|
||||||
}
|
|
||||||
} else {
|
msg_sent = true;
|
||||||
qemu_set_irq(dev->irq[dev->exp.aer_intx], 1);
|
if (msix_enabled(dev)) {
|
||||||
}
|
msix_notify(dev, pcie_aer_root_get_vector(dev));
|
||||||
msg_sent = true;
|
} else if (msi_enabled(dev)) {
|
||||||
|
msi_notify(dev, pcie_aer_root_get_vector(dev));
|
||||||
|
} else {
|
||||||
|
qemu_set_irq(dev->irq[dev->exp.aer_intx], 1);
|
||||||
}
|
}
|
||||||
return msg_sent;
|
return msg_sent;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue