aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLogan Gunthorpe <logang@deltatee.com>2018-10-04 17:27:37 -0400
committerBjorn Helgaas <bhelgaas@google.com>2018-10-17 13:18:16 -0400
commit977196b8c5b20b901acb0042579e30d7fa55790a (patch)
treeef3a0c1ee710fc331eb1fdfc0fcaccdca0308776
parentcbb8ca69fcbb2c82f70abcbb75b6ea8579236210 (diff)
PCI/P2PDMA: Add PCI p2pmem DMA mappings to adjust the bus offset
The DMA address used when mapping PCI P2P memory must be the PCI bus address. Thus, introduce pci_p2pmem_map_sg() to map the correct addresses when using P2P memory. Memory mapped in this way does not need to be unmapped and thus if we provided pci_p2pmem_unmap_sg() it would be empty. This breaks the expected balance between map/unmap but was left out as an empty function doesn't really provide any benefit. In the future, if this call becomes necessary it can be added without much difficulty. For this, we assume that an SGL passed to these functions contain all P2P memory or no P2P memory. Signed-off-by: Logan Gunthorpe <logang@deltatee.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--drivers/pci/p2pdma.c43
-rw-r--r--include/linux/memremap.h1
-rw-r--r--include/linux/pci-p2pdma.h7
3 files changed, 51 insertions, 0 deletions
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
index a8d484ddc5ad..09b3146c145c 100644
--- a/drivers/pci/p2pdma.c
+++ b/drivers/pci/p2pdma.c
@@ -194,6 +194,8 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
194 pgmap->res.flags = pci_resource_flags(pdev, bar); 194 pgmap->res.flags = pci_resource_flags(pdev, bar);
195 pgmap->ref = &pdev->p2pdma->devmap_ref; 195 pgmap->ref = &pdev->p2pdma->devmap_ref;
196 pgmap->type = MEMORY_DEVICE_PCI_P2PDMA; 196 pgmap->type = MEMORY_DEVICE_PCI_P2PDMA;
197 pgmap->pci_p2pdma_bus_offset = pci_bus_address(pdev, bar) -
198 pci_resource_start(pdev, bar);
197 199
198 addr = devm_memremap_pages(&pdev->dev, pgmap); 200 addr = devm_memremap_pages(&pdev->dev, pgmap);
199 if (IS_ERR(addr)) { 201 if (IS_ERR(addr)) {
@@ -678,3 +680,44 @@ void pci_p2pmem_publish(struct pci_dev *pdev, bool publish)
678 pdev->p2pdma->p2pmem_published = publish; 680 pdev->p2pdma->p2pmem_published = publish;
679} 681}
680EXPORT_SYMBOL_GPL(pci_p2pmem_publish); 682EXPORT_SYMBOL_GPL(pci_p2pmem_publish);
683
684/**
685 * pci_p2pdma_map_sg - map a PCI peer-to-peer scatterlist for DMA
686 * @dev: device doing the DMA request
687 * @sg: scatter list to map
688 * @nents: elements in the scatterlist
689 * @dir: DMA direction
690 *
691 * Scatterlists mapped with this function should not be unmapped in any way.
692 *
693 * Returns the number of SG entries mapped or 0 on error.
694 */
695int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
696 enum dma_data_direction dir)
697{
698 struct dev_pagemap *pgmap;
699 struct scatterlist *s;
700 phys_addr_t paddr;
701 int i;
702
703 /*
704 * p2pdma mappings are not compatible with devices that use
705 * dma_virt_ops. If the upper layers do the right thing
706 * this should never happen because it will be prevented
707 * by the check in pci_p2pdma_add_client()
708 */
709 if (WARN_ON_ONCE(IS_ENABLED(CONFIG_DMA_VIRT_OPS) &&
710 dev->dma_ops == &dma_virt_ops))
711 return 0;
712
713 for_each_sg(sg, s, nents, i) {
714 pgmap = sg_page(s)->pgmap;
715 paddr = sg_phys(s);
716
717 s->dma_address = paddr - pgmap->pci_p2pdma_bus_offset;
718 sg_dma_len(s) = s->length;
719 }
720
721 return nents;
722}
723EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg);
diff --git a/include/linux/memremap.h b/include/linux/memremap.h
index 9553370ebdad..0ac69ddf5fc4 100644
--- a/include/linux/memremap.h
+++ b/include/linux/memremap.h
@@ -125,6 +125,7 @@ struct dev_pagemap {
125 struct device *dev; 125 struct device *dev;
126 void *data; 126 void *data;
127 enum memory_type type; 127 enum memory_type type;
128 u64 pci_p2pdma_bus_offset;
128}; 129};
129 130
130#ifdef CONFIG_ZONE_DEVICE 131#ifdef CONFIG_ZONE_DEVICE
diff --git a/include/linux/pci-p2pdma.h b/include/linux/pci-p2pdma.h
index 7bdaacfd5892..b6dfb6dc2e53 100644
--- a/include/linux/pci-p2pdma.h
+++ b/include/linux/pci-p2pdma.h
@@ -30,6 +30,8 @@ struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev,
30 unsigned int *nents, u32 length); 30 unsigned int *nents, u32 length);
31void pci_p2pmem_free_sgl(struct pci_dev *pdev, struct scatterlist *sgl); 31void pci_p2pmem_free_sgl(struct pci_dev *pdev, struct scatterlist *sgl);
32void pci_p2pmem_publish(struct pci_dev *pdev, bool publish); 32void pci_p2pmem_publish(struct pci_dev *pdev, bool publish);
33int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
34 enum dma_data_direction dir);
33#else /* CONFIG_PCI_P2PDMA */ 35#else /* CONFIG_PCI_P2PDMA */
34static inline int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, 36static inline int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar,
35 size_t size, u64 offset) 37 size_t size, u64 offset)
@@ -75,6 +77,11 @@ static inline void pci_p2pmem_free_sgl(struct pci_dev *pdev,
75static inline void pci_p2pmem_publish(struct pci_dev *pdev, bool publish) 77static inline void pci_p2pmem_publish(struct pci_dev *pdev, bool publish)
76{ 78{
77} 79}
80static inline int pci_p2pdma_map_sg(struct device *dev,
81 struct scatterlist *sg, int nents, enum dma_data_direction dir)
82{
83 return 0;
84}
78#endif /* CONFIG_PCI_P2PDMA */ 85#endif /* CONFIG_PCI_P2PDMA */
79 86
80 87