mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 11:56:58 +00:00
Merge tag 'dma-mapping-6.19-2025-12-05' of git://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux
Pull dma-mapping updates from Marek Szyprowski: - More DMA mapping API refactoring to physical addresses as the primary interface instead of page+offset parameters. This time dma_map_ops callbacks are converted to physical addresses, what in turn results also in some simplification of architecture specific code (Leon Romanovsky and Jason Gunthorpe) - Clarify that dma_map_benchmark is not a kernel self-test, but standalone tool (Qinxin Xia) * tag 'dma-mapping-6.19-2025-12-05' of git://git.kernel.org/pub/scm/linux/kernel/git/mszyprowski/linux: dma-mapping: remove unused map_page callback xen: swiotlb: Convert mapping routine to rely on physical address x86: Use physical address for DMA mapping sparc: Use physical address DMA mapping powerpc: Convert to physical address DMA mapping parisc: Convert DMA map_page to map_phys interface MIPS/jazzdma: Provide physical address directly alpha: Convert mapping routine to rely on physical address dma-mapping: remove unused mapping resource callbacks xen: swiotlb: Switch to physical address mapping callbacks ARM: dma-mapping: Switch to physical address mapping callbacks ARM: dma-mapping: Reduce struct page exposure in arch_sync_dma*() dma-mapping: convert dummy ops to physical address mapping dma-mapping: prepare dma_map_ops to conversion to physical address tools/dma: move dma_map_benchmark from selftests to tools/dma
This commit is contained in:
@@ -224,28 +224,26 @@ static int pci_dac_dma_supported(struct pci_dev *dev, u64 mask)
|
||||
until either pci_unmap_single or pci_dma_sync_single is performed. */
|
||||
|
||||
static dma_addr_t
|
||||
pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
|
||||
pci_map_single_1(struct pci_dev *pdev, phys_addr_t paddr, size_t size,
|
||||
int dac_allowed)
|
||||
{
|
||||
struct pci_controller *hose = pdev ? pdev->sysdata : pci_isa_hose;
|
||||
dma_addr_t max_dma = pdev ? pdev->dma_mask : ISA_DMA_MASK;
|
||||
unsigned long offset = offset_in_page(paddr);
|
||||
struct pci_iommu_arena *arena;
|
||||
long npages, dma_ofs, i;
|
||||
unsigned long paddr;
|
||||
dma_addr_t ret;
|
||||
unsigned int align = 0;
|
||||
struct device *dev = pdev ? &pdev->dev : NULL;
|
||||
|
||||
paddr = __pa(cpu_addr);
|
||||
|
||||
#if !DEBUG_NODIRECT
|
||||
/* First check to see if we can use the direct map window. */
|
||||
if (paddr + size + __direct_map_base - 1 <= max_dma
|
||||
&& paddr + size <= __direct_map_size) {
|
||||
ret = paddr + __direct_map_base;
|
||||
|
||||
DBGA2("pci_map_single: [%p,%zx] -> direct %llx from %ps\n",
|
||||
cpu_addr, size, ret, __builtin_return_address(0));
|
||||
DBGA2("pci_map_single: [%pa,%zx] -> direct %llx from %ps\n",
|
||||
&paddr, size, ret, __builtin_return_address(0));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -255,8 +253,8 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
|
||||
if (dac_allowed) {
|
||||
ret = paddr + alpha_mv.pci_dac_offset;
|
||||
|
||||
DBGA2("pci_map_single: [%p,%zx] -> DAC %llx from %ps\n",
|
||||
cpu_addr, size, ret, __builtin_return_address(0));
|
||||
DBGA2("pci_map_single: [%pa,%zx] -> DAC %llx from %ps\n",
|
||||
&paddr, size, ret, __builtin_return_address(0));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -290,10 +288,10 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
|
||||
arena->ptes[i + dma_ofs] = mk_iommu_pte(paddr);
|
||||
|
||||
ret = arena->dma_base + dma_ofs * PAGE_SIZE;
|
||||
ret += (unsigned long)cpu_addr & ~PAGE_MASK;
|
||||
ret += offset;
|
||||
|
||||
DBGA2("pci_map_single: [%p,%zx] np %ld -> sg %llx from %ps\n",
|
||||
cpu_addr, size, npages, ret, __builtin_return_address(0));
|
||||
DBGA2("pci_map_single: [%pa,%zx] np %ld -> sg %llx from %ps\n",
|
||||
&paddr, size, npages, ret, __builtin_return_address(0));
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -322,19 +320,18 @@ static struct pci_dev *alpha_gendev_to_pci(struct device *dev)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static dma_addr_t alpha_pci_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size,
|
||||
enum dma_data_direction dir,
|
||||
static dma_addr_t alpha_pci_map_phys(struct device *dev, phys_addr_t phys,
|
||||
size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct pci_dev *pdev = alpha_gendev_to_pci(dev);
|
||||
int dac_allowed;
|
||||
|
||||
BUG_ON(dir == DMA_NONE);
|
||||
if (unlikely(attrs & DMA_ATTR_MMIO))
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0;
|
||||
return pci_map_single_1(pdev, (char *)page_address(page) + offset,
|
||||
size, dac_allowed);
|
||||
dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0;
|
||||
return pci_map_single_1(pdev, phys, size, dac_allowed);
|
||||
}
|
||||
|
||||
/* Unmap a single streaming mode DMA translation. The DMA_ADDR and
|
||||
@@ -343,7 +340,7 @@ static dma_addr_t alpha_pci_map_page(struct device *dev, struct page *page,
|
||||
the cpu to the buffer are guaranteed to see whatever the device
|
||||
wrote there. */
|
||||
|
||||
static void alpha_pci_unmap_page(struct device *dev, dma_addr_t dma_addr,
|
||||
static void alpha_pci_unmap_phys(struct device *dev, dma_addr_t dma_addr,
|
||||
size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
@@ -353,8 +350,6 @@ static void alpha_pci_unmap_page(struct device *dev, dma_addr_t dma_addr,
|
||||
struct pci_iommu_arena *arena;
|
||||
long dma_ofs, npages;
|
||||
|
||||
BUG_ON(dir == DMA_NONE);
|
||||
|
||||
if (dma_addr >= __direct_map_base
|
||||
&& dma_addr < __direct_map_base + __direct_map_size) {
|
||||
/* Nothing to do. */
|
||||
@@ -429,7 +424,7 @@ try_again:
|
||||
}
|
||||
memset(cpu_addr, 0, size);
|
||||
|
||||
*dma_addrp = pci_map_single_1(pdev, cpu_addr, size, 0);
|
||||
*dma_addrp = pci_map_single_1(pdev, virt_to_phys(cpu_addr), size, 0);
|
||||
if (*dma_addrp == DMA_MAPPING_ERROR) {
|
||||
free_pages((unsigned long)cpu_addr, order);
|
||||
if (alpha_mv.mv_pci_tbi || (gfp & GFP_DMA))
|
||||
@@ -643,9 +638,8 @@ static int alpha_pci_map_sg(struct device *dev, struct scatterlist *sg,
|
||||
/* Fast path single entry scatterlists. */
|
||||
if (nents == 1) {
|
||||
sg->dma_length = sg->length;
|
||||
sg->dma_address
|
||||
= pci_map_single_1(pdev, SG_ENT_VIRT_ADDRESS(sg),
|
||||
sg->length, dac_allowed);
|
||||
sg->dma_address = pci_map_single_1(pdev, sg_phys(sg),
|
||||
sg->length, dac_allowed);
|
||||
if (sg->dma_address == DMA_MAPPING_ERROR)
|
||||
return -EIO;
|
||||
return 1;
|
||||
@@ -917,8 +911,8 @@ iommu_unbind(struct pci_iommu_arena *arena, long pg_start, long pg_count)
|
||||
const struct dma_map_ops alpha_pci_ops = {
|
||||
.alloc = alpha_pci_alloc_coherent,
|
||||
.free = alpha_pci_free_coherent,
|
||||
.map_page = alpha_pci_map_page,
|
||||
.unmap_page = alpha_pci_unmap_page,
|
||||
.map_phys = alpha_pci_map_phys,
|
||||
.unmap_phys = alpha_pci_unmap_phys,
|
||||
.map_sg = alpha_pci_map_sg,
|
||||
.unmap_sg = alpha_pci_unmap_sg,
|
||||
.dma_supported = alpha_pci_supported,
|
||||
|
||||
@@ -624,16 +624,14 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
static void dma_cache_maint_page(struct page *page, unsigned long offset,
|
||||
size_t size, enum dma_data_direction dir,
|
||||
static void dma_cache_maint_page(phys_addr_t phys, size_t size,
|
||||
enum dma_data_direction dir,
|
||||
void (*op)(const void *, size_t, int))
|
||||
{
|
||||
unsigned long pfn;
|
||||
unsigned long offset = offset_in_page(phys);
|
||||
unsigned long pfn = __phys_to_pfn(phys);
|
||||
size_t left = size;
|
||||
|
||||
pfn = page_to_pfn(page) + offset / PAGE_SIZE;
|
||||
offset %= PAGE_SIZE;
|
||||
|
||||
/*
|
||||
* A single sg entry may refer to multiple physically contiguous
|
||||
* pages. But we still need to process highmem pages individually.
|
||||
@@ -644,17 +642,18 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset,
|
||||
size_t len = left;
|
||||
void *vaddr;
|
||||
|
||||
page = pfn_to_page(pfn);
|
||||
|
||||
if (PageHighMem(page)) {
|
||||
phys = __pfn_to_phys(pfn);
|
||||
if (PhysHighMem(phys)) {
|
||||
if (len + offset > PAGE_SIZE)
|
||||
len = PAGE_SIZE - offset;
|
||||
|
||||
if (cache_is_vipt_nonaliasing()) {
|
||||
vaddr = kmap_atomic(page);
|
||||
vaddr = kmap_atomic_pfn(pfn);
|
||||
op(vaddr + offset, len, dir);
|
||||
kunmap_atomic(vaddr);
|
||||
} else {
|
||||
struct page *page = phys_to_page(phys);
|
||||
|
||||
vaddr = kmap_high_get(page);
|
||||
if (vaddr) {
|
||||
op(vaddr + offset, len, dir);
|
||||
@@ -662,7 +661,8 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vaddr = page_address(page) + offset;
|
||||
phys += offset;
|
||||
vaddr = phys_to_virt(phys);
|
||||
op(vaddr, len, dir);
|
||||
}
|
||||
offset = 0;
|
||||
@@ -676,14 +676,11 @@ static void dma_cache_maint_page(struct page *page, unsigned long offset,
|
||||
* Note: Drivers should NOT use this function directly.
|
||||
* Use the driver DMA support - see dma-mapping.h (dma_sync_*)
|
||||
*/
|
||||
static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
|
||||
size_t size, enum dma_data_direction dir)
|
||||
void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
phys_addr_t paddr;
|
||||
dma_cache_maint_page(paddr, size, dir, dmac_map_area);
|
||||
|
||||
dma_cache_maint_page(page, off, size, dir, dmac_map_area);
|
||||
|
||||
paddr = page_to_phys(page) + off;
|
||||
if (dir == DMA_FROM_DEVICE) {
|
||||
outer_inv_range(paddr, paddr + size);
|
||||
} else {
|
||||
@@ -692,17 +689,15 @@ static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
|
||||
/* FIXME: non-speculating: flush on bidirectional mappings? */
|
||||
}
|
||||
|
||||
static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
|
||||
size_t size, enum dma_data_direction dir)
|
||||
void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
phys_addr_t paddr = page_to_phys(page) + off;
|
||||
|
||||
/* FIXME: non-speculating: not required */
|
||||
/* in any case, don't bother invalidating if DMA to device */
|
||||
if (dir != DMA_TO_DEVICE) {
|
||||
outer_inv_range(paddr, paddr + size);
|
||||
|
||||
dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
|
||||
dma_cache_maint_page(paddr, size, dir, dmac_unmap_area);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -737,6 +732,9 @@ static int __dma_info_to_prot(enum dma_data_direction dir, unsigned long attrs)
|
||||
if (attrs & DMA_ATTR_PRIVILEGED)
|
||||
prot |= IOMMU_PRIV;
|
||||
|
||||
if (attrs & DMA_ATTR_MMIO)
|
||||
prot |= IOMMU_MMIO;
|
||||
|
||||
switch (dir) {
|
||||
case DMA_BIDIRECTIONAL:
|
||||
return prot | IOMMU_READ | IOMMU_WRITE;
|
||||
@@ -1205,7 +1203,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
|
||||
unsigned int len = PAGE_ALIGN(s->offset + s->length);
|
||||
|
||||
if (!dev->dma_coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
|
||||
__dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
|
||||
arch_sync_dma_for_device(sg_phys(s), s->length, dir);
|
||||
|
||||
prot = __dma_info_to_prot(dir, attrs);
|
||||
|
||||
@@ -1307,8 +1305,7 @@ static void arm_iommu_unmap_sg(struct device *dev,
|
||||
__iommu_remove_mapping(dev, sg_dma_address(s),
|
||||
sg_dma_len(s));
|
||||
if (!dev->dma_coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
|
||||
__dma_page_dev_to_cpu(sg_page(s), s->offset,
|
||||
s->length, dir);
|
||||
arch_sync_dma_for_cpu(sg_phys(s), s->length, dir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1330,7 +1327,7 @@ static void arm_iommu_sync_sg_for_cpu(struct device *dev,
|
||||
return;
|
||||
|
||||
for_each_sg(sg, s, nents, i)
|
||||
__dma_page_dev_to_cpu(sg_page(s), s->offset, s->length, dir);
|
||||
arch_sync_dma_for_cpu(sg_phys(s), s->length, dir);
|
||||
|
||||
}
|
||||
|
||||
@@ -1352,29 +1349,31 @@ static void arm_iommu_sync_sg_for_device(struct device *dev,
|
||||
return;
|
||||
|
||||
for_each_sg(sg, s, nents, i)
|
||||
__dma_page_cpu_to_dev(sg_page(s), s->offset, s->length, dir);
|
||||
arch_sync_dma_for_device(sg_phys(s), s->length, dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* arm_iommu_map_page
|
||||
* arm_iommu_map_phys
|
||||
* @dev: valid struct device pointer
|
||||
* @page: page that buffer resides in
|
||||
* @offset: offset into page for start of buffer
|
||||
* @phys: physical address that buffer resides in
|
||||
* @size: size of buffer to map
|
||||
* @dir: DMA transfer direction
|
||||
* @attrs: DMA mapping attributes
|
||||
*
|
||||
* IOMMU aware version of arm_dma_map_page()
|
||||
*/
|
||||
static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
static dma_addr_t arm_iommu_map_phys(struct device *dev, phys_addr_t phys,
|
||||
size_t size, enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
|
||||
int len = PAGE_ALIGN(size + offset_in_page(phys));
|
||||
phys_addr_t addr = phys & PAGE_MASK;
|
||||
dma_addr_t dma_addr;
|
||||
int ret, prot, len = PAGE_ALIGN(size + offset);
|
||||
int ret, prot;
|
||||
|
||||
if (!dev->dma_coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
|
||||
__dma_page_cpu_to_dev(page, offset, size, dir);
|
||||
if (!dev->dma_coherent &&
|
||||
!(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)))
|
||||
arch_sync_dma_for_device(phys, size, dir);
|
||||
|
||||
dma_addr = __alloc_iova(mapping, len);
|
||||
if (dma_addr == DMA_MAPPING_ERROR)
|
||||
@@ -1382,12 +1381,11 @@ static dma_addr_t arm_iommu_map_page(struct device *dev, struct page *page,
|
||||
|
||||
prot = __dma_info_to_prot(dir, attrs);
|
||||
|
||||
ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len,
|
||||
prot, GFP_KERNEL);
|
||||
ret = iommu_map(mapping->domain, dma_addr, addr, len, prot, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
return dma_addr + offset;
|
||||
return dma_addr + offset_in_page(phys);
|
||||
fail:
|
||||
__free_iova(mapping, dma_addr, len);
|
||||
return DMA_MAPPING_ERROR;
|
||||
@@ -1399,100 +1397,45 @@ fail:
|
||||
* @handle: DMA address of buffer
|
||||
* @size: size of buffer (same as passed to dma_map_page)
|
||||
* @dir: DMA transfer direction (same as passed to dma_map_page)
|
||||
* @attrs: DMA mapping attributes
|
||||
*
|
||||
* IOMMU aware version of arm_dma_unmap_page()
|
||||
* IOMMU aware version of arm_dma_unmap_phys()
|
||||
*/
|
||||
static void arm_iommu_unmap_page(struct device *dev, dma_addr_t handle,
|
||||
static void arm_iommu_unmap_phys(struct device *dev, dma_addr_t handle,
|
||||
size_t size, enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
|
||||
dma_addr_t iova = handle & PAGE_MASK;
|
||||
struct page *page;
|
||||
int offset = handle & ~PAGE_MASK;
|
||||
int len = PAGE_ALIGN(size + offset);
|
||||
|
||||
if (!iova)
|
||||
return;
|
||||
|
||||
if (!dev->dma_coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC)) {
|
||||
page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
|
||||
__dma_page_dev_to_cpu(page, offset, size, dir);
|
||||
if (!dev->dma_coherent &&
|
||||
!(attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO))) {
|
||||
phys_addr_t phys = iommu_iova_to_phys(mapping->domain, iova);
|
||||
|
||||
arch_sync_dma_for_cpu(phys + offset, size, dir);
|
||||
}
|
||||
|
||||
iommu_unmap(mapping->domain, iova, len);
|
||||
__free_iova(mapping, iova, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* arm_iommu_map_resource - map a device resource for DMA
|
||||
* @dev: valid struct device pointer
|
||||
* @phys_addr: physical address of resource
|
||||
* @size: size of resource to map
|
||||
* @dir: DMA transfer direction
|
||||
*/
|
||||
static dma_addr_t arm_iommu_map_resource(struct device *dev,
|
||||
phys_addr_t phys_addr, size_t size,
|
||||
enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
|
||||
dma_addr_t dma_addr;
|
||||
int ret, prot;
|
||||
phys_addr_t addr = phys_addr & PAGE_MASK;
|
||||
unsigned int offset = phys_addr & ~PAGE_MASK;
|
||||
size_t len = PAGE_ALIGN(size + offset);
|
||||
|
||||
dma_addr = __alloc_iova(mapping, len);
|
||||
if (dma_addr == DMA_MAPPING_ERROR)
|
||||
return dma_addr;
|
||||
|
||||
prot = __dma_info_to_prot(dir, attrs) | IOMMU_MMIO;
|
||||
|
||||
ret = iommu_map(mapping->domain, dma_addr, addr, len, prot, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
return dma_addr + offset;
|
||||
fail:
|
||||
__free_iova(mapping, dma_addr, len);
|
||||
return DMA_MAPPING_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* arm_iommu_unmap_resource - unmap a device DMA resource
|
||||
* @dev: valid struct device pointer
|
||||
* @dma_handle: DMA address to resource
|
||||
* @size: size of resource to map
|
||||
* @dir: DMA transfer direction
|
||||
*/
|
||||
static void arm_iommu_unmap_resource(struct device *dev, dma_addr_t dma_handle,
|
||||
size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
|
||||
dma_addr_t iova = dma_handle & PAGE_MASK;
|
||||
unsigned int offset = dma_handle & ~PAGE_MASK;
|
||||
size_t len = PAGE_ALIGN(size + offset);
|
||||
|
||||
if (!iova)
|
||||
return;
|
||||
|
||||
iommu_unmap(mapping->domain, iova, len);
|
||||
__free_iova(mapping, iova, len);
|
||||
}
|
||||
|
||||
static void arm_iommu_sync_single_for_cpu(struct device *dev,
|
||||
dma_addr_t handle, size_t size, enum dma_data_direction dir)
|
||||
{
|
||||
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
|
||||
dma_addr_t iova = handle & PAGE_MASK;
|
||||
struct page *page;
|
||||
unsigned int offset = handle & ~PAGE_MASK;
|
||||
phys_addr_t phys;
|
||||
|
||||
if (dev->dma_coherent || !iova)
|
||||
return;
|
||||
|
||||
page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
|
||||
__dma_page_dev_to_cpu(page, offset, size, dir);
|
||||
phys = iommu_iova_to_phys(mapping->domain, iova);
|
||||
arch_sync_dma_for_cpu(phys + offset, size, dir);
|
||||
}
|
||||
|
||||
static void arm_iommu_sync_single_for_device(struct device *dev,
|
||||
@@ -1500,14 +1443,14 @@ static void arm_iommu_sync_single_for_device(struct device *dev,
|
||||
{
|
||||
struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
|
||||
dma_addr_t iova = handle & PAGE_MASK;
|
||||
struct page *page;
|
||||
unsigned int offset = handle & ~PAGE_MASK;
|
||||
phys_addr_t phys;
|
||||
|
||||
if (dev->dma_coherent || !iova)
|
||||
return;
|
||||
|
||||
page = phys_to_page(iommu_iova_to_phys(mapping->domain, iova));
|
||||
__dma_page_cpu_to_dev(page, offset, size, dir);
|
||||
phys = iommu_iova_to_phys(mapping->domain, iova);
|
||||
arch_sync_dma_for_device(phys + offset, size, dir);
|
||||
}
|
||||
|
||||
static const struct dma_map_ops iommu_ops = {
|
||||
@@ -1516,8 +1459,8 @@ static const struct dma_map_ops iommu_ops = {
|
||||
.mmap = arm_iommu_mmap_attrs,
|
||||
.get_sgtable = arm_iommu_get_sgtable,
|
||||
|
||||
.map_page = arm_iommu_map_page,
|
||||
.unmap_page = arm_iommu_unmap_page,
|
||||
.map_phys = arm_iommu_map_phys,
|
||||
.unmap_phys = arm_iommu_unmap_phys,
|
||||
.sync_single_for_cpu = arm_iommu_sync_single_for_cpu,
|
||||
.sync_single_for_device = arm_iommu_sync_single_for_device,
|
||||
|
||||
@@ -1525,9 +1468,6 @@ static const struct dma_map_ops iommu_ops = {
|
||||
.unmap_sg = arm_iommu_unmap_sg,
|
||||
.sync_sg_for_cpu = arm_iommu_sync_sg_for_cpu,
|
||||
.sync_sg_for_device = arm_iommu_sync_sg_for_device,
|
||||
|
||||
.map_resource = arm_iommu_map_resource,
|
||||
.unmap_resource = arm_iommu_unmap_resource,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1794,20 +1734,6 @@ void arch_teardown_dma_ops(struct device *dev)
|
||||
set_dma_ops(dev, NULL);
|
||||
}
|
||||
|
||||
void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
__dma_page_cpu_to_dev(phys_to_page(paddr), paddr & (PAGE_SIZE - 1),
|
||||
size, dir);
|
||||
}
|
||||
|
||||
void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
__dma_page_dev_to_cpu(phys_to_page(paddr), paddr & (PAGE_SIZE - 1),
|
||||
size, dir);
|
||||
}
|
||||
|
||||
void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
|
||||
gfp_t gfp, unsigned long attrs)
|
||||
{
|
||||
|
||||
@@ -521,18 +521,24 @@ static void jazz_dma_free(struct device *dev, size_t size, void *vaddr,
|
||||
__free_pages(virt_to_page(vaddr), get_order(size));
|
||||
}
|
||||
|
||||
static dma_addr_t jazz_dma_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
static dma_addr_t jazz_dma_map_phys(struct device *dev, phys_addr_t phys,
|
||||
size_t size, enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
phys_addr_t phys = page_to_phys(page) + offset;
|
||||
if (unlikely(attrs & DMA_ATTR_MMIO))
|
||||
/*
|
||||
* This check is included because older versions of the code lacked
|
||||
* MMIO path support, and my ability to test this path is limited.
|
||||
* However, from a software technical standpoint, there is no restriction,
|
||||
* as the following code operates solely on physical addresses.
|
||||
*/
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
|
||||
arch_sync_dma_for_device(phys, size, dir);
|
||||
return vdma_alloc(phys, size);
|
||||
}
|
||||
|
||||
static void jazz_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
|
||||
static void jazz_dma_unmap_phys(struct device *dev, dma_addr_t dma_addr,
|
||||
size_t size, enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
|
||||
@@ -607,8 +613,8 @@ static void jazz_dma_sync_sg_for_cpu(struct device *dev,
|
||||
const struct dma_map_ops jazz_dma_ops = {
|
||||
.alloc = jazz_dma_alloc,
|
||||
.free = jazz_dma_free,
|
||||
.map_page = jazz_dma_map_page,
|
||||
.unmap_page = jazz_dma_unmap_page,
|
||||
.map_phys = jazz_dma_map_phys,
|
||||
.unmap_phys = jazz_dma_unmap_phys,
|
||||
.map_sg = jazz_dma_map_sg,
|
||||
.unmap_sg = jazz_dma_unmap_sg,
|
||||
.sync_single_for_cpu = jazz_dma_sync_single_for_cpu,
|
||||
|
||||
@@ -274,12 +274,12 @@ extern void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
|
||||
unsigned long mask, gfp_t flag, int node);
|
||||
extern void iommu_free_coherent(struct iommu_table *tbl, size_t size,
|
||||
void *vaddr, dma_addr_t dma_handle);
|
||||
extern dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
|
||||
struct page *page, unsigned long offset,
|
||||
size_t size, unsigned long mask,
|
||||
extern dma_addr_t iommu_map_phys(struct device *dev, struct iommu_table *tbl,
|
||||
phys_addr_t phys, size_t size,
|
||||
unsigned long mask,
|
||||
enum dma_data_direction direction,
|
||||
unsigned long attrs);
|
||||
extern void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle,
|
||||
extern void iommu_unmap_phys(struct iommu_table *tbl, dma_addr_t dma_handle,
|
||||
size_t size, enum dma_data_direction direction,
|
||||
unsigned long attrs);
|
||||
|
||||
|
||||
@@ -93,28 +93,26 @@ static void dma_iommu_free_coherent(struct device *dev, size_t size,
|
||||
|
||||
/* Creates TCEs for a user provided buffer. The user buffer must be
|
||||
* contiguous real kernel storage (not vmalloc). The address passed here
|
||||
* comprises a page address and offset into that page. The dma_addr_t
|
||||
* returned will point to the same byte within the page as was passed in.
|
||||
* is a physical address to that page. The dma_addr_t returned will point
|
||||
* to the same byte within the page as was passed in.
|
||||
*/
|
||||
static dma_addr_t dma_iommu_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size,
|
||||
static dma_addr_t dma_iommu_map_phys(struct device *dev, phys_addr_t phys,
|
||||
size_t size,
|
||||
enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
{
|
||||
return iommu_map_page(dev, get_iommu_table_base(dev), page, offset,
|
||||
size, dma_get_mask(dev), direction, attrs);
|
||||
return iommu_map_phys(dev, get_iommu_table_base(dev), phys, size,
|
||||
dma_get_mask(dev), direction, attrs);
|
||||
}
|
||||
|
||||
|
||||
static void dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle,
|
||||
static void dma_iommu_unmap_phys(struct device *dev, dma_addr_t dma_handle,
|
||||
size_t size, enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
{
|
||||
iommu_unmap_page(get_iommu_table_base(dev), dma_handle, size, direction,
|
||||
iommu_unmap_phys(get_iommu_table_base(dev), dma_handle, size, direction,
|
||||
attrs);
|
||||
}
|
||||
|
||||
|
||||
static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
|
||||
int nelems, enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
@@ -211,8 +209,8 @@ const struct dma_map_ops dma_iommu_ops = {
|
||||
.map_sg = dma_iommu_map_sg,
|
||||
.unmap_sg = dma_iommu_unmap_sg,
|
||||
.dma_supported = dma_iommu_dma_supported,
|
||||
.map_page = dma_iommu_map_page,
|
||||
.unmap_page = dma_iommu_unmap_page,
|
||||
.map_phys = dma_iommu_map_phys,
|
||||
.unmap_phys = dma_iommu_unmap_phys,
|
||||
.get_required_mask = dma_iommu_get_required_mask,
|
||||
.mmap = dma_common_mmap,
|
||||
.get_sgtable = dma_common_get_sgtable,
|
||||
|
||||
@@ -848,12 +848,12 @@ EXPORT_SYMBOL_GPL(iommu_tce_table_put);
|
||||
|
||||
/* Creates TCEs for a user provided buffer. The user buffer must be
|
||||
* contiguous real kernel storage (not vmalloc). The address passed here
|
||||
* comprises a page address and offset into that page. The dma_addr_t
|
||||
* returned will point to the same byte within the page as was passed in.
|
||||
* is physical address into that page. The dma_addr_t returned will point
|
||||
* to the same byte within the page as was passed in.
|
||||
*/
|
||||
dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
|
||||
struct page *page, unsigned long offset, size_t size,
|
||||
unsigned long mask, enum dma_data_direction direction,
|
||||
dma_addr_t iommu_map_phys(struct device *dev, struct iommu_table *tbl,
|
||||
phys_addr_t phys, size_t size, unsigned long mask,
|
||||
enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
{
|
||||
dma_addr_t dma_handle = DMA_MAPPING_ERROR;
|
||||
@@ -863,7 +863,7 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
|
||||
|
||||
BUG_ON(direction == DMA_NONE);
|
||||
|
||||
vaddr = page_address(page) + offset;
|
||||
vaddr = phys_to_virt(phys);
|
||||
uaddr = (unsigned long)vaddr;
|
||||
|
||||
if (tbl) {
|
||||
@@ -890,7 +890,7 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
|
||||
return dma_handle;
|
||||
}
|
||||
|
||||
void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle,
|
||||
void iommu_unmap_phys(struct iommu_table *tbl, dma_addr_t dma_handle,
|
||||
size_t size, enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
{
|
||||
|
||||
@@ -551,18 +551,20 @@ static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
|
||||
|
||||
/* Creates TCEs for a user provided buffer. The user buffer must be
|
||||
* contiguous real kernel storage (not vmalloc). The address passed here
|
||||
* comprises a page address and offset into that page. The dma_addr_t
|
||||
* returned will point to the same byte within the page as was passed in.
|
||||
* is physical address to that hat page. The dma_addr_t returned will point
|
||||
* to the same byte within the page as was passed in.
|
||||
*/
|
||||
|
||||
static dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page,
|
||||
unsigned long offset, size_t size, enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
static dma_addr_t ps3_sb_map_phys(struct device *_dev, phys_addr_t phys,
|
||||
size_t size, enum dma_data_direction direction, unsigned long attrs)
|
||||
{
|
||||
struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
|
||||
int result;
|
||||
dma_addr_t bus_addr;
|
||||
void *ptr = page_address(page) + offset;
|
||||
void *ptr = phys_to_virt(phys);
|
||||
|
||||
if (unlikely(attrs & DMA_ATTR_MMIO))
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
|
||||
&bus_addr,
|
||||
@@ -577,8 +579,8 @@ static dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page,
|
||||
return bus_addr;
|
||||
}
|
||||
|
||||
static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page,
|
||||
unsigned long offset, size_t size,
|
||||
static dma_addr_t ps3_ioc0_map_phys(struct device *_dev, phys_addr_t phys,
|
||||
size_t size,
|
||||
enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
{
|
||||
@@ -586,7 +588,10 @@ static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page,
|
||||
int result;
|
||||
dma_addr_t bus_addr;
|
||||
u64 iopte_flag;
|
||||
void *ptr = page_address(page) + offset;
|
||||
void *ptr = phys_to_virt(phys);
|
||||
|
||||
if (unlikely(attrs & DMA_ATTR_MMIO))
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
iopte_flag = CBE_IOPTE_M;
|
||||
switch (direction) {
|
||||
@@ -613,7 +618,7 @@ static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page,
|
||||
return bus_addr;
|
||||
}
|
||||
|
||||
static void ps3_unmap_page(struct device *_dev, dma_addr_t dma_addr,
|
||||
static void ps3_unmap_phys(struct device *_dev, dma_addr_t dma_addr,
|
||||
size_t size, enum dma_data_direction direction, unsigned long attrs)
|
||||
{
|
||||
struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
|
||||
@@ -690,8 +695,8 @@ static const struct dma_map_ops ps3_sb_dma_ops = {
|
||||
.map_sg = ps3_sb_map_sg,
|
||||
.unmap_sg = ps3_sb_unmap_sg,
|
||||
.dma_supported = ps3_dma_supported,
|
||||
.map_page = ps3_sb_map_page,
|
||||
.unmap_page = ps3_unmap_page,
|
||||
.map_phys = ps3_sb_map_phys,
|
||||
.unmap_phys = ps3_unmap_phys,
|
||||
.mmap = dma_common_mmap,
|
||||
.get_sgtable = dma_common_get_sgtable,
|
||||
.alloc_pages_op = dma_common_alloc_pages,
|
||||
@@ -704,8 +709,8 @@ static const struct dma_map_ops ps3_ioc0_dma_ops = {
|
||||
.map_sg = ps3_ioc0_map_sg,
|
||||
.unmap_sg = ps3_ioc0_unmap_sg,
|
||||
.dma_supported = ps3_dma_supported,
|
||||
.map_page = ps3_ioc0_map_page,
|
||||
.unmap_page = ps3_unmap_page,
|
||||
.map_phys = ps3_ioc0_map_phys,
|
||||
.unmap_phys = ps3_unmap_phys,
|
||||
.mmap = dma_common_mmap,
|
||||
.get_sgtable = dma_common_get_sgtable,
|
||||
.alloc_pages_op = dma_common_alloc_pages,
|
||||
|
||||
@@ -86,17 +86,18 @@ static void ibmebus_free_coherent(struct device *dev,
|
||||
kfree(vaddr);
|
||||
}
|
||||
|
||||
static dma_addr_t ibmebus_map_page(struct device *dev,
|
||||
struct page *page,
|
||||
unsigned long offset,
|
||||
static dma_addr_t ibmebus_map_phys(struct device *dev, phys_addr_t phys,
|
||||
size_t size,
|
||||
enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
{
|
||||
return (dma_addr_t)(page_address(page) + offset);
|
||||
if (attrs & DMA_ATTR_MMIO)
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
return (dma_addr_t)(phys_to_virt(phys));
|
||||
}
|
||||
|
||||
static void ibmebus_unmap_page(struct device *dev,
|
||||
static void ibmebus_unmap_phys(struct device *dev,
|
||||
dma_addr_t dma_addr,
|
||||
size_t size,
|
||||
enum dma_data_direction direction,
|
||||
@@ -146,8 +147,8 @@ static const struct dma_map_ops ibmebus_dma_ops = {
|
||||
.unmap_sg = ibmebus_unmap_sg,
|
||||
.dma_supported = ibmebus_dma_supported,
|
||||
.get_required_mask = ibmebus_dma_get_required_mask,
|
||||
.map_page = ibmebus_map_page,
|
||||
.unmap_page = ibmebus_unmap_page,
|
||||
.map_phys = ibmebus_map_phys,
|
||||
.unmap_phys = ibmebus_unmap_phys,
|
||||
};
|
||||
|
||||
static int ibmebus_match_path(struct device *dev, const void *data)
|
||||
|
||||
@@ -512,18 +512,21 @@ static void vio_dma_iommu_free_coherent(struct device *dev, size_t size,
|
||||
vio_cmo_dealloc(viodev, roundup(size, PAGE_SIZE));
|
||||
}
|
||||
|
||||
static dma_addr_t vio_dma_iommu_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size,
|
||||
enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
static dma_addr_t vio_dma_iommu_map_phys(struct device *dev, phys_addr_t phys,
|
||||
size_t size,
|
||||
enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct vio_dev *viodev = to_vio_dev(dev);
|
||||
struct iommu_table *tbl = get_iommu_table_base(dev);
|
||||
dma_addr_t ret = DMA_MAPPING_ERROR;
|
||||
|
||||
if (unlikely(attrs & DMA_ATTR_MMIO))
|
||||
return ret;
|
||||
|
||||
if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl))))
|
||||
goto out_fail;
|
||||
ret = iommu_map_page(dev, tbl, page, offset, size, dma_get_mask(dev),
|
||||
ret = iommu_map_phys(dev, tbl, phys, size, dma_get_mask(dev),
|
||||
direction, attrs);
|
||||
if (unlikely(ret == DMA_MAPPING_ERROR))
|
||||
goto out_deallocate;
|
||||
@@ -536,7 +539,7 @@ out_fail:
|
||||
return DMA_MAPPING_ERROR;
|
||||
}
|
||||
|
||||
static void vio_dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle,
|
||||
static void vio_dma_iommu_unmap_phys(struct device *dev, dma_addr_t dma_handle,
|
||||
size_t size,
|
||||
enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
@@ -544,7 +547,7 @@ static void vio_dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle,
|
||||
struct vio_dev *viodev = to_vio_dev(dev);
|
||||
struct iommu_table *tbl = get_iommu_table_base(dev);
|
||||
|
||||
iommu_unmap_page(tbl, dma_handle, size, direction, attrs);
|
||||
iommu_unmap_phys(tbl, dma_handle, size, direction, attrs);
|
||||
vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl)));
|
||||
}
|
||||
|
||||
@@ -605,8 +608,8 @@ static const struct dma_map_ops vio_dma_mapping_ops = {
|
||||
.free = vio_dma_iommu_free_coherent,
|
||||
.map_sg = vio_dma_iommu_map_sg,
|
||||
.unmap_sg = vio_dma_iommu_unmap_sg,
|
||||
.map_page = vio_dma_iommu_map_page,
|
||||
.unmap_page = vio_dma_iommu_unmap_page,
|
||||
.map_phys = vio_dma_iommu_map_phys,
|
||||
.unmap_phys = vio_dma_iommu_unmap_phys,
|
||||
.dma_supported = dma_iommu_dma_supported,
|
||||
.get_required_mask = dma_iommu_get_required_mask,
|
||||
.mmap = dma_common_mmap,
|
||||
|
||||
@@ -260,26 +260,35 @@ static void dma_4u_free_coherent(struct device *dev, size_t size,
|
||||
free_pages((unsigned long)cpu, order);
|
||||
}
|
||||
|
||||
static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t sz,
|
||||
enum dma_data_direction direction,
|
||||
static dma_addr_t dma_4u_map_phys(struct device *dev, phys_addr_t phys,
|
||||
size_t sz, enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct iommu *iommu;
|
||||
struct strbuf *strbuf;
|
||||
iopte_t *base;
|
||||
unsigned long flags, npages, oaddr;
|
||||
unsigned long i, base_paddr, ctx;
|
||||
unsigned long i, ctx;
|
||||
u32 bus_addr, ret;
|
||||
unsigned long iopte_protection;
|
||||
|
||||
if (unlikely(attrs & DMA_ATTR_MMIO))
|
||||
/*
|
||||
* This check is included because older versions of the code
|
||||
* lacked MMIO path support, and my ability to test this path
|
||||
* is limited. However, from a software technical standpoint,
|
||||
* there is no restriction, as the following code operates
|
||||
* solely on physical addresses.
|
||||
*/
|
||||
goto bad_no_ctx;
|
||||
|
||||
iommu = dev->archdata.iommu;
|
||||
strbuf = dev->archdata.stc;
|
||||
|
||||
if (unlikely(direction == DMA_NONE))
|
||||
goto bad_no_ctx;
|
||||
|
||||
oaddr = (unsigned long)(page_address(page) + offset);
|
||||
oaddr = (unsigned long)(phys_to_virt(phys));
|
||||
npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
|
||||
npages >>= IO_PAGE_SHIFT;
|
||||
|
||||
@@ -296,7 +305,6 @@ static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page,
|
||||
bus_addr = (iommu->tbl.table_map_base +
|
||||
((base - iommu->page_table) << IO_PAGE_SHIFT));
|
||||
ret = bus_addr | (oaddr & ~IO_PAGE_MASK);
|
||||
base_paddr = __pa(oaddr & IO_PAGE_MASK);
|
||||
if (strbuf->strbuf_enabled)
|
||||
iopte_protection = IOPTE_STREAMING(ctx);
|
||||
else
|
||||
@@ -304,8 +312,8 @@ static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page,
|
||||
if (direction != DMA_TO_DEVICE)
|
||||
iopte_protection |= IOPTE_WRITE;
|
||||
|
||||
for (i = 0; i < npages; i++, base++, base_paddr += IO_PAGE_SIZE)
|
||||
iopte_val(*base) = iopte_protection | base_paddr;
|
||||
for (i = 0; i < npages; i++, base++, phys += IO_PAGE_SIZE)
|
||||
iopte_val(*base) = iopte_protection | phys;
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -383,7 +391,7 @@ do_flush_sync:
|
||||
vaddr, ctx, npages);
|
||||
}
|
||||
|
||||
static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr,
|
||||
static void dma_4u_unmap_phys(struct device *dev, dma_addr_t bus_addr,
|
||||
size_t sz, enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
{
|
||||
@@ -753,8 +761,8 @@ static int dma_4u_supported(struct device *dev, u64 device_mask)
|
||||
static const struct dma_map_ops sun4u_dma_ops = {
|
||||
.alloc = dma_4u_alloc_coherent,
|
||||
.free = dma_4u_free_coherent,
|
||||
.map_page = dma_4u_map_page,
|
||||
.unmap_page = dma_4u_unmap_page,
|
||||
.map_phys = dma_4u_map_phys,
|
||||
.unmap_phys = dma_4u_unmap_phys,
|
||||
.map_sg = dma_4u_map_sg,
|
||||
.unmap_sg = dma_4u_unmap_sg,
|
||||
.sync_single_for_cpu = dma_4u_sync_single_for_cpu,
|
||||
|
||||
@@ -352,9 +352,8 @@ static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu,
|
||||
free_pages((unsigned long)cpu, order);
|
||||
}
|
||||
|
||||
static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t sz,
|
||||
enum dma_data_direction direction,
|
||||
static dma_addr_t dma_4v_map_phys(struct device *dev, phys_addr_t phys,
|
||||
size_t sz, enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct iommu *iommu;
|
||||
@@ -362,18 +361,27 @@ static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
|
||||
struct iommu_map_table *tbl;
|
||||
u64 mask;
|
||||
unsigned long flags, npages, oaddr;
|
||||
unsigned long i, base_paddr;
|
||||
unsigned long prot;
|
||||
unsigned long i, prot;
|
||||
dma_addr_t bus_addr, ret;
|
||||
long entry;
|
||||
|
||||
if (unlikely(attrs & DMA_ATTR_MMIO))
|
||||
/*
|
||||
* This check is included because older versions of the code
|
||||
* lacked MMIO path support, and my ability to test this path
|
||||
* is limited. However, from a software technical standpoint,
|
||||
* there is no restriction, as the following code operates
|
||||
* solely on physical addresses.
|
||||
*/
|
||||
goto bad;
|
||||
|
||||
iommu = dev->archdata.iommu;
|
||||
atu = iommu->atu;
|
||||
|
||||
if (unlikely(direction == DMA_NONE))
|
||||
goto bad;
|
||||
|
||||
oaddr = (unsigned long)(page_address(page) + offset);
|
||||
oaddr = (unsigned long)(phys_to_virt(phys));
|
||||
npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
|
||||
npages >>= IO_PAGE_SHIFT;
|
||||
|
||||
@@ -391,7 +399,6 @@ static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
|
||||
|
||||
bus_addr = (tbl->table_map_base + (entry << IO_PAGE_SHIFT));
|
||||
ret = bus_addr | (oaddr & ~IO_PAGE_MASK);
|
||||
base_paddr = __pa(oaddr & IO_PAGE_MASK);
|
||||
prot = HV_PCI_MAP_ATTR_READ;
|
||||
if (direction != DMA_TO_DEVICE)
|
||||
prot |= HV_PCI_MAP_ATTR_WRITE;
|
||||
@@ -403,8 +410,8 @@ static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
|
||||
|
||||
iommu_batch_start(dev, prot, entry);
|
||||
|
||||
for (i = 0; i < npages; i++, base_paddr += IO_PAGE_SIZE) {
|
||||
long err = iommu_batch_add(base_paddr, mask);
|
||||
for (i = 0; i < npages; i++, phys += IO_PAGE_SIZE) {
|
||||
long err = iommu_batch_add(phys, mask);
|
||||
if (unlikely(err < 0L))
|
||||
goto iommu_map_fail;
|
||||
}
|
||||
@@ -426,7 +433,7 @@ iommu_map_fail:
|
||||
return DMA_MAPPING_ERROR;
|
||||
}
|
||||
|
||||
static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr,
|
||||
static void dma_4v_unmap_phys(struct device *dev, dma_addr_t bus_addr,
|
||||
size_t sz, enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
{
|
||||
@@ -686,8 +693,8 @@ static int dma_4v_supported(struct device *dev, u64 device_mask)
|
||||
static const struct dma_map_ops sun4v_dma_ops = {
|
||||
.alloc = dma_4v_alloc_coherent,
|
||||
.free = dma_4v_free_coherent,
|
||||
.map_page = dma_4v_map_page,
|
||||
.unmap_page = dma_4v_unmap_page,
|
||||
.map_phys = dma_4v_map_phys,
|
||||
.unmap_phys = dma_4v_unmap_phys,
|
||||
.map_sg = dma_4v_map_sg,
|
||||
.unmap_sg = dma_4v_unmap_sg,
|
||||
.dma_supported = dma_4v_supported,
|
||||
|
||||
@@ -94,13 +94,14 @@ static int __init iounit_init(void)
|
||||
subsys_initcall(iounit_init);
|
||||
|
||||
/* One has to hold iounit->lock to call this */
|
||||
static unsigned long iounit_get_area(struct iounit_struct *iounit, unsigned long vaddr, int size)
|
||||
static dma_addr_t iounit_get_area(struct iounit_struct *iounit,
|
||||
phys_addr_t phys, int size)
|
||||
{
|
||||
int i, j, k, npages;
|
||||
unsigned long rotor, scan, limit;
|
||||
iopte_t iopte;
|
||||
|
||||
npages = ((vaddr & ~PAGE_MASK) + size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
|
||||
npages = (offset_in_page(phys) + size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
|
||||
|
||||
/* A tiny bit of magic ingredience :) */
|
||||
switch (npages) {
|
||||
@@ -109,7 +110,7 @@ static unsigned long iounit_get_area(struct iounit_struct *iounit, unsigned long
|
||||
default: i = 0x0213; break;
|
||||
}
|
||||
|
||||
IOD(("iounit_get_area(%08lx,%d[%d])=", vaddr, size, npages));
|
||||
IOD(("%s(%pa,%d[%d])=", __func__, &phys, size, npages));
|
||||
|
||||
next: j = (i & 15);
|
||||
rotor = iounit->rotor[j - 1];
|
||||
@@ -124,7 +125,8 @@ nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
|
||||
}
|
||||
i >>= 4;
|
||||
if (!(i & 15))
|
||||
panic("iounit_get_area: Couldn't find free iopte slots for (%08lx,%d)\n", vaddr, size);
|
||||
panic("iounit_get_area: Couldn't find free iopte slots for (%pa,%d)\n",
|
||||
&phys, size);
|
||||
goto next;
|
||||
}
|
||||
for (k = 1, scan++; k < npages; k++)
|
||||
@@ -132,30 +134,29 @@ nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
|
||||
goto nexti;
|
||||
iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
|
||||
scan -= npages;
|
||||
iopte = MKIOPTE(__pa(vaddr & PAGE_MASK));
|
||||
vaddr = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + (vaddr & ~PAGE_MASK);
|
||||
iopte = MKIOPTE(phys & PAGE_MASK);
|
||||
phys = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + offset_in_page(phys);
|
||||
for (k = 0; k < npages; k++, iopte = __iopte(iopte_val(iopte) + 0x100), scan++) {
|
||||
set_bit(scan, iounit->bmap);
|
||||
sbus_writel(iopte_val(iopte), &iounit->page_table[scan]);
|
||||
}
|
||||
IOD(("%08lx\n", vaddr));
|
||||
return vaddr;
|
||||
IOD(("%pa\n", &phys));
|
||||
return phys;
|
||||
}
|
||||
|
||||
static dma_addr_t iounit_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t len, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
static dma_addr_t iounit_map_phys(struct device *dev, phys_addr_t phys,
|
||||
size_t len, enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
void *vaddr = page_address(page) + offset;
|
||||
struct iounit_struct *iounit = dev->archdata.iommu;
|
||||
unsigned long ret, flags;
|
||||
unsigned long flags;
|
||||
dma_addr_t ret;
|
||||
|
||||
/* XXX So what is maxphys for us and how do drivers know it? */
|
||||
if (!len || len > 256 * 1024)
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
spin_lock_irqsave(&iounit->lock, flags);
|
||||
ret = iounit_get_area(iounit, (unsigned long)vaddr, len);
|
||||
ret = iounit_get_area(iounit, phys, len);
|
||||
spin_unlock_irqrestore(&iounit->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
@@ -171,14 +172,15 @@ static int iounit_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
|
||||
/* FIXME: Cache some resolved pages - often several sg entries are to the same page */
|
||||
spin_lock_irqsave(&iounit->lock, flags);
|
||||
for_each_sg(sgl, sg, nents, i) {
|
||||
sg->dma_address = iounit_get_area(iounit, (unsigned long) sg_virt(sg), sg->length);
|
||||
sg->dma_address =
|
||||
iounit_get_area(iounit, sg_phys(sg), sg->length);
|
||||
sg->dma_length = sg->length;
|
||||
}
|
||||
spin_unlock_irqrestore(&iounit->lock, flags);
|
||||
return nents;
|
||||
}
|
||||
|
||||
static void iounit_unmap_page(struct device *dev, dma_addr_t vaddr, size_t len,
|
||||
static void iounit_unmap_phys(struct device *dev, dma_addr_t vaddr, size_t len,
|
||||
enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
struct iounit_struct *iounit = dev->archdata.iommu;
|
||||
@@ -279,8 +281,8 @@ static const struct dma_map_ops iounit_dma_ops = {
|
||||
.alloc = iounit_alloc,
|
||||
.free = iounit_free,
|
||||
#endif
|
||||
.map_page = iounit_map_page,
|
||||
.unmap_page = iounit_unmap_page,
|
||||
.map_phys = iounit_map_phys,
|
||||
.unmap_phys = iounit_unmap_phys,
|
||||
.map_sg = iounit_map_sg,
|
||||
.unmap_sg = iounit_unmap_sg,
|
||||
};
|
||||
|
||||
@@ -181,18 +181,20 @@ static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte)
|
||||
}
|
||||
}
|
||||
|
||||
static dma_addr_t __sbus_iommu_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t len, bool per_page_flush)
|
||||
static dma_addr_t __sbus_iommu_map_phys(struct device *dev, phys_addr_t paddr,
|
||||
size_t len, bool per_page_flush, unsigned long attrs)
|
||||
{
|
||||
struct iommu_struct *iommu = dev->archdata.iommu;
|
||||
phys_addr_t paddr = page_to_phys(page) + offset;
|
||||
unsigned long off = paddr & ~PAGE_MASK;
|
||||
unsigned long off = offset_in_page(paddr);
|
||||
unsigned long npages = (off + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
unsigned long pfn = __phys_to_pfn(paddr);
|
||||
unsigned int busa, busa0;
|
||||
iopte_t *iopte, *iopte0;
|
||||
int ioptex, i;
|
||||
|
||||
if (unlikely(attrs & DMA_ATTR_MMIO))
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
/* XXX So what is maxphys for us and how do drivers know it? */
|
||||
if (!len || len > 256 * 1024)
|
||||
return DMA_MAPPING_ERROR;
|
||||
@@ -202,10 +204,10 @@ static dma_addr_t __sbus_iommu_map_page(struct device *dev, struct page *page,
|
||||
* XXX Is this a good assumption?
|
||||
* XXX What if someone else unmaps it here and races us?
|
||||
*/
|
||||
if (per_page_flush && !PageHighMem(page)) {
|
||||
if (per_page_flush && !PhysHighMem(paddr)) {
|
||||
unsigned long vaddr, p;
|
||||
|
||||
vaddr = (unsigned long)page_address(page) + offset;
|
||||
vaddr = (unsigned long)phys_to_virt(paddr);
|
||||
for (p = vaddr & PAGE_MASK; p < vaddr + len; p += PAGE_SIZE)
|
||||
flush_page_for_dma(p);
|
||||
}
|
||||
@@ -231,19 +233,19 @@ static dma_addr_t __sbus_iommu_map_page(struct device *dev, struct page *page,
|
||||
return busa0 + off;
|
||||
}
|
||||
|
||||
static dma_addr_t sbus_iommu_map_page_gflush(struct device *dev,
|
||||
struct page *page, unsigned long offset, size_t len,
|
||||
enum dma_data_direction dir, unsigned long attrs)
|
||||
static dma_addr_t sbus_iommu_map_phys_gflush(struct device *dev,
|
||||
phys_addr_t phys, size_t len, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
flush_page_for_dma(0);
|
||||
return __sbus_iommu_map_page(dev, page, offset, len, false);
|
||||
return __sbus_iommu_map_phys(dev, phys, len, false, attrs);
|
||||
}
|
||||
|
||||
static dma_addr_t sbus_iommu_map_page_pflush(struct device *dev,
|
||||
struct page *page, unsigned long offset, size_t len,
|
||||
enum dma_data_direction dir, unsigned long attrs)
|
||||
static dma_addr_t sbus_iommu_map_phys_pflush(struct device *dev,
|
||||
phys_addr_t phys, size_t len, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
return __sbus_iommu_map_page(dev, page, offset, len, true);
|
||||
return __sbus_iommu_map_phys(dev, phys, len, true, attrs);
|
||||
}
|
||||
|
||||
static int __sbus_iommu_map_sg(struct device *dev, struct scatterlist *sgl,
|
||||
@@ -254,8 +256,8 @@ static int __sbus_iommu_map_sg(struct device *dev, struct scatterlist *sgl,
|
||||
int j;
|
||||
|
||||
for_each_sg(sgl, sg, nents, j) {
|
||||
sg->dma_address =__sbus_iommu_map_page(dev, sg_page(sg),
|
||||
sg->offset, sg->length, per_page_flush);
|
||||
sg->dma_address = __sbus_iommu_map_phys(dev, sg_phys(sg),
|
||||
sg->length, per_page_flush, attrs);
|
||||
if (sg->dma_address == DMA_MAPPING_ERROR)
|
||||
return -EIO;
|
||||
sg->dma_length = sg->length;
|
||||
@@ -277,7 +279,7 @@ static int sbus_iommu_map_sg_pflush(struct device *dev, struct scatterlist *sgl,
|
||||
return __sbus_iommu_map_sg(dev, sgl, nents, dir, attrs, true);
|
||||
}
|
||||
|
||||
static void sbus_iommu_unmap_page(struct device *dev, dma_addr_t dma_addr,
|
||||
static void sbus_iommu_unmap_phys(struct device *dev, dma_addr_t dma_addr,
|
||||
size_t len, enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
struct iommu_struct *iommu = dev->archdata.iommu;
|
||||
@@ -303,7 +305,7 @@ static void sbus_iommu_unmap_sg(struct device *dev, struct scatterlist *sgl,
|
||||
int i;
|
||||
|
||||
for_each_sg(sgl, sg, nents, i) {
|
||||
sbus_iommu_unmap_page(dev, sg->dma_address, sg->length, dir,
|
||||
sbus_iommu_unmap_phys(dev, sg->dma_address, sg->length, dir,
|
||||
attrs);
|
||||
sg->dma_address = 0x21212121;
|
||||
}
|
||||
@@ -426,8 +428,8 @@ static const struct dma_map_ops sbus_iommu_dma_gflush_ops = {
|
||||
.alloc = sbus_iommu_alloc,
|
||||
.free = sbus_iommu_free,
|
||||
#endif
|
||||
.map_page = sbus_iommu_map_page_gflush,
|
||||
.unmap_page = sbus_iommu_unmap_page,
|
||||
.map_phys = sbus_iommu_map_phys_gflush,
|
||||
.unmap_phys = sbus_iommu_unmap_phys,
|
||||
.map_sg = sbus_iommu_map_sg_gflush,
|
||||
.unmap_sg = sbus_iommu_unmap_sg,
|
||||
};
|
||||
@@ -437,8 +439,8 @@ static const struct dma_map_ops sbus_iommu_dma_pflush_ops = {
|
||||
.alloc = sbus_iommu_alloc,
|
||||
.free = sbus_iommu_free,
|
||||
#endif
|
||||
.map_page = sbus_iommu_map_page_pflush,
|
||||
.unmap_page = sbus_iommu_unmap_page,
|
||||
.map_phys = sbus_iommu_map_phys_pflush,
|
||||
.unmap_phys = sbus_iommu_unmap_phys,
|
||||
.map_sg = sbus_iommu_map_sg_pflush,
|
||||
.unmap_sg = sbus_iommu_unmap_sg,
|
||||
};
|
||||
|
||||
@@ -222,13 +222,14 @@ static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
|
||||
}
|
||||
|
||||
/* Map a single area into the IOMMU */
|
||||
static dma_addr_t gart_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size,
|
||||
enum dma_data_direction dir,
|
||||
static dma_addr_t gart_map_phys(struct device *dev, phys_addr_t paddr,
|
||||
size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
unsigned long bus;
|
||||
phys_addr_t paddr = page_to_phys(page) + offset;
|
||||
|
||||
if (unlikely(attrs & DMA_ATTR_MMIO))
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
if (!need_iommu(dev, paddr, size))
|
||||
return paddr;
|
||||
@@ -242,7 +243,7 @@ static dma_addr_t gart_map_page(struct device *dev, struct page *page,
|
||||
/*
|
||||
* Free a DMA mapping.
|
||||
*/
|
||||
static void gart_unmap_page(struct device *dev, dma_addr_t dma_addr,
|
||||
static void gart_unmap_phys(struct device *dev, dma_addr_t dma_addr,
|
||||
size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
@@ -282,7 +283,7 @@ static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
|
||||
for_each_sg(sg, s, nents, i) {
|
||||
if (!s->dma_length || !s->length)
|
||||
break;
|
||||
gart_unmap_page(dev, s->dma_address, s->dma_length, dir, 0);
|
||||
gart_unmap_phys(dev, s->dma_address, s->dma_length, dir, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,7 +488,7 @@ static void
|
||||
gart_free_coherent(struct device *dev, size_t size, void *vaddr,
|
||||
dma_addr_t dma_addr, unsigned long attrs)
|
||||
{
|
||||
gart_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL, 0);
|
||||
gart_unmap_phys(dev, dma_addr, size, DMA_BIDIRECTIONAL, 0);
|
||||
dma_direct_free(dev, size, vaddr, dma_addr, attrs);
|
||||
}
|
||||
|
||||
@@ -672,8 +673,8 @@ static __init int init_amd_gatt(struct agp_kern_info *info)
|
||||
static const struct dma_map_ops gart_dma_ops = {
|
||||
.map_sg = gart_map_sg,
|
||||
.unmap_sg = gart_unmap_sg,
|
||||
.map_page = gart_map_page,
|
||||
.unmap_page = gart_unmap_page,
|
||||
.map_phys = gart_map_phys,
|
||||
.unmap_phys = gart_unmap_phys,
|
||||
.alloc = gart_alloc_coherent,
|
||||
.free = gart_free_coherent,
|
||||
.mmap = dma_common_mmap,
|
||||
|
||||
@@ -517,10 +517,10 @@ static u32 hint_lookup[] = {
|
||||
* ccio_io_pdir_entry - Initialize an I/O Pdir.
|
||||
* @pdir_ptr: A pointer into I/O Pdir.
|
||||
* @sid: The Space Identifier.
|
||||
* @vba: The virtual address.
|
||||
* @pba: The physical address.
|
||||
* @hints: The DMA Hint.
|
||||
*
|
||||
* Given a virtual address (vba, arg2) and space id, (sid, arg1),
|
||||
* Given a physical address (pba, arg2) and space id, (sid, arg1),
|
||||
* load the I/O PDIR entry pointed to by pdir_ptr (arg0). Each IO Pdir
|
||||
* entry consists of 8 bytes as shown below (MSB == bit 0):
|
||||
*
|
||||
@@ -543,7 +543,7 @@ static u32 hint_lookup[] = {
|
||||
* index are bits 12:19 of the value returned by LCI.
|
||||
*/
|
||||
static void
|
||||
ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, unsigned long vba,
|
||||
ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, phys_addr_t pba,
|
||||
unsigned long hints)
|
||||
{
|
||||
register unsigned long pa;
|
||||
@@ -557,7 +557,7 @@ ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, unsigned long vba,
|
||||
** "hints" parm includes the VALID bit!
|
||||
** "dep" clobbers the physical address offset bits as well.
|
||||
*/
|
||||
pa = lpa(vba);
|
||||
pa = pba;
|
||||
asm volatile("depw %1,31,12,%0" : "+r" (pa) : "r" (hints));
|
||||
((u32 *)pdir_ptr)[1] = (u32) pa;
|
||||
|
||||
@@ -582,7 +582,7 @@ ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, unsigned long vba,
|
||||
** Grab virtual index [0:11]
|
||||
** Deposit virt_idx bits into I/O PDIR word
|
||||
*/
|
||||
asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (vba));
|
||||
asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (phys_to_virt(pba)));
|
||||
asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci));
|
||||
asm volatile ("depw %1,15,12,%0" : "+r" (pa) : "r" (ci));
|
||||
|
||||
@@ -704,14 +704,14 @@ ccio_dma_supported(struct device *dev, u64 mask)
|
||||
/**
|
||||
* ccio_map_single - Map an address range into the IOMMU.
|
||||
* @dev: The PCI device.
|
||||
* @addr: The start address of the DMA region.
|
||||
* @addr: The physical address of the DMA region.
|
||||
* @size: The length of the DMA region.
|
||||
* @direction: The direction of the DMA transaction (to/from device).
|
||||
*
|
||||
* This function implements the pci_map_single function.
|
||||
*/
|
||||
static dma_addr_t
|
||||
ccio_map_single(struct device *dev, void *addr, size_t size,
|
||||
ccio_map_single(struct device *dev, phys_addr_t addr, size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
int idx;
|
||||
@@ -730,7 +730,7 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
|
||||
BUG_ON(size <= 0);
|
||||
|
||||
/* save offset bits */
|
||||
offset = ((unsigned long) addr) & ~IOVP_MASK;
|
||||
offset = offset_in_page(addr);
|
||||
|
||||
/* round up to nearest IOVP_SIZE */
|
||||
size = ALIGN(size + offset, IOVP_SIZE);
|
||||
@@ -746,15 +746,15 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
|
||||
|
||||
pdir_start = &(ioc->pdir_base[idx]);
|
||||
|
||||
DBG_RUN("%s() %px -> %#lx size: %zu\n",
|
||||
__func__, addr, (long)(iovp | offset), size);
|
||||
DBG_RUN("%s() %pa -> %#lx size: %zu\n",
|
||||
__func__, &addr, (long)(iovp | offset), size);
|
||||
|
||||
/* If not cacheline aligned, force SAFE_DMA on the whole mess */
|
||||
if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES))
|
||||
if ((size % L1_CACHE_BYTES) || (addr % L1_CACHE_BYTES))
|
||||
hint |= HINT_SAFE_DMA;
|
||||
|
||||
while(size > 0) {
|
||||
ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long)addr, hint);
|
||||
ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint);
|
||||
|
||||
DBG_RUN(" pdir %p %08x%08x\n",
|
||||
pdir_start,
|
||||
@@ -773,17 +773,18 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
|
||||
|
||||
|
||||
static dma_addr_t
|
||||
ccio_map_page(struct device *dev, struct page *page, unsigned long offset,
|
||||
size_t size, enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
ccio_map_phys(struct device *dev, phys_addr_t phys, size_t size,
|
||||
enum dma_data_direction direction, unsigned long attrs)
|
||||
{
|
||||
return ccio_map_single(dev, page_address(page) + offset, size,
|
||||
direction);
|
||||
if (unlikely(attrs & DMA_ATTR_MMIO))
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
return ccio_map_single(dev, phys, size, direction);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ccio_unmap_page - Unmap an address range from the IOMMU.
|
||||
* ccio_unmap_phys - Unmap an address range from the IOMMU.
|
||||
* @dev: The PCI device.
|
||||
* @iova: The start address of the DMA region.
|
||||
* @size: The length of the DMA region.
|
||||
@@ -791,7 +792,7 @@ ccio_map_page(struct device *dev, struct page *page, unsigned long offset,
|
||||
* @attrs: attributes
|
||||
*/
|
||||
static void
|
||||
ccio_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
|
||||
ccio_unmap_phys(struct device *dev, dma_addr_t iova, size_t size,
|
||||
enum dma_data_direction direction, unsigned long attrs)
|
||||
{
|
||||
struct ioc *ioc;
|
||||
@@ -853,7 +854,8 @@ ccio_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag,
|
||||
|
||||
if (ret) {
|
||||
memset(ret, 0, size);
|
||||
*dma_handle = ccio_map_single(dev, ret, size, DMA_BIDIRECTIONAL);
|
||||
*dma_handle = ccio_map_single(dev, virt_to_phys(ret), size,
|
||||
DMA_BIDIRECTIONAL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -873,7 +875,7 @@ static void
|
||||
ccio_free(struct device *dev, size_t size, void *cpu_addr,
|
||||
dma_addr_t dma_handle, unsigned long attrs)
|
||||
{
|
||||
ccio_unmap_page(dev, dma_handle, size, 0, 0);
|
||||
ccio_unmap_phys(dev, dma_handle, size, 0, 0);
|
||||
free_pages((unsigned long)cpu_addr, get_order(size));
|
||||
}
|
||||
|
||||
@@ -920,7 +922,7 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
|
||||
/* Fast path single entry scatterlists. */
|
||||
if (nents == 1) {
|
||||
sg_dma_address(sglist) = ccio_map_single(dev,
|
||||
sg_virt(sglist), sglist->length,
|
||||
sg_phys(sglist), sglist->length,
|
||||
direction);
|
||||
sg_dma_len(sglist) = sglist->length;
|
||||
return 1;
|
||||
@@ -1004,7 +1006,7 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
|
||||
#ifdef CCIO_COLLECT_STATS
|
||||
ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
|
||||
#endif
|
||||
ccio_unmap_page(dev, sg_dma_address(sglist),
|
||||
ccio_unmap_phys(dev, sg_dma_address(sglist),
|
||||
sg_dma_len(sglist), direction, 0);
|
||||
++sglist;
|
||||
nents--;
|
||||
@@ -1017,8 +1019,8 @@ static const struct dma_map_ops ccio_ops = {
|
||||
.dma_supported = ccio_dma_supported,
|
||||
.alloc = ccio_alloc,
|
||||
.free = ccio_free,
|
||||
.map_page = ccio_map_page,
|
||||
.unmap_page = ccio_unmap_page,
|
||||
.map_phys = ccio_map_phys,
|
||||
.unmap_phys = ccio_unmap_phys,
|
||||
.map_sg = ccio_map_sg,
|
||||
.unmap_sg = ccio_unmap_sg,
|
||||
.get_sgtable = dma_common_get_sgtable,
|
||||
@@ -1072,7 +1074,7 @@ static int ccio_proc_info(struct seq_file *m, void *p)
|
||||
ioc->msingle_calls, ioc->msingle_pages,
|
||||
(int)((ioc->msingle_pages * 1000)/ioc->msingle_calls));
|
||||
|
||||
/* KLUGE - unmap_sg calls unmap_page for each mapped page */
|
||||
/* KLUGE - unmap_sg calls unmap_phys for each mapped page */
|
||||
min = ioc->usingle_calls - ioc->usg_calls;
|
||||
max = ioc->usingle_pages - ioc->usg_pages;
|
||||
seq_printf(m, "pci_unmap_single: %8ld calls %8ld pages (avg %d/1000)\n",
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
static inline unsigned int
|
||||
iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents,
|
||||
unsigned long hint,
|
||||
void (*iommu_io_pdir_entry)(__le64 *, space_t, unsigned long,
|
||||
void (*iommu_io_pdir_entry)(__le64 *, space_t, phys_addr_t,
|
||||
unsigned long))
|
||||
{
|
||||
struct scatterlist *dma_sg = startsg; /* pointer to current DMA */
|
||||
@@ -28,7 +28,7 @@ iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents,
|
||||
dma_sg--;
|
||||
|
||||
while (nents-- > 0) {
|
||||
unsigned long vaddr;
|
||||
phys_addr_t paddr;
|
||||
long size;
|
||||
|
||||
DBG_RUN_SG(" %d : %08lx %p/%05x\n", nents,
|
||||
@@ -67,7 +67,7 @@ iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents,
|
||||
|
||||
BUG_ON(pdirp == NULL);
|
||||
|
||||
vaddr = (unsigned long)sg_virt(startsg);
|
||||
paddr = sg_phys(startsg);
|
||||
sg_dma_len(dma_sg) += startsg->length;
|
||||
size = startsg->length + dma_offset;
|
||||
dma_offset = 0;
|
||||
@@ -76,8 +76,8 @@ iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents,
|
||||
#endif
|
||||
do {
|
||||
iommu_io_pdir_entry(pdirp, KERNEL_SPACE,
|
||||
vaddr, hint);
|
||||
vaddr += IOVP_SIZE;
|
||||
paddr, hint);
|
||||
paddr += IOVP_SIZE;
|
||||
size -= IOVP_SIZE;
|
||||
pdirp++;
|
||||
} while(unlikely(size > 0));
|
||||
|
||||
@@ -532,7 +532,7 @@ typedef unsigned long space_t;
|
||||
* sba_io_pdir_entry - fill in one IO PDIR entry
|
||||
* @pdir_ptr: pointer to IO PDIR entry
|
||||
* @sid: process Space ID - currently only support KERNEL_SPACE
|
||||
* @vba: Virtual CPU address of buffer to map
|
||||
* @pba: Physical address of buffer to map
|
||||
* @hint: DMA hint set to use for this mapping
|
||||
*
|
||||
* SBA Mapping Routine
|
||||
@@ -569,20 +569,17 @@ typedef unsigned long space_t;
|
||||
*/
|
||||
|
||||
static void
|
||||
sba_io_pdir_entry(__le64 *pdir_ptr, space_t sid, unsigned long vba,
|
||||
sba_io_pdir_entry(__le64 *pdir_ptr, space_t sid, phys_addr_t pba,
|
||||
unsigned long hint)
|
||||
{
|
||||
u64 pa; /* physical address */
|
||||
register unsigned ci; /* coherent index */
|
||||
|
||||
pa = lpa(vba);
|
||||
pa &= IOVP_MASK;
|
||||
asm("lci 0(%1), %0" : "=r" (ci) : "r" (phys_to_virt(pba)));
|
||||
pba &= IOVP_MASK;
|
||||
pba |= (ci >> PAGE_SHIFT) & 0xff; /* move CI (8 bits) into lowest byte */
|
||||
|
||||
asm("lci 0(%1), %0" : "=r" (ci) : "r" (vba));
|
||||
pa |= (ci >> PAGE_SHIFT) & 0xff; /* move CI (8 bits) into lowest byte */
|
||||
|
||||
pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */
|
||||
*pdir_ptr = cpu_to_le64(pa); /* swap and store into I/O Pdir */
|
||||
pba |= SBA_PDIR_VALID_BIT; /* set "valid" bit */
|
||||
*pdir_ptr = cpu_to_le64(pba); /* swap and store into I/O Pdir */
|
||||
|
||||
/*
|
||||
* If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit set
|
||||
@@ -707,7 +704,7 @@ static int sba_dma_supported( struct device *dev, u64 mask)
|
||||
* See Documentation/core-api/dma-api-howto.rst
|
||||
*/
|
||||
static dma_addr_t
|
||||
sba_map_single(struct device *dev, void *addr, size_t size,
|
||||
sba_map_single(struct device *dev, phys_addr_t addr, size_t size,
|
||||
enum dma_data_direction direction)
|
||||
{
|
||||
struct ioc *ioc;
|
||||
@@ -722,7 +719,7 @@ sba_map_single(struct device *dev, void *addr, size_t size,
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
/* save offset bits */
|
||||
offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK;
|
||||
offset = offset_in_page(addr);
|
||||
|
||||
/* round up to nearest IOVP_SIZE */
|
||||
size = (size + offset + ~IOVP_MASK) & IOVP_MASK;
|
||||
@@ -739,13 +736,13 @@ sba_map_single(struct device *dev, void *addr, size_t size,
|
||||
pide = sba_alloc_range(ioc, dev, size);
|
||||
iovp = (dma_addr_t) pide << IOVP_SHIFT;
|
||||
|
||||
DBG_RUN("%s() 0x%p -> 0x%lx\n",
|
||||
__func__, addr, (long) iovp | offset);
|
||||
DBG_RUN("%s() 0x%pa -> 0x%lx\n",
|
||||
__func__, &addr, (long) iovp | offset);
|
||||
|
||||
pdir_start = &(ioc->pdir_base[pide]);
|
||||
|
||||
while (size > 0) {
|
||||
sba_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long) addr, 0);
|
||||
sba_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, 0);
|
||||
|
||||
DBG_RUN(" pdir 0x%p %02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
pdir_start,
|
||||
@@ -778,17 +775,18 @@ sba_map_single(struct device *dev, void *addr, size_t size,
|
||||
|
||||
|
||||
static dma_addr_t
|
||||
sba_map_page(struct device *dev, struct page *page, unsigned long offset,
|
||||
size_t size, enum dma_data_direction direction,
|
||||
unsigned long attrs)
|
||||
sba_map_phys(struct device *dev, phys_addr_t phys, size_t size,
|
||||
enum dma_data_direction direction, unsigned long attrs)
|
||||
{
|
||||
return sba_map_single(dev, page_address(page) + offset, size,
|
||||
direction);
|
||||
if (unlikely(attrs & DMA_ATTR_MMIO))
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
return sba_map_single(dev, phys, size, direction);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* sba_unmap_page - unmap one IOVA and free resources
|
||||
* sba_unmap_phys - unmap one IOVA and free resources
|
||||
* @dev: instance of PCI owned by the driver that's asking.
|
||||
* @iova: IOVA of driver buffer previously mapped.
|
||||
* @size: number of bytes mapped in driver buffer.
|
||||
@@ -798,7 +796,7 @@ sba_map_page(struct device *dev, struct page *page, unsigned long offset,
|
||||
* See Documentation/core-api/dma-api-howto.rst
|
||||
*/
|
||||
static void
|
||||
sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
|
||||
sba_unmap_phys(struct device *dev, dma_addr_t iova, size_t size,
|
||||
enum dma_data_direction direction, unsigned long attrs)
|
||||
{
|
||||
struct ioc *ioc;
|
||||
@@ -893,7 +891,7 @@ static void *sba_alloc(struct device *hwdev, size_t size, dma_addr_t *dma_handle
|
||||
|
||||
if (ret) {
|
||||
memset(ret, 0, size);
|
||||
*dma_handle = sba_map_single(hwdev, ret, size, 0);
|
||||
*dma_handle = sba_map_single(hwdev, virt_to_phys(ret), size, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -914,7 +912,7 @@ static void
|
||||
sba_free(struct device *hwdev, size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle, unsigned long attrs)
|
||||
{
|
||||
sba_unmap_page(hwdev, dma_handle, size, 0, 0);
|
||||
sba_unmap_phys(hwdev, dma_handle, size, 0, 0);
|
||||
free_pages((unsigned long) vaddr, get_order(size));
|
||||
}
|
||||
|
||||
@@ -962,7 +960,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
|
||||
|
||||
/* Fast path single entry scatterlists. */
|
||||
if (nents == 1) {
|
||||
sg_dma_address(sglist) = sba_map_single(dev, sg_virt(sglist),
|
||||
sg_dma_address(sglist) = sba_map_single(dev, sg_phys(sglist),
|
||||
sglist->length, direction);
|
||||
sg_dma_len(sglist) = sglist->length;
|
||||
return 1;
|
||||
@@ -1061,7 +1059,7 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
|
||||
|
||||
while (nents && sg_dma_len(sglist)) {
|
||||
|
||||
sba_unmap_page(dev, sg_dma_address(sglist), sg_dma_len(sglist),
|
||||
sba_unmap_phys(dev, sg_dma_address(sglist), sg_dma_len(sglist),
|
||||
direction, 0);
|
||||
#ifdef SBA_COLLECT_STATS
|
||||
ioc->usg_pages += ((sg_dma_address(sglist) & ~IOVP_MASK) + sg_dma_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
|
||||
@@ -1085,8 +1083,8 @@ static const struct dma_map_ops sba_ops = {
|
||||
.dma_supported = sba_dma_supported,
|
||||
.alloc = sba_alloc,
|
||||
.free = sba_free,
|
||||
.map_page = sba_map_page,
|
||||
.unmap_page = sba_unmap_page,
|
||||
.map_phys = sba_map_phys,
|
||||
.unmap_phys = sba_unmap_phys,
|
||||
.map_sg = sba_map_sg,
|
||||
.unmap_sg = sba_unmap_sg,
|
||||
.get_sgtable = dma_common_get_sgtable,
|
||||
|
||||
@@ -163,18 +163,22 @@ static void xen_grant_dma_free_pages(struct device *dev, size_t size,
|
||||
xen_grant_dma_free(dev, size, page_to_virt(vaddr), dma_handle, 0);
|
||||
}
|
||||
|
||||
static dma_addr_t xen_grant_dma_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size,
|
||||
static dma_addr_t xen_grant_dma_map_phys(struct device *dev, phys_addr_t phys,
|
||||
size_t size,
|
||||
enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct xen_grant_dma_data *data;
|
||||
unsigned long offset = offset_in_page(phys);
|
||||
unsigned long dma_offset = xen_offset_in_page(offset),
|
||||
pfn_offset = XEN_PFN_DOWN(offset);
|
||||
unsigned int i, n_pages = XEN_PFN_UP(dma_offset + size);
|
||||
grant_ref_t grant;
|
||||
dma_addr_t dma_handle;
|
||||
|
||||
if (unlikely(attrs & DMA_ATTR_MMIO))
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
if (WARN_ON(dir == DMA_NONE))
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
@@ -190,7 +194,7 @@ static dma_addr_t xen_grant_dma_map_page(struct device *dev, struct page *page,
|
||||
|
||||
for (i = 0; i < n_pages; i++) {
|
||||
gnttab_grant_foreign_access_ref(grant + i, data->backend_domid,
|
||||
pfn_to_gfn(page_to_xen_pfn(page) + i + pfn_offset),
|
||||
pfn_to_gfn(page_to_xen_pfn(phys_to_page(phys)) + i + pfn_offset),
|
||||
dir == DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
@@ -199,7 +203,7 @@ static dma_addr_t xen_grant_dma_map_page(struct device *dev, struct page *page,
|
||||
return dma_handle;
|
||||
}
|
||||
|
||||
static void xen_grant_dma_unmap_page(struct device *dev, dma_addr_t dma_handle,
|
||||
static void xen_grant_dma_unmap_phys(struct device *dev, dma_addr_t dma_handle,
|
||||
size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
@@ -242,7 +246,7 @@ static void xen_grant_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
|
||||
return;
|
||||
|
||||
for_each_sg(sg, s, nents, i)
|
||||
xen_grant_dma_unmap_page(dev, s->dma_address, sg_dma_len(s), dir,
|
||||
xen_grant_dma_unmap_phys(dev, s->dma_address, sg_dma_len(s), dir,
|
||||
attrs);
|
||||
}
|
||||
|
||||
@@ -257,7 +261,7 @@ static int xen_grant_dma_map_sg(struct device *dev, struct scatterlist *sg,
|
||||
return -EINVAL;
|
||||
|
||||
for_each_sg(sg, s, nents, i) {
|
||||
s->dma_address = xen_grant_dma_map_page(dev, sg_page(s), s->offset,
|
||||
s->dma_address = xen_grant_dma_map_phys(dev, sg_phys(s),
|
||||
s->length, dir, attrs);
|
||||
if (s->dma_address == DMA_MAPPING_ERROR)
|
||||
goto out;
|
||||
@@ -286,8 +290,8 @@ static const struct dma_map_ops xen_grant_dma_ops = {
|
||||
.free_pages = xen_grant_dma_free_pages,
|
||||
.mmap = dma_common_mmap,
|
||||
.get_sgtable = dma_common_get_sgtable,
|
||||
.map_page = xen_grant_dma_map_page,
|
||||
.unmap_page = xen_grant_dma_unmap_page,
|
||||
.map_phys = xen_grant_dma_map_phys,
|
||||
.unmap_phys = xen_grant_dma_unmap_phys,
|
||||
.map_sg = xen_grant_dma_map_sg,
|
||||
.unmap_sg = xen_grant_dma_unmap_sg,
|
||||
.dma_supported = xen_grant_dma_supported,
|
||||
|
||||
@@ -200,17 +200,32 @@ xen_swiotlb_free_coherent(struct device *dev, size_t size, void *vaddr,
|
||||
* physical address to use is returned.
|
||||
*
|
||||
* Once the device is given the dma address, the device owns this memory until
|
||||
* either xen_swiotlb_unmap_page or xen_swiotlb_dma_sync_single is performed.
|
||||
* either xen_swiotlb_unmap_phys or xen_swiotlb_dma_sync_single is performed.
|
||||
*/
|
||||
static dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size,
|
||||
enum dma_data_direction dir,
|
||||
static dma_addr_t xen_swiotlb_map_phys(struct device *dev, phys_addr_t phys,
|
||||
size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
phys_addr_t map, phys = page_to_phys(page) + offset;
|
||||
dma_addr_t dev_addr = xen_phys_to_dma(dev, phys);
|
||||
dma_addr_t dev_addr;
|
||||
phys_addr_t map;
|
||||
|
||||
BUG_ON(dir == DMA_NONE);
|
||||
|
||||
if (attrs & DMA_ATTR_MMIO) {
|
||||
if (unlikely(!dma_capable(dev, phys, size, false))) {
|
||||
dev_err_once(
|
||||
dev,
|
||||
"DMA addr %pa+%zu overflow (mask %llx, bus limit %llx).\n",
|
||||
&phys, size, *dev->dma_mask,
|
||||
dev->bus_dma_limit);
|
||||
WARN_ON_ONCE(1);
|
||||
return DMA_MAPPING_ERROR;
|
||||
}
|
||||
return phys;
|
||||
}
|
||||
|
||||
dev_addr = xen_phys_to_dma(dev, phys);
|
||||
|
||||
/*
|
||||
* If the address happens to be in the device's DMA window,
|
||||
* we can safely return the device addr and not worry about bounce
|
||||
@@ -257,13 +272,13 @@ done:
|
||||
|
||||
/*
|
||||
* Unmap a single streaming mode DMA translation. The dma_addr and size must
|
||||
* match what was provided for in a previous xen_swiotlb_map_page call. All
|
||||
* match what was provided for in a previous xen_swiotlb_map_phys call. All
|
||||
* other usages are undefined.
|
||||
*
|
||||
* After this call, reads by the cpu to the buffer are guaranteed to see
|
||||
* whatever the device wrote there.
|
||||
*/
|
||||
static void xen_swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
|
||||
static void xen_swiotlb_unmap_phys(struct device *hwdev, dma_addr_t dev_addr,
|
||||
size_t size, enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
phys_addr_t paddr = xen_dma_to_phys(hwdev, dev_addr);
|
||||
@@ -325,7 +340,7 @@ xen_swiotlb_sync_single_for_device(struct device *dev, dma_addr_t dma_addr,
|
||||
|
||||
/*
|
||||
* Unmap a set of streaming mode DMA translations. Again, cpu read rules
|
||||
* concerning calls here are the same as for swiotlb_unmap_page() above.
|
||||
* concerning calls here are the same as for swiotlb_unmap_phys() above.
|
||||
*/
|
||||
static void
|
||||
xen_swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
|
||||
@@ -337,7 +352,7 @@ xen_swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
|
||||
BUG_ON(dir == DMA_NONE);
|
||||
|
||||
for_each_sg(sgl, sg, nelems, i)
|
||||
xen_swiotlb_unmap_page(hwdev, sg->dma_address, sg_dma_len(sg),
|
||||
xen_swiotlb_unmap_phys(hwdev, sg->dma_address, sg_dma_len(sg),
|
||||
dir, attrs);
|
||||
|
||||
}
|
||||
@@ -352,8 +367,8 @@ xen_swiotlb_map_sg(struct device *dev, struct scatterlist *sgl, int nelems,
|
||||
BUG_ON(dir == DMA_NONE);
|
||||
|
||||
for_each_sg(sgl, sg, nelems, i) {
|
||||
sg->dma_address = xen_swiotlb_map_page(dev, sg_page(sg),
|
||||
sg->offset, sg->length, dir, attrs);
|
||||
sg->dma_address = xen_swiotlb_map_phys(dev, sg_phys(sg),
|
||||
sg->length, dir, attrs);
|
||||
if (sg->dma_address == DMA_MAPPING_ERROR)
|
||||
goto out_unmap;
|
||||
sg_dma_len(sg) = sg->length;
|
||||
@@ -392,25 +407,6 @@ xen_swiotlb_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
|
||||
}
|
||||
}
|
||||
|
||||
static dma_addr_t xen_swiotlb_direct_map_resource(struct device *dev,
|
||||
phys_addr_t paddr,
|
||||
size_t size,
|
||||
enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
dma_addr_t dma_addr = paddr;
|
||||
|
||||
if (unlikely(!dma_capable(dev, dma_addr, size, false))) {
|
||||
dev_err_once(dev,
|
||||
"DMA addr %pad+%zu overflow (mask %llx, bus limit %llx).\n",
|
||||
&dma_addr, size, *dev->dma_mask, dev->bus_dma_limit);
|
||||
WARN_ON_ONCE(1);
|
||||
return DMA_MAPPING_ERROR;
|
||||
}
|
||||
|
||||
return dma_addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return whether the given device DMA address mask can be supported
|
||||
* properly. For example, if your device can only drive the low 24-bits
|
||||
@@ -437,13 +433,12 @@ const struct dma_map_ops xen_swiotlb_dma_ops = {
|
||||
.sync_sg_for_device = xen_swiotlb_sync_sg_for_device,
|
||||
.map_sg = xen_swiotlb_map_sg,
|
||||
.unmap_sg = xen_swiotlb_unmap_sg,
|
||||
.map_page = xen_swiotlb_map_page,
|
||||
.unmap_page = xen_swiotlb_unmap_page,
|
||||
.map_phys = xen_swiotlb_map_phys,
|
||||
.unmap_phys = xen_swiotlb_unmap_phys,
|
||||
.dma_supported = xen_swiotlb_dma_supported,
|
||||
.mmap = dma_common_mmap,
|
||||
.get_sgtable = dma_common_get_sgtable,
|
||||
.alloc_pages_op = dma_common_alloc_pages,
|
||||
.free_pages = dma_common_free_pages,
|
||||
.max_mapping_size = swiotlb_max_mapping_size,
|
||||
.map_resource = xen_swiotlb_direct_map_resource,
|
||||
};
|
||||
|
||||
@@ -31,10 +31,10 @@ struct dma_map_ops {
|
||||
void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
||||
unsigned long attrs);
|
||||
|
||||
dma_addr_t (*map_page)(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size,
|
||||
enum dma_data_direction dir, unsigned long attrs);
|
||||
void (*unmap_page)(struct device *dev, dma_addr_t dma_handle,
|
||||
dma_addr_t (*map_phys)(struct device *dev, phys_addr_t phys,
|
||||
size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs);
|
||||
void (*unmap_phys)(struct device *dev, dma_addr_t dma_handle,
|
||||
size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs);
|
||||
/*
|
||||
@@ -46,12 +46,6 @@ struct dma_map_ops {
|
||||
enum dma_data_direction dir, unsigned long attrs);
|
||||
void (*unmap_sg)(struct device *dev, struct scatterlist *sg, int nents,
|
||||
enum dma_data_direction dir, unsigned long attrs);
|
||||
dma_addr_t (*map_resource)(struct device *dev, phys_addr_t phys_addr,
|
||||
size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs);
|
||||
void (*unmap_resource)(struct device *dev, dma_addr_t dma_handle,
|
||||
size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs);
|
||||
void (*sync_single_for_cpu)(struct device *dev, dma_addr_t dma_handle,
|
||||
size_t size, enum dma_data_direction dir);
|
||||
void (*sync_single_for_device)(struct device *dev,
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (C) 2022 HiSilicon Limited.
|
||||
* Copyright (C) 2022-2025 HiSilicon Limited.
|
||||
*/
|
||||
|
||||
#ifndef _KERNEL_DMA_BENCHMARK_H
|
||||
#define _KERNEL_DMA_BENCHMARK_H
|
||||
#ifndef _UAPI_DMA_BENCHMARK_H
|
||||
#define _UAPI_DMA_BENCHMARK_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define DMA_MAP_BENCHMARK _IOWR('d', 1, struct map_benchmark)
|
||||
#define DMA_MAP_MAX_THREADS 1024
|
||||
@@ -29,4 +31,5 @@ struct map_benchmark {
|
||||
__u32 granule; /* how many PAGE_SIZE will do map/unmap once a time */
|
||||
__u8 expansion[76]; /* For future use */
|
||||
};
|
||||
#endif /* _KERNEL_DMA_BENCHMARK_H */
|
||||
|
||||
#endif /* _UAPI_DMA_BENCHMARK_H */
|
||||
@@ -11,17 +11,16 @@ static int dma_dummy_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
static dma_addr_t dma_dummy_map_page(struct device *dev, struct page *page,
|
||||
unsigned long offset, size_t size, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
static dma_addr_t dma_dummy_map_phys(struct device *dev, phys_addr_t phys,
|
||||
size_t size, enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
return DMA_MAPPING_ERROR;
|
||||
}
|
||||
static void dma_dummy_unmap_page(struct device *dev, dma_addr_t dma_handle,
|
||||
static void dma_dummy_unmap_phys(struct device *dev, dma_addr_t dma_handle,
|
||||
size_t size, enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
/*
|
||||
* Dummy ops doesn't support map_page, so unmap_page should never be
|
||||
* Dummy ops doesn't support map_phys, so unmap_page should never be
|
||||
* called.
|
||||
*/
|
||||
WARN_ON_ONCE(true);
|
||||
@@ -51,8 +50,8 @@ static int dma_dummy_supported(struct device *hwdev, u64 mask)
|
||||
|
||||
const struct dma_map_ops dma_dummy_ops = {
|
||||
.mmap = dma_dummy_mmap,
|
||||
.map_page = dma_dummy_map_page,
|
||||
.unmap_page = dma_dummy_unmap_page,
|
||||
.map_phys = dma_dummy_map_phys,
|
||||
.unmap_phys = dma_dummy_unmap_phys,
|
||||
.map_sg = dma_dummy_map_sg,
|
||||
.unmap_sg = dma_dummy_unmap_sg,
|
||||
.dma_supported = dma_dummy_supported,
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/map_benchmark.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timekeeping.h>
|
||||
#include <uapi/linux/map_benchmark.h>
|
||||
|
||||
struct map_benchmark_data {
|
||||
struct map_benchmark bparam;
|
||||
|
||||
@@ -157,7 +157,7 @@ dma_addr_t dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
|
||||
{
|
||||
const struct dma_map_ops *ops = get_dma_ops(dev);
|
||||
bool is_mmio = attrs & DMA_ATTR_MMIO;
|
||||
dma_addr_t addr;
|
||||
dma_addr_t addr = DMA_MAPPING_ERROR;
|
||||
|
||||
BUG_ON(!valid_dma_direction(dir));
|
||||
|
||||
@@ -169,21 +169,8 @@ dma_addr_t dma_map_phys(struct device *dev, phys_addr_t phys, size_t size,
|
||||
addr = dma_direct_map_phys(dev, phys, size, dir, attrs);
|
||||
else if (use_dma_iommu(dev))
|
||||
addr = iommu_dma_map_phys(dev, phys, size, dir, attrs);
|
||||
else if (is_mmio) {
|
||||
if (!ops->map_resource)
|
||||
return DMA_MAPPING_ERROR;
|
||||
|
||||
addr = ops->map_resource(dev, phys, size, dir, attrs);
|
||||
} else {
|
||||
struct page *page = phys_to_page(phys);
|
||||
size_t offset = offset_in_page(phys);
|
||||
|
||||
/*
|
||||
* The dma_ops API contract for ops->map_page() requires
|
||||
* kmappable memory, while ops->map_resource() does not.
|
||||
*/
|
||||
addr = ops->map_page(dev, page, offset, size, dir, attrs);
|
||||
}
|
||||
else if (ops->map_phys)
|
||||
addr = ops->map_phys(dev, phys, size, dir, attrs);
|
||||
|
||||
if (!is_mmio)
|
||||
kmsan_handle_dma(phys, size, dir);
|
||||
@@ -223,11 +210,8 @@ void dma_unmap_phys(struct device *dev, dma_addr_t addr, size_t size,
|
||||
dma_direct_unmap_phys(dev, addr, size, dir, attrs);
|
||||
else if (use_dma_iommu(dev))
|
||||
iommu_dma_unmap_phys(dev, addr, size, dir, attrs);
|
||||
else if (is_mmio) {
|
||||
if (ops->unmap_resource)
|
||||
ops->unmap_resource(dev, addr, size, dir, attrs);
|
||||
} else
|
||||
ops->unmap_page(dev, addr, size, dir, attrs);
|
||||
else if (ops->unmap_phys)
|
||||
ops->unmap_phys(dev, addr, size, dir, attrs);
|
||||
trace_dma_unmap_phys(dev, addr, size, dir, attrs);
|
||||
debug_dma_unmap_phys(dev, addr, size, dir);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ struct page *dma_common_alloc_pages(struct device *dev, size_t size,
|
||||
{
|
||||
const struct dma_map_ops *ops = get_dma_ops(dev);
|
||||
struct page *page;
|
||||
phys_addr_t phys;
|
||||
|
||||
page = dma_alloc_contiguous(dev, size, gfp);
|
||||
if (!page)
|
||||
@@ -71,11 +72,12 @@ struct page *dma_common_alloc_pages(struct device *dev, size_t size,
|
||||
if (!page)
|
||||
return NULL;
|
||||
|
||||
phys = page_to_phys(page);
|
||||
if (use_dma_iommu(dev))
|
||||
*dma_handle = iommu_dma_map_phys(dev, page_to_phys(page), size,
|
||||
dir, DMA_ATTR_SKIP_CPU_SYNC);
|
||||
*dma_handle = iommu_dma_map_phys(dev, phys, size, dir,
|
||||
DMA_ATTR_SKIP_CPU_SYNC);
|
||||
else
|
||||
*dma_handle = ops->map_page(dev, page, 0, size, dir,
|
||||
*dma_handle = ops->map_phys(dev, phys, size, dir,
|
||||
DMA_ATTR_SKIP_CPU_SYNC);
|
||||
if (*dma_handle == DMA_MAPPING_ERROR) {
|
||||
dma_free_contiguous(dev, page, size);
|
||||
@@ -94,8 +96,8 @@ void dma_common_free_pages(struct device *dev, size_t size, struct page *page,
|
||||
if (use_dma_iommu(dev))
|
||||
iommu_dma_unmap_phys(dev, dma_handle, size, dir,
|
||||
DMA_ATTR_SKIP_CPU_SYNC);
|
||||
else if (ops->unmap_page)
|
||||
ops->unmap_page(dev, dma_handle, size, dir,
|
||||
else if (ops->unmap_phys)
|
||||
ops->unmap_phys(dev, dma_handle, size, dir,
|
||||
DMA_ATTR_SKIP_CPU_SYNC);
|
||||
dma_free_contiguous(dev, page, size);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ help:
|
||||
@echo ' counter - counter tools'
|
||||
@echo ' cpupower - a tool for all things x86 CPU power'
|
||||
@echo ' debugging - tools for debugging'
|
||||
@echo ' dma - tools for DMA mapping'
|
||||
@echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
|
||||
@echo ' firmware - Firmware tools'
|
||||
@echo ' freefall - laptop accelerometer program for disk protection'
|
||||
@@ -69,7 +70,7 @@ acpi: FORCE
|
||||
cpupower: FORCE
|
||||
$(call descend,power/$@)
|
||||
|
||||
counter firewire hv guest bootconfig spi usb virtio mm bpf iio gpio objtool leds wmi firmware debugging tracing: FORCE
|
||||
counter dma firewire hv guest bootconfig spi usb virtio mm bpf iio gpio objtool leds wmi firmware debugging tracing: FORCE
|
||||
$(call descend,$@)
|
||||
|
||||
bpf/%: FORCE
|
||||
@@ -122,7 +123,7 @@ kvm_stat: FORCE
|
||||
ynl: FORCE
|
||||
$(call descend,net/ynl)
|
||||
|
||||
all: acpi counter cpupower gpio hv firewire \
|
||||
all: acpi counter cpupower dma gpio hv firewire \
|
||||
perf selftests bootconfig spi turbostat usb \
|
||||
virtio mm bpf x86_energy_perf_policy \
|
||||
tmon freefall iio objtool kvm_stat wmi \
|
||||
@@ -134,7 +135,7 @@ acpi_install:
|
||||
cpupower_install:
|
||||
$(call descend,power/$(@:_install=),install)
|
||||
|
||||
counter_install firewire_install gpio_install hv_install iio_install perf_install bootconfig_install spi_install usb_install virtio_install mm_install bpf_install objtool_install wmi_install debugging_install tracing_install:
|
||||
counter_install dma_install firewire_install gpio_install hv_install iio_install perf_install bootconfig_install spi_install usb_install virtio_install mm_install bpf_install objtool_install wmi_install debugging_install tracing_install:
|
||||
$(call descend,$(@:_install=),install)
|
||||
|
||||
selftests_install:
|
||||
@@ -164,7 +165,7 @@ kvm_stat_install:
|
||||
ynl_install:
|
||||
$(call descend,net/$(@:_install=),install)
|
||||
|
||||
install: acpi_install counter_install cpupower_install gpio_install \
|
||||
install: acpi_install counter_install cpupower_install dma_install gpio_install \
|
||||
hv_install firewire_install iio_install \
|
||||
perf_install selftests_install turbostat_install usb_install \
|
||||
virtio_install mm_install bpf_install x86_energy_perf_policy_install \
|
||||
@@ -178,7 +179,7 @@ acpi_clean:
|
||||
cpupower_clean:
|
||||
$(call descend,power/cpupower,clean)
|
||||
|
||||
counter_clean hv_clean firewire_clean bootconfig_clean spi_clean usb_clean virtio_clean mm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean firmware_clean debugging_clean tracing_clean:
|
||||
counter_clean dma_clean hv_clean firewire_clean bootconfig_clean spi_clean usb_clean virtio_clean mm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean firmware_clean debugging_clean tracing_clean:
|
||||
$(call descend,$(@:_clean=),clean)
|
||||
|
||||
libapi_clean:
|
||||
@@ -224,7 +225,7 @@ build_clean:
|
||||
ynl_clean:
|
||||
$(call descend,net/$(@:_clean=),clean)
|
||||
|
||||
clean: acpi_clean counter_clean cpupower_clean hv_clean firewire_clean \
|
||||
clean: acpi_clean counter_clean cpupower_clean dma_clean hv_clean firewire_clean \
|
||||
perf_clean selftests_clean turbostat_clean bootconfig_clean spi_clean usb_clean virtio_clean \
|
||||
mm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
|
||||
freefall_clean build_clean libbpf_clean libsubcmd_clean \
|
||||
|
||||
3
tools/dma/.gitignore
vendored
Normal file
3
tools/dma/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
dma_map_benchmark
|
||||
include/linux/map_benchmark.h
|
||||
55
tools/dma/Makefile
Normal file
55
tools/dma/Makefile
Normal file
@@ -0,0 +1,55 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
include ../scripts/Makefile.include
|
||||
|
||||
bindir ?= /usr/bin
|
||||
|
||||
# This will work when dma is built in tools env. where srctree
|
||||
# isn't set and when invoked from selftests build, where srctree
|
||||
# is set to ".". building_out_of_srctree is undefined for in srctree
|
||||
# builds
|
||||
ifndef building_out_of_srctree
|
||||
srctree := $(patsubst %/,%,$(dir $(CURDIR)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
endif
|
||||
|
||||
# Do not use make's built-in rules
|
||||
# (this improves performance and avoids hard-to-debug behaviour);
|
||||
MAKEFLAGS += -r
|
||||
|
||||
override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
|
||||
|
||||
ALL_TARGETS := dma_map_benchmark
|
||||
ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
|
||||
|
||||
all: $(ALL_PROGRAMS)
|
||||
|
||||
export srctree OUTPUT CC LD CFLAGS
|
||||
include $(srctree)/tools/build/Makefile.include
|
||||
|
||||
#
|
||||
# We need the following to be outside of kernel tree
|
||||
#
|
||||
$(OUTPUT)include/linux/map_benchmark.h: ../../include/uapi/linux/map_benchmark.h
|
||||
mkdir -p $(OUTPUT)include/linux 2>&1 || true
|
||||
ln -sf $(CURDIR)/../../include/uapi/linux/map_benchmark.h $@
|
||||
|
||||
prepare: $(OUTPUT)include/linux/map_benchmark.h
|
||||
|
||||
FORCE:
|
||||
|
||||
DMA_MAP_BENCHMARK = dma_map_benchmark
|
||||
$(DMA_MAP_BENCHMARK): prepare FORCE
|
||||
$(CC) $(CFLAGS) $(DMA_MAP_BENCHMARK).c -o $(DMA_MAP_BENCHMARK)
|
||||
|
||||
clean:
|
||||
rm -f $(ALL_PROGRAMS)
|
||||
rm -rf $(OUTPUT)include
|
||||
find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete -o -name '\.*.cmd' -delete
|
||||
|
||||
install: $(ALL_PROGRAMS)
|
||||
install -d -m 755 $(DESTDIR)$(bindir); \
|
||||
for program in $(ALL_PROGRAMS); do \
|
||||
install $$program $(DESTDIR)$(bindir); \
|
||||
done
|
||||
|
||||
.PHONY: all install clean prepare FORCE
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/map_benchmark.h>
|
||||
|
||||
#define NSEC_PER_MSEC 1000000L
|
||||
@@ -1,7 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
CFLAGS += -I../../../../usr/include/
|
||||
CFLAGS += -I../../../../include/
|
||||
|
||||
TEST_GEN_PROGS := dma_map_benchmark
|
||||
|
||||
include ../lib.mk
|
||||
Reference in New Issue
Block a user