vfio-pci: Fix interrupt disabling
When disabling MSI/X interrupts the disable functions will leave the device in INTx mode (when available). This matches how hardware operates, INTx is enabled unless MSI/X is enabled (DisINTx is handled separately). Therefore when we really want to disable all interrupts, such as when removing the device, and we start with the device in MSI/X mode, we need to pass through INTx on our way to being completely quiesced. In well behaved situations, the guest driver will have shutdown the device and it will start vfio_exitfn() in INTx mode, producing the desired result. If hot-unplug causes the guest to crash, we may get the device in MSI/X state, which will leave QEMU with a bogus handler installed. Fix this by re-ordering our disable routine so that it should always finish in VFIO_INT_NONE state, which is what all callers expect. Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
		
							parent
							
								
									29c6e6df49
								
							
						
					
					
						commit
						b3e27c3aee
					
				| 
						 | 
				
			
			@ -2129,16 +2129,19 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
 | 
			
		|||
 */
 | 
			
		||||
static void vfio_disable_interrupts(VFIOPCIDevice *vdev)
 | 
			
		||||
{
 | 
			
		||||
    switch (vdev->interrupt) {
 | 
			
		||||
    case VFIO_INT_INTx:
 | 
			
		||||
        vfio_disable_intx(vdev);
 | 
			
		||||
        break;
 | 
			
		||||
    case VFIO_INT_MSI:
 | 
			
		||||
        vfio_disable_msi(vdev);
 | 
			
		||||
        break;
 | 
			
		||||
    case VFIO_INT_MSIX:
 | 
			
		||||
    /*
 | 
			
		||||
     * More complicated than it looks.  Disabling MSI/X transitions the
 | 
			
		||||
     * device to INTx mode (if supported).  Therefore we need to first
 | 
			
		||||
     * disable MSI/X and then cleanup by disabling INTx.
 | 
			
		||||
     */
 | 
			
		||||
    if (vdev->interrupt == VFIO_INT_MSIX) {
 | 
			
		||||
        vfio_disable_msix(vdev);
 | 
			
		||||
        break;
 | 
			
		||||
    } else if (vdev->interrupt == VFIO_INT_MSI) {
 | 
			
		||||
        vfio_disable_msi(vdev);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (vdev->interrupt == VFIO_INT_INTx) {
 | 
			
		||||
        vfio_disable_intx(vdev);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue