Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions arch/arc/mm/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
/*
* Plug in direct dma map ops.
*/
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
bool coherent)
void arch_setup_dma_ops(struct device *dev, bool coherent)
{
/*
* IOC hardware snoops all DMA traffic keeping the caches consistent
Expand Down
3 changes: 1 addition & 2 deletions arch/arm/mm/dma-mapping-nommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
}
}

void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
bool coherent)
void arch_setup_dma_ops(struct device *dev, bool coherent)
{
if (IS_ENABLED(CONFIG_CPU_V7M)) {
/*
Expand Down
16 changes: 9 additions & 7 deletions arch/arm/mm/dma-mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -1712,11 +1712,15 @@ void arm_iommu_detach_device(struct device *dev)
}
EXPORT_SYMBOL_GPL(arm_iommu_detach_device);

static void arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,
bool coherent)
static void arm_setup_iommu_dma_ops(struct device *dev)
{
struct dma_iommu_mapping *mapping;
u64 dma_base = 0, size = 1ULL << 32;

if (dev->dma_range_map) {
dma_base = dma_range_map_min(dev->dma_range_map);
size = dma_range_map_max(dev->dma_range_map) - dma_base;
}
mapping = arm_iommu_create_mapping(dev->bus, dma_base, size);
if (IS_ERR(mapping)) {
pr_warn("Failed to create %llu-byte IOMMU mapping for device %s\n",
Expand Down Expand Up @@ -1747,17 +1751,15 @@ static void arm_teardown_iommu_dma_ops(struct device *dev)

#else

static void arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,
bool coherent)
static void arm_setup_iommu_dma_ops(struct device *dev)
{
}

static void arm_teardown_iommu_dma_ops(struct device *dev) { }

#endif /* CONFIG_ARM_DMA_USE_IOMMU */

void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
bool coherent)
void arch_setup_dma_ops(struct device *dev, bool coherent)
{
/*
* Due to legacy code that sets the ->dma_coherent flag from a bus
Expand All @@ -1777,7 +1779,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
return;

if (device_iommu_mapped(dev))
arm_setup_iommu_dma_ops(dev, dma_base, size, coherent);
arm_setup_iommu_dma_ops(dev);

xen_setup_dma_ops(dev);
dev->archdata.dma_ops_setup = true;
Expand Down
5 changes: 1 addition & 4 deletions arch/arm64/mm/dma-mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ void arch_teardown_dma_ops(struct device *dev)
}
#endif

void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
bool coherent)
void arch_setup_dma_ops(struct device *dev, bool coherent)
{
int cls = cache_line_size_of_cpu();

Expand All @@ -62,8 +61,6 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
ARCH_DMA_MINALIGN, cls);

dev->dma_coherent = coherent;
if (device_iommu_mapped(dev))
iommu_setup_dma_ops(dev, dma_base, dma_base + size - 1);

#ifdef CONFIG_PSWIOTLB
pswiotlb_setup_dma_ops(dev);
Expand Down
3 changes: 1 addition & 2 deletions arch/mips/mm/dma-noncoherent.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
#endif

#ifdef CONFIG_ARCH_HAS_SETUP_DMA_OPS
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
bool coherent)
void arch_setup_dma_ops(struct device *dev, bool coherent)
{
dev->dma_coherent = coherent;
}
Expand Down
3 changes: 1 addition & 2 deletions arch/riscv/mm/dma-noncoherent.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,7 @@ void arch_dma_prep_coherent(struct page *page, size_t size)
ALT_CMO_OP_VPA(flush, flush_addr, paddr, size, riscv_cbom_block_size);
}

void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
bool coherent)
void arch_setup_dma_ops(struct device *dev, bool coherent)
{
WARN_TAINT(!coherent && riscv_cbom_block_size > ARCH_DMA_MINALIGN,
TAINT_CPU_OUT_OF_SPEC,
Expand Down
7 changes: 1 addition & 6 deletions drivers/acpi/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -1696,12 +1696,7 @@ int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr,
if (ret)
dev_dbg(dev, "Adding to IOMMU failed: %d\n", ret);

/*
* Historically this routine doesn't fail driver probing due to errors
* in acpi_iommu_configure_id()
*/

arch_setup_dma_ops(dev, 0, U64_MAX, attr == DEV_DMA_COHERENT);
arch_setup_dma_ops(dev, attr == DEV_DMA_COHERENT);

return 0;
}
Expand Down
6 changes: 1 addition & 5 deletions drivers/hv/hv_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,11 +487,7 @@ EXPORT_SYMBOL_GPL(hv_query_ext_cap);

void hv_setup_dma_ops(struct device *dev, bool coherent)
{
/*
* Hyper-V does not offer a vIOMMU in the guest
* VM, so pass 0/NULL for the IOMMU settings
*/
arch_setup_dma_ops(dev, 0, 0, coherent);
arch_setup_dma_ops(dev, coherent);
}
EXPORT_SYMBOL_GPL(hv_setup_dma_ops);

Expand Down
8 changes: 0 additions & 8 deletions drivers/iommu/amd/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1945,13 +1945,6 @@ static struct iommu_device *amd_iommu_probe_device(struct device *dev)
return iommu_dev;
}

static void amd_iommu_probe_finalize(struct device *dev)
{
/* Domains are initialized for this device - have a look what we ended up with */
set_dma_ops(dev, NULL);
iommu_setup_dma_ops(dev, 0, U64_MAX);
}

static void amd_iommu_release_device(struct device *dev)
{
struct amd_iommu *iommu;
Expand Down Expand Up @@ -2627,7 +2620,6 @@ const struct iommu_ops amd_iommu_ops = {
.domain_alloc_user = amd_iommu_domain_alloc_user,
.probe_device = amd_iommu_probe_device,
.release_device = amd_iommu_release_device,
.probe_finalize = amd_iommu_probe_finalize,
.device_group = amd_iommu_device_group,
.get_resv_regions = amd_iommu_get_resv_regions,
.is_attach_deferred = amd_iommu_is_attach_deferred,
Expand Down
39 changes: 15 additions & 24 deletions drivers/iommu/dma-iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -715,19 +715,16 @@ static void iommu_dma_init_options(struct iommu_dma_options *options,
/**
* iommu_dma_init_domain - Initialise a DMA mapping domain
* @domain: IOMMU domain previously prepared by iommu_get_dma_cookie()
* @base: IOVA at which the mappable address space starts
* @limit: Last address of the IOVA space
* @dev: Device the domain is being initialised for
*
* @base and @limit + 1 should be exact multiples of IOMMU page granularity to
* avoid rounding surprises. If necessary, we reserve the page at address 0
* If the geometry and dma_range_map include address 0, we reserve that page
* to ensure it is an invalid IOVA. It is safe to reinitialise a domain, but
* any change which could make prior IOVAs invalid will fail.
*/
static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
dma_addr_t limit, struct device *dev)
static int iommu_dma_init_domain(struct iommu_domain *domain, struct device *dev)
{
struct iommu_dma_cookie *cookie = domain->iova_cookie;
const struct bus_dma_region *map = dev->dma_range_map;
unsigned long order, base_pfn;
struct iova_domain *iovad;
int ret;
Expand All @@ -739,18 +736,18 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,

/* Use the smallest supported page size for IOVA granularity */
order = __ffs(domain->pgsize_bitmap);
base_pfn = max_t(unsigned long, 1, base >> order);
base_pfn = 1;

/* Check the domain allows at least some access to the device... */
if (domain->geometry.force_aperture) {
if (map) {
dma_addr_t base = dma_range_map_min(map);
if (base > domain->geometry.aperture_end ||
limit < domain->geometry.aperture_start) {
dma_range_map_max(map) < domain->geometry.aperture_start) {
pr_warn("specified DMA range outside IOMMU capability\n");
return -EFAULT;
}
/* ...then finally give it a kicking to make sure it fits */
base_pfn = max_t(unsigned long, base_pfn,
domain->geometry.aperture_start >> order);
base_pfn = max(base, domain->geometry.aperture_start) >> order;
}

/* start_pfn is always nonzero for an already-initialised domain */
Expand Down Expand Up @@ -1802,33 +1799,27 @@ static const struct dma_map_ops iommu_dma_ops = {
.max_mapping_size = iommu_dma_max_mapping_size,
};

/*
* The IOMMU core code allocates the default DMA domain, which the underlying
* IOMMU driver needs to support via the dma-iommu layer.
*/
void iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 dma_limit)
void iommu_setup_dma_ops(struct device *dev)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);

if (!domain)
goto out_err;
if (dev_is_pci(dev))
dev->iommu->pci_32bit_workaround = !iommu_dma_forcedac;

/*
* The IOMMU core code allocates the default DMA domain, which the
* underlying IOMMU driver needs to support via the dma-iommu layer.
*/
if (iommu_is_dma_domain(domain)) {
if (iommu_dma_init_domain(domain, dma_base, dma_limit, dev))
if (iommu_dma_init_domain(domain, dev))
goto out_err;
dev->dma_ops = &iommu_dma_ops;
} else if (dev->dma_ops == &iommu_dma_ops) {
/* Clean up if we've switched *from* a DMA domain */
dev->dma_ops = NULL;
}

return;
out_err:
pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
dev_name(dev));
}
EXPORT_SYMBOL_GPL(iommu_setup_dma_ops);

static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
phys_addr_t msi_addr, struct iommu_domain *domain)
Expand Down
14 changes: 6 additions & 8 deletions drivers/iommu/dma-iommu.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#ifdef CONFIG_IOMMU_DMA

void iommu_setup_dma_ops(struct device *dev);

int iommu_get_dma_cookie(struct iommu_domain *domain);
void iommu_put_dma_cookie(struct iommu_domain *domain);

Expand All @@ -20,15 +22,15 @@ void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list);
struct iova_domain *iommu_get_iova_domain(struct iommu_domain *domain);
#endif
extern bool iommu_dma_forcedac;
static inline void iommu_dma_set_pci_32bit_workaround(struct device *dev)
{
dev->iommu->pci_32bit_workaround = !iommu_dma_forcedac;
}

int iova_reserve_domain_addr(struct iommu_domain *domain, dma_addr_t start, dma_addr_t end);

#else /* CONFIG_IOMMU_DMA */

static inline void iommu_setup_dma_ops(struct device *dev)
{
}

static inline int iommu_dma_init_fq(struct iommu_domain *domain)
{
return -EINVAL;
Expand All @@ -47,10 +49,6 @@ static inline void iommu_dma_get_resv_regions(struct device *dev, struct list_he
{
}

static inline void iommu_dma_set_pci_32bit_workaround(struct device *dev)
{
}

static inline int iova_reserve_domain_addr(struct iommu_domain *domain, dma_addr_t start,
dma_addr_t end)
{
Expand Down
11 changes: 0 additions & 11 deletions drivers/iommu/intel/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -4398,16 +4398,6 @@ static void intel_iommu_release_device(struct device *dev)
set_dma_ops(dev, NULL);
}

static void intel_iommu_probe_finalize(struct device *dev)
{
set_dma_ops(dev, NULL);
iommu_setup_dma_ops(dev, 0, U64_MAX);
#ifdef CONFIG_X86_64
if (is_zhaoxin_kh40000())
kh40000_set_iommu_dma_ops(dev);
#endif
}

static void intel_iommu_get_resv_regions(struct device *device,
struct list_head *head)
{
Expand Down Expand Up @@ -4887,7 +4877,6 @@ const struct iommu_ops intel_iommu_ops = {
.domain_alloc = intel_iommu_domain_alloc,
.domain_alloc_user = intel_iommu_domain_alloc_user,
.probe_device = intel_iommu_probe_device,
.probe_finalize = intel_iommu_probe_finalize,
.release_device = intel_iommu_release_device,
.get_resv_regions = intel_iommu_get_resv_regions,
.device_group = intel_iommu_device_group,
Expand Down
20 changes: 7 additions & 13 deletions drivers/iommu/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -613,10 +613,11 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
if (list_empty(&group->entry))
list_add_tail(&group->entry, group_list);
}
mutex_unlock(&group->mutex);

if (dev_is_pci(dev))
iommu_dma_set_pci_32bit_workaround(dev);
if (group->default_domain)
iommu_setup_dma_ops(dev);

mutex_unlock(&group->mutex);

return 0;

Expand Down Expand Up @@ -1911,6 +1912,8 @@ int bus_iommu_probe(const struct bus_type *bus)
mutex_unlock(&group->mutex);
return ret;
}
for_each_group_device(group, gdev)
iommu_setup_dma_ops(gdev->dev);
mutex_unlock(&group->mutex);

/*
Expand Down Expand Up @@ -3303,18 +3306,9 @@ static ssize_t iommu_group_store_type(struct iommu_group *group,
if (ret)
goto out_unlock;

/*
* Release the mutex here because ops->probe_finalize() call-back of
* some vendor IOMMU drivers calls arm_iommu_attach_device() which
* in-turn might call back into IOMMU core code, where it tries to take
* group->mutex, resulting in a deadlock.
*/
mutex_unlock(&group->mutex);

/* Make sure dma_ops is appropriatley set */
for_each_group_device(group, gdev)
iommu_group_do_probe_finalize(gdev->dev);
return count;
iommu_setup_dma_ops(gdev->dev);

out_unlock:
mutex_unlock(&group->mutex);
Expand Down
8 changes: 0 additions & 8 deletions drivers/iommu/riscv/iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/dma-map-ops.h>

#include "../iommu-pages.h"
#include "iommu-bits.h"
Expand Down Expand Up @@ -1581,12 +1580,6 @@ static struct iommu_device *riscv_iommu_probe_device(struct device *dev)
return &iommu->iommu;
}

static void riscv_iommu_probe_finalize(struct device *dev)
{
set_dma_ops(dev, NULL);
iommu_setup_dma_ops(dev, 0, U64_MAX);
}

static void riscv_iommu_release_device(struct device *dev)
{
struct riscv_iommu_info *info = dev_iommu_priv_get(dev);
Expand All @@ -1606,7 +1599,6 @@ static const struct iommu_ops riscv_iommu_ops = {
.get_resv_regions = riscv_iommu_get_resv_regions,
.device_group = riscv_iommu_device_group,
.probe_device = riscv_iommu_probe_device,
.probe_finalize = riscv_iommu_probe_finalize,
.release_device = riscv_iommu_release_device,
};

Expand Down
Loading
Loading