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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user