+static struct sg_table *
+vfio_pci_dma_buf_map(struct dma_buf_attachment *attachment,
+ enum dma_data_direction dir)
+{
+ struct vfio_pci_dma_buf *priv = attachment->dmabuf->priv;
+ struct p2pdma_provider *provider = priv->vdev->provider;
+ struct dma_iova_state *state = attachment->priv;
+ struct phys_vec *phys_vec = &priv->phys_vec;
+ struct scatterlist *sgl;
+ struct sg_table *sgt;
+ dma_addr_t addr;
+ int ret;
+
+ dma_resv_assert_held(priv->dmabuf->resv);
+
+ sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
+ if (!sgt)
+ return ERR_PTR(-ENOMEM);
+
+ ret = sg_alloc_table(sgt, 1, GFP_KERNEL | __GFP_ZERO);
+ if (ret)
+ goto err_kfree_sgt;
+
+ sgl = sgt->sgl;
+
+ if (!state) {
+ addr = pci_p2pdma_bus_addr_map(provider, phys_vec->paddr);
+ } else if (dma_use_iova(state)) {
+ ret = dma_iova_link(attachment->dev, state, phys_vec->paddr, 0,
+ phys_vec->len, dir, DMA_ATTR_SKIP_CPU_SYNC);
+ if (ret)
+ goto err_free_table;
+
+ ret = dma_iova_sync(attachment->dev, state, 0, phys_vec->len);
+ if (ret)
+ goto err_unmap_dma;
+
+ addr = state->addr;
+ } else {
+ addr = dma_map_phys(attachment->dev, phys_vec->paddr,
+ phys_vec->len, dir, DMA_ATTR_SKIP_CPU_SYNC);
+ ret = dma_mapping_error(attachment->dev, addr);
+ if (ret)
+ goto err_free_table;
+ }
+
+ fill_sg_entry(sgl, phys_vec->len, addr);
+ return sgt;
+
+err_unmap_dma:
+ dma_iova_destroy(attachment->dev, state, phys_vec->len, dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
+err_free_table:
+ sg_free_table(sgt);
+err_kfree_sgt:
+ kfree(sgt);
+ return ERR_PTR(ret);
+}
+
+static void vfio_pci_dma_buf_unmap(struct dma_buf_attachment *attachment,
+ struct sg_table *sgt,
+ enum dma_data_direction dir)
+{
+ struct vfio_pci_dma_buf *priv = attachment->dmabuf->priv;
+ struct dma_iova_state *state = attachment->priv;
+ struct scatterlist *sgl;
+ int i;
+
+ if (!state)
+ ; /* Do nothing */
+ else if (dma_use_iova(state))
+ dma_iova_destroy(attachment->dev, state, priv->phys_vec.len,
+ dir, DMA_ATTR_SKIP_CPU_SYNC);
+ else
+ for_each_sgtable_dma_sg(sgt, sgl, i)
+ dma_unmap_phys(attachment->dev, sg_dma_address(sgl),
+ sg_dma_len(sgl), dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
+
+ sg_free_table(sgt);
+ kfree(sgt);
+}