Add TPH metadata fields to struct vfio_pci_dma_buf to store PH, basic/extended ST and their validity flags. Implement vfio_pci_dma_buf_get_pci_tph() to fetch TPH tag and PH from dmabuf, distinguish basic and extended ST namespace. Add vfio_pci_dma_buf_get_tph_by_fd() to resolve TPH data via dmabuf fd, validate dmabuf owner ops. Provide stub implementation if CONFIG_VFIO_PCI_DMABUF is unset. Lay dmabuf foundation for the upcoming TPH_RESOLVE feature. Signed-off-by: Zhiping Zhang Signed-off-by: Chengwen Feng --- drivers/vfio/pci/vfio_pci_dmabuf.c | 49 +++++++++++++++++++++++++++++- drivers/vfio/pci/vfio_pci_priv.h | 6 ++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c b/drivers/vfio/pci/vfio_pci_dmabuf.c index c16f460c01d6..d9c5e434e586 100644 --- a/drivers/vfio/pci/vfio_pci_dmabuf.c +++ b/drivers/vfio/pci/vfio_pci_dmabuf.c @@ -19,7 +19,14 @@ struct vfio_pci_dma_buf { u32 nr_ranges; struct kref kref; struct completion comp; - u8 revoked : 1; + + /* Protected by dmabuf->resv. */ + u8 revoked:1; + u8 tph_ph:2; + u8 tph_st_valid:1; + u8 tph_xst_valid:1; + u8 tph_st; + u16 tph_xst; }; static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf, @@ -81,6 +88,26 @@ static void vfio_pci_dma_buf_unmap(struct dma_buf_attachment *attachment, kref_put(&priv->kref, vfio_pci_dma_buf_done); } +static int vfio_pci_dma_buf_get_pci_tph(struct dma_buf *dmabuf, bool extended, + u16 *tag, u8 *ph) +{ + struct vfio_pci_dma_buf *priv = dmabuf->priv; + + dma_resv_assert_held(priv->dmabuf->resv); + + if (extended) { + if (!priv->tph_xst_valid) + return -EOPNOTSUPP; + *tag = priv->tph_xst; + } else { + if (!priv->tph_st_valid) + return -EOPNOTSUPP; + *tag = priv->tph_st; + } + *ph = priv->tph_ph; + return 0; +} + static void vfio_pci_dma_buf_release(struct dma_buf *dmabuf) { struct vfio_pci_dma_buf *priv = dmabuf->priv; @@ -106,6 +133,26 @@ static const struct dma_buf_ops vfio_pci_dmabuf_ops = { .release = vfio_pci_dma_buf_release, }; +int vfio_pci_dma_buf_get_tph_by_fd(int fd, bool extended, u16 *tag, u8 *ph) +{ + struct dma_buf *dmabuf; + int ret = 0; + + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + if (dmabuf->ops != &vfio_pci_dmabuf_ops) { + ret = -EINVAL; + goto out; + } + + ret = vfio_pci_dma_buf_get_pci_tph(dmabuf, extended, tag, ph); +out: + dma_buf_put(dmabuf); + return ret; +} + /* * This is a temporary "private interconnect" between VFIO DMABUF and iommufd. * It allows the two co-operating drivers to exchange the physical address of diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h index c997cc9bf330..d7bc52f488c6 100644 --- a/drivers/vfio/pci/vfio_pci_priv.h +++ b/drivers/vfio/pci/vfio_pci_priv.h @@ -122,12 +122,18 @@ static inline bool vfio_pci_is_vga(struct pci_dev *pdev) } #ifdef CONFIG_VFIO_PCI_DMABUF +int vfio_pci_dma_buf_get_tph_by_fd(int fd, bool extended, u16 *tag, u8 *ph); int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags, struct vfio_device_feature_dma_buf __user *arg, size_t argsz); void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev); void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked); #else +static inline int vfio_pci_dma_buf_get_tph_by_fd(int fd, bool extended, + u16 *tag, u8 *ph) +{ + return -EOPNOTSUPP; +} static inline int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags, struct vfio_device_feature_dma_buf __user *arg, -- 2.17.1