Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a9a16a6d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull IOMMU updates from Joerg Roedel:
 "These changes include:

   - support for the ACPI IORT table on ARM systems and patches to make
     the ARM-SMMU driver make use of it

   - conversion of the Exynos IOMMU driver to device dependency links
     and implementation of runtime pm support based on that conversion

   - update the Mediatek IOMMU driver to use the new struct
     device->iommu_fwspec member

   - implementation of dma_map/unmap_resource in the generic ARM
     dma-iommu layer

   - a number of smaller fixes and improvements all over the place"

* tag 'iommu-updates-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (44 commits)
  ACPI/IORT: Make dma masks set-up IORT specific
  iommu/amd: Missing error code in amd_iommu_init_device()
  iommu/s390: Drop duplicate header pci.h
  ACPI/IORT: Introduce iort_iommu_configure
  ACPI/IORT: Add single mapping function
  ACPI/IORT: Replace rid map type with type mask
  iommu/arm-smmu: Add IORT configuration
  iommu/arm-smmu: Split probe functions into DT/generic portions
  iommu/arm-smmu-v3: Add IORT configuration
  iommu/arm-smmu-v3: Split probe functions into DT/generic portions
  ACPI/IORT: Add support for ARM SMMU platform devices creation
  ACPI/IORT: Add node match function
  ACPI: Implement acpi_dma_configure
  iommu/arm-smmu-v3: Convert struct device of_node to fwnode usage
  iommu/arm-smmu: Convert struct device of_node to fwnode usage
  iommu: Make of_iommu_set/get_ops() DT agnostic
  ACPI/IORT: Add support for IOMMU fwnode registration
  ACPI/IORT: Introduce linker section for IORT entries probing
  ACPI: Add FWNODE_ACPI_STATIC fwnode type
  iommu/arm-smmu: Set SMTNMB_TLBEN in ACR to enable caching of bypass entries
  ...
parents d3ea5478 1465f481
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -796,6 +796,8 @@ static struct dma_map_ops iommu_dma_ops = {
	.sync_single_for_device = __iommu_sync_single_for_device,
	.sync_sg_for_cpu = __iommu_sync_sg_for_cpu,
	.sync_sg_for_device = __iommu_sync_sg_for_device,
	.map_resource = iommu_dma_map_resource,
	.unmap_resource = iommu_dma_unmap_resource,
	.dma_supported = iommu_dma_supported,
	.mapping_error = iommu_dma_mapping_error,
};
+600 −7
Original line number Diff line number Diff line
@@ -19,8 +19,17 @@
#define pr_fmt(fmt)	"ACPI: IORT: " fmt

#include <linux/acpi_iort.h>
#include <linux/iommu.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

#define IORT_TYPE_MASK(type)	(1 << (type))
#define IORT_MSI_TYPE		(1 << ACPI_IORT_NODE_ITS_GROUP)
#define IORT_IOMMU_TYPE		((1 << ACPI_IORT_NODE_SMMU) |	\
				(1 << ACPI_IORT_NODE_SMMU_V3))

struct iort_its_msi_chip {
	struct list_head	list;
@@ -28,6 +37,90 @@ struct iort_its_msi_chip {
	u32			translation_id;
};

struct iort_fwnode {
	struct list_head list;
	struct acpi_iort_node *iort_node;
	struct fwnode_handle *fwnode;
};
static LIST_HEAD(iort_fwnode_list);
static DEFINE_SPINLOCK(iort_fwnode_lock);

/**
 * iort_set_fwnode() - Create iort_fwnode and use it to register
 *		       iommu data in the iort_fwnode_list
 *
 * @node: IORT table node associated with the IOMMU
 * @fwnode: fwnode associated with the IORT node
 *
 * Returns: 0 on success
 *          <0 on failure
 */
static inline int iort_set_fwnode(struct acpi_iort_node *iort_node,
				  struct fwnode_handle *fwnode)
{
	struct iort_fwnode *np;

	np = kzalloc(sizeof(struct iort_fwnode), GFP_ATOMIC);

	if (WARN_ON(!np))
		return -ENOMEM;

	INIT_LIST_HEAD(&np->list);
	np->iort_node = iort_node;
	np->fwnode = fwnode;

	spin_lock(&iort_fwnode_lock);
	list_add_tail(&np->list, &iort_fwnode_list);
	spin_unlock(&iort_fwnode_lock);

	return 0;
}

/**
 * iort_get_fwnode() - Retrieve fwnode associated with an IORT node
 *
 * @node: IORT table node to be looked-up
 *
 * Returns: fwnode_handle pointer on success, NULL on failure
 */
static inline
struct fwnode_handle *iort_get_fwnode(struct acpi_iort_node *node)
{
	struct iort_fwnode *curr;
	struct fwnode_handle *fwnode = NULL;

	spin_lock(&iort_fwnode_lock);
	list_for_each_entry(curr, &iort_fwnode_list, list) {
		if (curr->iort_node == node) {
			fwnode = curr->fwnode;
			break;
		}
	}
	spin_unlock(&iort_fwnode_lock);

	return fwnode;
}

/**
 * iort_delete_fwnode() - Delete fwnode associated with an IORT node
 *
 * @node: IORT table node associated with fwnode to delete
 */
static inline void iort_delete_fwnode(struct acpi_iort_node *node)
{
	struct iort_fwnode *curr, *tmp;

	spin_lock(&iort_fwnode_lock);
	list_for_each_entry_safe(curr, tmp, &iort_fwnode_list, list) {
		if (curr->iort_node == node) {
			list_del(&curr->list);
			kfree(curr);
			break;
		}
	}
	spin_unlock(&iort_fwnode_lock);
}

typedef acpi_status (*iort_find_node_callback)
	(struct acpi_iort_node *node, void *context);

@@ -141,6 +234,21 @@ static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
	return NULL;
}

static acpi_status
iort_match_type_callback(struct acpi_iort_node *node, void *context)
{
	return AE_OK;
}

bool iort_node_match(u8 type)
{
	struct acpi_iort_node *node;

	node = iort_scan_node(type, iort_match_type_callback, NULL);

	return node != NULL;
}

static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
					    void *context)
{
@@ -212,9 +320,48 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
	return 0;
}

static
struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
					u32 *id_out, u8 type_mask,
					int index)
{
	struct acpi_iort_node *parent;
	struct acpi_iort_id_mapping *map;

	if (!node->mapping_offset || !node->mapping_count ||
				     index >= node->mapping_count)
		return NULL;

	map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
			   node->mapping_offset);

	/* Firmware bug! */
	if (!map->output_reference) {
		pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
		       node, node->type);
		return NULL;
	}

	parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
			       map->output_reference);

	if (!(IORT_TYPE_MASK(parent->type) & type_mask))
		return NULL;

	if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) {
		if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
		    node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
			*id_out = map[index].output_base;
			return parent;
		}
	}

	return NULL;
}

static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
						u32 rid_in, u32 *rid_out,
						u8 type)
						u8 type_mask)
{
	u32 rid = rid_in;

@@ -223,7 +370,7 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
		struct acpi_iort_id_mapping *map;
		int i;

		if (node->type == type) {
		if (IORT_TYPE_MASK(node->type) & type_mask) {
			if (rid_out)
				*rid_out = rid;
			return node;
@@ -296,7 +443,7 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
	if (!node)
		return req_id;

	iort_node_map_rid(node, req_id, &dev_id, ACPI_IORT_NODE_ITS_GROUP);
	iort_node_map_rid(node, req_id, &dev_id, IORT_MSI_TYPE);
	return dev_id;
}

@@ -318,7 +465,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
	if (!node)
		return -ENXIO;

	node = iort_node_map_rid(node, req_id, NULL, ACPI_IORT_NODE_ITS_GROUP);
	node = iort_node_map_rid(node, req_id, NULL, IORT_MSI_TYPE);
	if (!node)
		return -ENXIO;

@@ -356,13 +503,459 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
	return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
}

static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
{
	u32 *rid = data;

	*rid = alias;
	return 0;
}

static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
			       struct fwnode_handle *fwnode,
			       const struct iommu_ops *ops)
{
	int ret = iommu_fwspec_init(dev, fwnode, ops);

	if (!ret)
		ret = iommu_fwspec_add_ids(dev, &streamid, 1);

	return ret;
}

static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
					struct acpi_iort_node *node,
					u32 streamid)
{
	const struct iommu_ops *ops = NULL;
	int ret = -ENODEV;
	struct fwnode_handle *iort_fwnode;

	if (node) {
		iort_fwnode = iort_get_fwnode(node);
		if (!iort_fwnode)
			return NULL;

		ops = iommu_get_instance(iort_fwnode);
		if (!ops)
			return NULL;

		ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops);
	}

	return ret ? NULL : ops;
}

/**
 * iort_set_dma_mask - Set-up dma mask for a device.
 *
 * @dev: device to configure
 */
void iort_set_dma_mask(struct device *dev)
{
	/*
	 * Set default coherent_dma_mask to 32 bit.  Drivers are expected to
	 * setup the correct supported mask.
	 */
	if (!dev->coherent_dma_mask)
		dev->coherent_dma_mask = DMA_BIT_MASK(32);

	/*
	 * Set it to coherent_dma_mask by default if the architecture
	 * code has not set it.
	 */
	if (!dev->dma_mask)
		dev->dma_mask = &dev->coherent_dma_mask;
}

/**
 * iort_iommu_configure - Set-up IOMMU configuration for a device.
 *
 * @dev: device to configure
 *
 * Returns: iommu_ops pointer on configuration success
 *          NULL on configuration failure
 */
const struct iommu_ops *iort_iommu_configure(struct device *dev)
{
	struct acpi_iort_node *node, *parent;
	const struct iommu_ops *ops = NULL;
	u32 streamid = 0;

	if (dev_is_pci(dev)) {
		struct pci_bus *bus = to_pci_dev(dev)->bus;
		u32 rid;

		pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
				       &rid);

		node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
				      iort_match_node_callback, &bus->dev);
		if (!node)
			return NULL;

		parent = iort_node_map_rid(node, rid, &streamid,
					   IORT_IOMMU_TYPE);

		ops = iort_iommu_xlate(dev, parent, streamid);

	} else {
		int i = 0;

		node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
				      iort_match_node_callback, dev);
		if (!node)
			return NULL;

		parent = iort_node_get_id(node, &streamid,
					  IORT_IOMMU_TYPE, i++);

		while (parent) {
			ops = iort_iommu_xlate(dev, parent, streamid);

			parent = iort_node_get_id(node, &streamid,
						  IORT_IOMMU_TYPE, i++);
		}
	}

	return ops;
}

static void __init acpi_iort_register_irq(int hwirq, const char *name,
					  int trigger,
					  struct resource *res)
{
	int irq = acpi_register_gsi(NULL, hwirq, trigger,
				    ACPI_ACTIVE_HIGH);

	if (irq <= 0) {
		pr_err("could not register gsi hwirq %d name [%s]\n", hwirq,
								      name);
		return;
	}

	res->start = irq;
	res->end = irq;
	res->flags = IORESOURCE_IRQ;
	res->name = name;
}

static int __init arm_smmu_v3_count_resources(struct acpi_iort_node *node)
{
	struct acpi_iort_smmu_v3 *smmu;
	/* Always present mem resource */
	int num_res = 1;

	/* Retrieve SMMUv3 specific data */
	smmu = (struct acpi_iort_smmu_v3 *)node->node_data;

	if (smmu->event_gsiv)
		num_res++;

	if (smmu->pri_gsiv)
		num_res++;

	if (smmu->gerr_gsiv)
		num_res++;

	if (smmu->sync_gsiv)
		num_res++;

	return num_res;
}

static void __init arm_smmu_v3_init_resources(struct resource *res,
					      struct acpi_iort_node *node)
{
	struct acpi_iort_smmu_v3 *smmu;
	int num_res = 0;

	/* Retrieve SMMUv3 specific data */
	smmu = (struct acpi_iort_smmu_v3 *)node->node_data;

	res[num_res].start = smmu->base_address;
	res[num_res].end = smmu->base_address + SZ_128K - 1;
	res[num_res].flags = IORESOURCE_MEM;

	num_res++;

	if (smmu->event_gsiv)
		acpi_iort_register_irq(smmu->event_gsiv, "eventq",
				       ACPI_EDGE_SENSITIVE,
				       &res[num_res++]);

	if (smmu->pri_gsiv)
		acpi_iort_register_irq(smmu->pri_gsiv, "priq",
				       ACPI_EDGE_SENSITIVE,
				       &res[num_res++]);

	if (smmu->gerr_gsiv)
		acpi_iort_register_irq(smmu->gerr_gsiv, "gerror",
				       ACPI_EDGE_SENSITIVE,
				       &res[num_res++]);

	if (smmu->sync_gsiv)
		acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync",
				       ACPI_EDGE_SENSITIVE,
				       &res[num_res++]);
}

static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node)
{
	struct acpi_iort_smmu_v3 *smmu;

	/* Retrieve SMMUv3 specific data */
	smmu = (struct acpi_iort_smmu_v3 *)node->node_data;

	return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE;
}

static int __init arm_smmu_count_resources(struct acpi_iort_node *node)
{
	struct acpi_iort_smmu *smmu;

	/* Retrieve SMMU specific data */
	smmu = (struct acpi_iort_smmu *)node->node_data;

	/*
	 * Only consider the global fault interrupt and ignore the
	 * configuration access interrupt.
	 *
	 * MMIO address and global fault interrupt resources are always
	 * present so add them to the context interrupt count as a static
	 * value.
	 */
	return smmu->context_interrupt_count + 2;
}

static void __init arm_smmu_init_resources(struct resource *res,
					   struct acpi_iort_node *node)
{
	struct acpi_iort_smmu *smmu;
	int i, hw_irq, trigger, num_res = 0;
	u64 *ctx_irq, *glb_irq;

	/* Retrieve SMMU specific data */
	smmu = (struct acpi_iort_smmu *)node->node_data;

	res[num_res].start = smmu->base_address;
	res[num_res].end = smmu->base_address + smmu->span - 1;
	res[num_res].flags = IORESOURCE_MEM;
	num_res++;

	glb_irq = ACPI_ADD_PTR(u64, node, smmu->global_interrupt_offset);
	/* Global IRQs */
	hw_irq = IORT_IRQ_MASK(glb_irq[0]);
	trigger = IORT_IRQ_TRIGGER_MASK(glb_irq[0]);

	acpi_iort_register_irq(hw_irq, "arm-smmu-global", trigger,
				     &res[num_res++]);

	/* Context IRQs */
	ctx_irq = ACPI_ADD_PTR(u64, node, smmu->context_interrupt_offset);
	for (i = 0; i < smmu->context_interrupt_count; i++) {
		hw_irq = IORT_IRQ_MASK(ctx_irq[i]);
		trigger = IORT_IRQ_TRIGGER_MASK(ctx_irq[i]);

		acpi_iort_register_irq(hw_irq, "arm-smmu-context", trigger,
				       &res[num_res++]);
	}
}

static bool __init arm_smmu_is_coherent(struct acpi_iort_node *node)
{
	struct acpi_iort_smmu *smmu;

	/* Retrieve SMMU specific data */
	smmu = (struct acpi_iort_smmu *)node->node_data;

	return smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK;
}

struct iort_iommu_config {
	const char *name;
	int (*iommu_init)(struct acpi_iort_node *node);
	bool (*iommu_is_coherent)(struct acpi_iort_node *node);
	int (*iommu_count_resources)(struct acpi_iort_node *node);
	void (*iommu_init_resources)(struct resource *res,
				     struct acpi_iort_node *node);
};

static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = {
	.name = "arm-smmu-v3",
	.iommu_is_coherent = arm_smmu_v3_is_coherent,
	.iommu_count_resources = arm_smmu_v3_count_resources,
	.iommu_init_resources = arm_smmu_v3_init_resources
};

static const struct iort_iommu_config iort_arm_smmu_cfg __initconst = {
	.name = "arm-smmu",
	.iommu_is_coherent = arm_smmu_is_coherent,
	.iommu_count_resources = arm_smmu_count_resources,
	.iommu_init_resources = arm_smmu_init_resources
};

static __init
const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
{
	switch (node->type) {
	case ACPI_IORT_NODE_SMMU_V3:
		return &iort_arm_smmu_v3_cfg;
	case ACPI_IORT_NODE_SMMU:
		return &iort_arm_smmu_cfg;
	default:
		return NULL;
	}
}

/**
 * iort_add_smmu_platform_device() - Allocate a platform device for SMMU
 * @node: Pointer to SMMU ACPI IORT node
 *
 * Returns: 0 on success, <0 failure
 */
static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
{
	struct fwnode_handle *fwnode;
	struct platform_device *pdev;
	struct resource *r;
	enum dev_dma_attr attr;
	int ret, count;
	const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);

	if (!ops)
		return -ENODEV;

	pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
	if (!pdev)
		return PTR_ERR(pdev);

	count = ops->iommu_count_resources(node);

	r = kcalloc(count, sizeof(*r), GFP_KERNEL);
	if (!r) {
		ret = -ENOMEM;
		goto dev_put;
	}

	ops->iommu_init_resources(r, node);

	ret = platform_device_add_resources(pdev, r, count);
	/*
	 * Resources are duplicated in platform_device_add_resources,
	 * free their allocated memory
	 */
	kfree(r);

	if (ret)
		goto dev_put;

	/*
	 * Add a copy of IORT node pointer to platform_data to
	 * be used to retrieve IORT data information.
	 */
	ret = platform_device_add_data(pdev, &node, sizeof(node));
	if (ret)
		goto dev_put;

	/*
	 * We expect the dma masks to be equivalent for
	 * all SMMUs set-ups
	 */
	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;

	fwnode = iort_get_fwnode(node);

	if (!fwnode) {
		ret = -ENODEV;
		goto dev_put;
	}

	pdev->dev.fwnode = fwnode;

	attr = ops->iommu_is_coherent(node) ?
			     DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;

	/* Configure DMA for the page table walker */
	acpi_dma_configure(&pdev->dev, attr);

	ret = platform_device_add(pdev);
	if (ret)
		goto dma_deconfigure;

	return 0;

dma_deconfigure:
	acpi_dma_deconfigure(&pdev->dev);
dev_put:
	platform_device_put(pdev);

	return ret;
}

static void __init iort_init_platform_devices(void)
{
	struct acpi_iort_node *iort_node, *iort_end;
	struct acpi_table_iort *iort;
	struct fwnode_handle *fwnode;
	int i, ret;

	/*
	 * iort_table and iort both point to the start of IORT table, but
	 * have different struct types
	 */
	iort = (struct acpi_table_iort *)iort_table;

	/* Get the first IORT node */
	iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
				 iort->node_offset);
	iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort,
				iort_table->length);

	for (i = 0; i < iort->node_count; i++) {
		if (iort_node >= iort_end) {
			pr_err("iort node pointer overflows, bad table\n");
			return;
		}

		if ((iort_node->type == ACPI_IORT_NODE_SMMU) ||
			(iort_node->type == ACPI_IORT_NODE_SMMU_V3)) {

			fwnode = acpi_alloc_fwnode_static();
			if (!fwnode)
				return;

			iort_set_fwnode(iort_node, fwnode);

			ret = iort_add_smmu_platform_device(iort_node);
			if (ret) {
				iort_delete_fwnode(iort_node);
				acpi_free_fwnode_static(fwnode);
				return;
			}
		}

		iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
					 iort_node->length);
	}
}

void __init acpi_iort_init(void)
{
	acpi_status status;

	status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
	if (ACPI_FAILURE(status)) {
		if (status != AE_NOT_FOUND) {
			const char *msg = acpi_format_exception(status);

			pr_err("Failed to get table, %s\n", msg);
		}

		return;
	}

	iort_init_platform_devices();

	acpi_probe_device_table(iort);
}
+2 −2
Original line number Diff line number Diff line
@@ -227,8 +227,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)

	attr = acpi_get_dma_attr(acpi_dev);
	if (attr != DEV_DMA_NOT_SUPPORTED)
		arch_setup_dma_ops(dev, 0, 0, NULL,
				   attr == DEV_DMA_COHERENT);
		acpi_dma_configure(dev, attr);

	acpi_physnode_link_name(physical_node_name, node_id);
	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
@@ -251,6 +250,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
	return 0;

 err:
	acpi_dma_deconfigure(dev);
	ACPI_COMPANION_SET(dev, NULL);
	put_device(dev);
	put_device(&acpi_dev->dev);
+33 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/acpi_iort.h>
#include <linux/signal.h>
#include <linux/kthread.h>
#include <linux/dmi.h>
@@ -1370,6 +1371,38 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
		return DEV_DMA_NON_COHERENT;
}

/**
 * acpi_dma_configure - Set-up DMA configuration for the device.
 * @dev: The pointer to the device
 * @attr: device dma attributes
 */
void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
{
	const struct iommu_ops *iommu;

	iort_set_dma_mask(dev);

	iommu = iort_iommu_configure(dev);

	/*
	 * Assume dma valid range starts at 0 and covers the whole
	 * coherent_dma_mask.
	 */
	arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, iommu,
			   attr == DEV_DMA_COHERENT);
}
EXPORT_SYMBOL_GPL(acpi_dma_configure);

/**
 * acpi_dma_deconfigure - Tear-down DMA configuration for the device.
 * @dev: The pointer to the device
 */
void acpi_dma_deconfigure(struct device *dev)
{
	arch_teardown_dma_ops(dev);
}
EXPORT_SYMBOL_GPL(acpi_dma_deconfigure);

static void acpi_init_coherency(struct acpi_device *adev)
{
	unsigned long long cca = 0;
+2 −0
Original line number Diff line number Diff line
@@ -373,6 +373,8 @@ static struct iommu_group *acpihid_device_group(struct device *dev)

	if (!entry->group)
		entry->group = generic_device_group(dev);
	else
		iommu_group_ref_get(entry->group);

	return entry->group;
}
Loading