Add support to batch get CPU steering tags for device-specific TPH mode that does not implement an ST table. This interface requires enabling the 'enable_unsafe_tph_ds_mode' module parameter. Signed-off-by: Chengwen Feng --- drivers/vfio/pci/vfio_pci_core.c | 73 ++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index 69f666d20c4a..45e641ab2a88 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -1529,6 +1529,77 @@ static int vfio_pci_tph_disable(struct vfio_pci_core_device *vdev) return 0; } +static int vfio_pci_tph_get_st(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_entry *ents; + struct vfio_pci_tph_st st; + enum tph_mem_type mtype; + size_t size, ents_off; + int i, err; + + if (!enable_unsafe_tph_ds_mode || + pcie_tph_get_st_table_loc(pdev) != PCI_TPH_LOC_NONE) + return -EOPNOTSUPP; + + if (copy_from_user(&st, uarg, sizeof(st))) + return -EFAULT; + + /* Check reserved fields are zero */ + if (memchr_inv(&st.reserved, 0, sizeof(st.reserved))) + return -EINVAL; + + if (!st.count || st.count > VFIO_PCI_TPH_MAX_ENTRIES) + return -EINVAL; + + size = st.count * sizeof(*ents); + if (op->argsz < offsetofend(struct vfio_device_pci_tph_op, st) + + sizeof(struct vfio_pci_tph_st) + size) + return -EINVAL; + + ents = kvmalloc(size, GFP_KERNEL); + if (!ents) + return -ENOMEM; + + ents_off = offsetof(struct vfio_pci_tph_st, ents); + if (copy_from_user(ents, uarg + ents_off, size)) { + err = -EFAULT; + goto out; + } + + for (i = 0; i < st.count; i++) { + /* Check reserved fields are zero */ + if (memchr_inv(&ents[i].reserved0, 0, sizeof(ents[i].reserved0)) || + memchr_inv(&ents[i].reserved1, 0, sizeof(ents[i].reserved1))) { + err = -EINVAL; + goto out; + } + + if (ents[i].mem_type == VFIO_PCI_TPH_MEM_TYPE_VM) { + mtype = TPH_MEM_TYPE_VM; + } else if (ents[i].mem_type == VFIO_PCI_TPH_MEM_TYPE_PM) { + mtype = TPH_MEM_TYPE_PM; + } else { + err = -EINVAL; + goto out; + } + + err = pcie_tph_get_cpu_st(pdev, mtype, ents[i].cpu, + &ents[i].st); + if (err) + goto out; + } + + if (copy_to_user(uarg + ents_off, ents, size)) + err = -EFAULT; + +out: + kvfree(ents); + return err; +} + static int vfio_pci_ioctl_tph(struct vfio_pci_core_device *vdev, void __user *uarg) { @@ -1545,6 +1616,8 @@ static int vfio_pci_ioctl_tph(struct vfio_pci_core_device *vdev, return vfio_pci_tph_enable(vdev, &op, uarg + minsz); case VFIO_PCI_TPH_DISABLE: return vfio_pci_tph_disable(vdev); + case VFIO_PCI_TPH_GET_ST: + return vfio_pci_tph_get_st(vdev, &op, uarg + minsz); default: /* Other ops are not implemented yet */ return -EINVAL; -- 2.17.1