diff options
Diffstat (limited to 'drivers/vfio/pci')
| -rw-r--r-- | drivers/vfio/pci/vfio_pci.c | 39 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci_config.c | 19 | ||||
| -rw-r--r-- | drivers/vfio/pci/vfio_pci_intrs.c | 29 | 
3 files changed, 33 insertions, 54 deletions
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 6ab71b9fcf8..010e0f8b8e4 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -57,7 +57,8 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)  	ret = vfio_config_init(vdev);  	if (ret) { -		pci_load_and_free_saved_state(pdev, &vdev->pci_saved_state); +		kfree(vdev->pci_saved_state); +		vdev->pci_saved_state = NULL;  		pci_disable_device(pdev);  		return ret;  	} @@ -139,25 +140,14 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)  	pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);  	/* -	 * Careful, device_lock may already be held.  This is the case if -	 * a driver unbind is blocked.  Try to get the locks ourselves to -	 * prevent a deadlock. +	 * Try to reset the device.  The success of this is dependent on +	 * being able to lock the device, which is not always possible.  	 */  	if (vdev->reset_works) { -		bool reset_done = false; - -		if (pci_cfg_access_trylock(pdev)) { -			if (device_trylock(&pdev->dev)) { -				__pci_reset_function_locked(pdev); -				reset_done = true; -				device_unlock(&pdev->dev); -			} -			pci_cfg_access_unlock(pdev); -		} - -		if (!reset_done) -			pr_warn("%s: Unable to acquire locks for reset of %s\n", -				__func__, dev_name(&pdev->dev)); +		int ret = pci_try_reset_function(pdev); +		if (ret) +			pr_warn("%s: Failed to reset device %s (%d)\n", +				__func__, dev_name(&pdev->dev), ret);  	}  	pci_restore_state(pdev); @@ -207,8 +197,7 @@ static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)  		if (pos) {  			pci_read_config_word(vdev->pdev,  					     pos + PCI_MSI_FLAGS, &flags); - -			return 1 << (flags & PCI_MSI_FLAGS_QMASK); +			return 1 << ((flags & PCI_MSI_FLAGS_QMASK) >> 1);  		}  	} else if (irq_type == VFIO_PCI_MSIX_IRQ_INDEX) {  		u8 pos; @@ -514,7 +503,7 @@ static long vfio_pci_ioctl(void *device_data,  	} else if (cmd == VFIO_DEVICE_RESET) {  		return vdev->reset_works ? -			pci_reset_function(vdev->pdev) : -EINVAL; +			pci_try_reset_function(vdev->pdev) : -EINVAL;  	} else if (cmd == VFIO_DEVICE_GET_PCI_HOT_RESET_INFO) {  		struct vfio_pci_hot_reset_info hdr; @@ -684,8 +673,8 @@ reset_info_exit:  						    &info, slot);  		if (!ret)  			/* User has access, do the reset */ -			ret = slot ? pci_reset_slot(vdev->pdev->slot) : -				     pci_reset_bus(vdev->pdev->bus); +			ret = slot ? pci_try_reset_slot(vdev->pdev->slot) : +				     pci_try_reset_bus(vdev->pdev->bus);  hot_reset_release:  		for (i--; i >= 0; i--) @@ -883,9 +872,13 @@ static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev,  		return PCI_ERS_RESULT_DISCONNECT;  	} +	mutex_lock(&vdev->igate); +  	if (vdev->err_trigger)  		eventfd_signal(vdev->err_trigger, 1); +	mutex_unlock(&vdev->igate); +  	vfio_device_put(device);  	return PCI_ERS_RESULT_CAN_RECOVER; diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index ffd0632c3cb..e50790e91f7 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -975,20 +975,20 @@ static int vfio_vc_cap_len(struct vfio_pci_device *vdev, u16 pos)  	int ret, evcc, phases, vc_arb;  	int len = PCI_CAP_VC_BASE_SIZEOF; -	ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_REG1, &tmp); +	ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_CAP1, &tmp);  	if (ret)  		return pcibios_err_to_errno(ret); -	evcc = tmp & PCI_VC_REG1_EVCC; /* extended vc count */ -	ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_REG2, &tmp); +	evcc = tmp & PCI_VC_CAP1_EVCC; /* extended vc count */ +	ret = pci_read_config_dword(pdev, pos + PCI_VC_PORT_CAP2, &tmp);  	if (ret)  		return pcibios_err_to_errno(ret); -	if (tmp & PCI_VC_REG2_128_PHASE) +	if (tmp & PCI_VC_CAP2_128_PHASE)  		phases = 128; -	else if (tmp & PCI_VC_REG2_64_PHASE) +	else if (tmp & PCI_VC_CAP2_64_PHASE)  		phases = 64; -	else if (tmp & PCI_VC_REG2_32_PHASE) +	else if (tmp & PCI_VC_CAP2_32_PHASE)  		phases = 32;  	else  		phases = 0; @@ -1126,8 +1126,7 @@ static int vfio_ext_cap_len(struct vfio_pci_device *vdev, u16 ecap, u16 epos)  			return pcibios_err_to_errno(ret);  		byte &= PCI_DPA_CAP_SUBSTATE_MASK; -		byte = round_up(byte + 1, 4); -		return PCI_DPA_BASE_SIZEOF + byte; +		return PCI_DPA_BASE_SIZEOF + byte + 1;  	case PCI_EXT_CAP_ID_TPH:  		ret = pci_read_config_dword(pdev, epos + PCI_TPH_CAP, &dword);  		if (ret) @@ -1136,9 +1135,9 @@ static int vfio_ext_cap_len(struct vfio_pci_device *vdev, u16 ecap, u16 epos)  		if ((dword & PCI_TPH_CAP_LOC_MASK) == PCI_TPH_LOC_CAP) {  			int sts; -			sts = byte & PCI_TPH_CAP_ST_MASK; +			sts = dword & PCI_TPH_CAP_ST_MASK;  			sts >>= PCI_TPH_CAP_ST_SHIFT; -			return PCI_TPH_BASE_SIZEOF + round_up(sts * 2, 4); +			return PCI_TPH_BASE_SIZEOF + (sts * 2) + 2;  		}  		return PCI_TPH_BASE_SIZEOF;  	default: diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 641bc87bdb9..9dd49c9839a 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c @@ -482,15 +482,19 @@ static int vfio_msi_enable(struct vfio_pci_device *vdev, int nvec, bool msix)  		for (i = 0; i < nvec; i++)  			vdev->msix[i].entry = i; -		ret = pci_enable_msix(pdev, vdev->msix, nvec); -		if (ret) { +		ret = pci_enable_msix_range(pdev, vdev->msix, 1, nvec); +		if (ret < nvec) { +			if (ret > 0) +				pci_disable_msix(pdev);  			kfree(vdev->msix);  			kfree(vdev->ctx);  			return ret;  		}  	} else { -		ret = pci_enable_msi_block(pdev, nvec); -		if (ret) { +		ret = pci_enable_msi_range(pdev, 1, nvec); +		if (ret < nvec) { +			if (ret > 0) +				pci_disable_msi(pdev);  			kfree(vdev->ctx);  			return ret;  		} @@ -749,54 +753,37 @@ static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev,  				    unsigned count, uint32_t flags, void *data)  {  	int32_t fd = *(int32_t *)data; -	struct pci_dev *pdev = vdev->pdev;  	if ((index != VFIO_PCI_ERR_IRQ_INDEX) ||  	    !(flags & VFIO_IRQ_SET_DATA_TYPE_MASK))  		return -EINVAL; -	/* -	 * device_lock synchronizes setting and checking of -	 * err_trigger. The vfio_pci_aer_err_detected() is also -	 * called with device_lock held. -	 */ -  	/* DATA_NONE/DATA_BOOL enables loopback testing */ -  	if (flags & VFIO_IRQ_SET_DATA_NONE) { -		device_lock(&pdev->dev);  		if (vdev->err_trigger)  			eventfd_signal(vdev->err_trigger, 1); -		device_unlock(&pdev->dev);  		return 0;  	} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {  		uint8_t trigger = *(uint8_t *)data; -		device_lock(&pdev->dev);  		if (trigger && vdev->err_trigger)  			eventfd_signal(vdev->err_trigger, 1); -		device_unlock(&pdev->dev);  		return 0;  	}  	/* Handle SET_DATA_EVENTFD */ -  	if (fd == -1) { -		device_lock(&pdev->dev);  		if (vdev->err_trigger)  			eventfd_ctx_put(vdev->err_trigger);  		vdev->err_trigger = NULL; -		device_unlock(&pdev->dev);  		return 0;  	} else if (fd >= 0) {  		struct eventfd_ctx *efdctx;  		efdctx = eventfd_ctx_fdget(fd);  		if (IS_ERR(efdctx))  			return PTR_ERR(efdctx); -		device_lock(&pdev->dev);  		if (vdev->err_trigger)  			eventfd_ctx_put(vdev->err_trigger);  		vdev->err_trigger = efdctx; -		device_unlock(&pdev->dev);  		return 0;  	} else  		return -EINVAL;  | 
