Add support to enable and disable TPH function with mode selection. Restrict unsafe device-specific TPH mode to be allowed only when module parameter enable_unsafe_tph_ds_mode=1 is set. Disable TPH when taking over ownership of the device. Signed-off-by: Chengwen Feng --- drivers/vfio/pci/vfio_pci_core.c | 43 ++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index d98d04bad4a3..69f666d20c4a 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -1492,6 +1492,43 @@ static int vfio_pci_tph_get_cap(struct vfio_pci_core_device *vdev, return 0; } +static int vfio_pci_tph_enable(struct vfio_pci_core_device *vdev, + struct vfio_device_pci_tph_op *op, + void __user *uarg) +{ + struct pci_dev *pdev = vdev->pdev; + struct vfio_pci_tph_ctrl ctrl; + int mode; + + if (op->argsz < offsetofend(struct vfio_device_pci_tph_op, ctrl) + + sizeof(struct vfio_pci_tph_ctrl)) + return -EINVAL; + + if (copy_from_user(&ctrl, uarg, sizeof(ctrl))) + return -EFAULT; + + if (ctrl.mode != VFIO_PCI_TPH_MODE_IV && + ctrl.mode != VFIO_PCI_TPH_MODE_DS) + return -EINVAL; + + if (ctrl.mode == VFIO_PCI_TPH_MODE_DS && !enable_unsafe_tph_ds_mode) + return -EOPNOTSUPP; + + /* Reserved must be zero */ + if (memchr_inv(ctrl.reserved, 0, sizeof(ctrl.reserved))) + return -EINVAL; + + mode = (ctrl.mode == VFIO_PCI_TPH_MODE_IV) ? PCI_TPH_ST_IV_MODE : + PCI_TPH_ST_DS_MODE; + return pcie_enable_tph(pdev, mode); +} + +static int vfio_pci_tph_disable(struct vfio_pci_core_device *vdev) +{ + pcie_disable_tph(vdev->pdev); + return 0; +} + static int vfio_pci_ioctl_tph(struct vfio_pci_core_device *vdev, void __user *uarg) { @@ -1504,6 +1541,10 @@ static int vfio_pci_ioctl_tph(struct vfio_pci_core_device *vdev, switch (op.op) { case VFIO_PCI_TPH_GET_CAP: return vfio_pci_tph_get_cap(vdev, &op, uarg + minsz); + case VFIO_PCI_TPH_ENABLE: + return vfio_pci_tph_enable(vdev, &op, uarg + minsz); + case VFIO_PCI_TPH_DISABLE: + return vfio_pci_tph_disable(vdev); default: /* Other ops are not implemented yet */ return -EINVAL; @@ -2259,6 +2300,8 @@ int vfio_pci_core_register_device(struct vfio_pci_core_device *vdev) ret = vfio_register_group_dev(&vdev->vdev); if (ret) goto out_power; + /* Disable TPH when taking over ownership of the device */ + pcie_disable_tph(pdev); return 0; out_power: -- 2.17.1