diff options
Diffstat (limited to 'drivers/iommu/iommu.c')
| -rw-r--r-- | drivers/iommu/iommu.c | 161 | 
1 files changed, 74 insertions, 87 deletions
| diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index d0b0a15dba84..808ab70d5df5 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -69,16 +69,7 @@ static const char * const iommu_group_resv_type_string[] = {  };  #define IOMMU_CMD_LINE_DMA_API		BIT(0) - -static void iommu_set_cmd_line_dma_api(void) -{ -	iommu_cmd_line |= IOMMU_CMD_LINE_DMA_API; -} - -static bool iommu_cmd_line_dma_api(void) -{ -	return !!(iommu_cmd_line & IOMMU_CMD_LINE_DMA_API); -} +#define IOMMU_CMD_LINE_STRICT		BIT(1)  static int iommu_alloc_default_domain(struct iommu_group *group,  				      struct device *dev); @@ -130,9 +121,7 @@ static const char *iommu_domain_type_str(unsigned int t)  static int __init iommu_subsys_init(void)  { -	bool cmd_line = iommu_cmd_line_dma_api(); - -	if (!cmd_line) { +	if (!(iommu_cmd_line & IOMMU_CMD_LINE_DMA_API)) {  		if (IS_ENABLED(CONFIG_IOMMU_DEFAULT_PASSTHROUGH))  			iommu_set_default_passthrough(false);  		else @@ -146,14 +135,32 @@ static int __init iommu_subsys_init(void)  	pr_info("Default domain type: %s %s\n",  		iommu_domain_type_str(iommu_def_domain_type), -		cmd_line ? "(set via kernel command line)" : ""); +		(iommu_cmd_line & IOMMU_CMD_LINE_DMA_API) ? +			"(set via kernel command line)" : "");  	return 0;  }  subsys_initcall(iommu_subsys_init); -int iommu_device_register(struct iommu_device *iommu) +/** + * iommu_device_register() - Register an IOMMU hardware instance + * @iommu: IOMMU handle for the instance + * @ops:   IOMMU ops to associate with the instance + * @hwdev: (optional) actual instance device, used for fwnode lookup + * + * Return: 0 on success, or an error. + */ +int iommu_device_register(struct iommu_device *iommu, +			  const struct iommu_ops *ops, struct device *hwdev)  { +	/* We need to be able to take module references appropriately */ +	if (WARN_ON(is_module_address((unsigned long)ops) && !ops->owner)) +		return -EINVAL; + +	iommu->ops = ops; +	if (hwdev) +		iommu->fwnode = hwdev->fwnode; +  	spin_lock(&iommu_device_lock);  	list_add_tail(&iommu->list, &iommu_device_list);  	spin_unlock(&iommu_device_lock); @@ -329,10 +336,29 @@ early_param("iommu.passthrough", iommu_set_def_domain_type);  static int __init iommu_dma_setup(char *str)  { -	return kstrtobool(str, &iommu_dma_strict); +	int ret = kstrtobool(str, &iommu_dma_strict); + +	if (!ret) +		iommu_cmd_line |= IOMMU_CMD_LINE_STRICT; +	return ret;  }  early_param("iommu.strict", iommu_dma_setup); +void iommu_set_dma_strict(bool strict) +{ +	if (strict || !(iommu_cmd_line & IOMMU_CMD_LINE_STRICT)) +		iommu_dma_strict = strict; +} + +bool iommu_get_dma_strict(struct iommu_domain *domain) +{ +	/* only allow lazy flushing for DMA domains */ +	if (domain->type == IOMMU_DOMAIN_DMA) +		return iommu_dma_strict; +	return true; +} +EXPORT_SYMBOL_GPL(iommu_get_dma_strict); +  static ssize_t iommu_group_attr_show(struct kobject *kobj,  				     struct attribute *__attr, char *buf)  { @@ -1511,14 +1537,6 @@ static int iommu_group_alloc_default_domain(struct bus_type *bus,  	group->default_domain = dom;  	if (!group->domain)  		group->domain = dom; - -	if (!iommu_dma_strict) { -		int attr = 1; -		iommu_domain_set_attr(dom, -				      DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE, -				      &attr); -	} -  	return 0;  } @@ -2610,17 +2628,6 @@ size_t iommu_map_sg_atomic(struct iommu_domain *domain, unsigned long iova,  	return __iommu_map_sg(domain, iova, sg, nents, prot, GFP_ATOMIC);  } -int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr, -			       phys_addr_t paddr, u64 size, int prot) -{ -	if (unlikely(domain->ops->domain_window_enable == NULL)) -		return -ENODEV; - -	return domain->ops->domain_window_enable(domain, wnd_nr, paddr, size, -						 prot); -} -EXPORT_SYMBOL_GPL(iommu_domain_window_enable); -  /**   * report_iommu_fault() - report about an IOMMU fault to the IOMMU framework   * @domain: the iommu domain where the fault has happened @@ -2675,50 +2682,26 @@ static int __init iommu_init(void)  }  core_initcall(iommu_init); -int iommu_domain_get_attr(struct iommu_domain *domain, -			  enum iommu_attr attr, void *data) +int iommu_enable_nesting(struct iommu_domain *domain)  { -	struct iommu_domain_geometry *geometry; -	bool *paging; -	int ret = 0; - -	switch (attr) { -	case DOMAIN_ATTR_GEOMETRY: -		geometry  = data; -		*geometry = domain->geometry; - -		break; -	case DOMAIN_ATTR_PAGING: -		paging  = data; -		*paging = (domain->pgsize_bitmap != 0UL); -		break; -	default: -		if (!domain->ops->domain_get_attr) -			return -EINVAL; - -		ret = domain->ops->domain_get_attr(domain, attr, data); -	} - -	return ret; +	if (domain->type != IOMMU_DOMAIN_UNMANAGED) +		return -EINVAL; +	if (!domain->ops->enable_nesting) +		return -EINVAL; +	return domain->ops->enable_nesting(domain);  } -EXPORT_SYMBOL_GPL(iommu_domain_get_attr); +EXPORT_SYMBOL_GPL(iommu_enable_nesting); -int iommu_domain_set_attr(struct iommu_domain *domain, -			  enum iommu_attr attr, void *data) +int iommu_set_pgtable_quirks(struct iommu_domain *domain, +		unsigned long quirk)  { -	int ret = 0; - -	switch (attr) { -	default: -		if (domain->ops->domain_set_attr == NULL) -			return -EINVAL; - -		ret = domain->ops->domain_set_attr(domain, attr, data); -	} - -	return ret; +	if (domain->type != IOMMU_DOMAIN_UNMANAGED) +		return -EINVAL; +	if (!domain->ops->set_pgtable_quirks) +		return -EINVAL; +	return domain->ops->set_pgtable_quirks(domain, quirk);  } -EXPORT_SYMBOL_GPL(iommu_domain_set_attr); +EXPORT_SYMBOL_GPL(iommu_set_pgtable_quirks);  void iommu_get_resv_regions(struct device *dev, struct list_head *list)  { @@ -2777,16 +2760,14 @@ EXPORT_SYMBOL_GPL(iommu_alloc_resv_region);  void iommu_set_default_passthrough(bool cmd_line)  {  	if (cmd_line) -		iommu_set_cmd_line_dma_api(); - +		iommu_cmd_line |= IOMMU_CMD_LINE_DMA_API;  	iommu_def_domain_type = IOMMU_DOMAIN_IDENTITY;  }  void iommu_set_default_translated(bool cmd_line)  {  	if (cmd_line) -		iommu_set_cmd_line_dma_api(); - +		iommu_cmd_line |= IOMMU_CMD_LINE_DMA_API;  	iommu_def_domain_type = IOMMU_DOMAIN_DMA;  } @@ -2878,10 +2859,12 @@ EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids);   */  int iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features feat)  { -	const struct iommu_ops *ops = dev->bus->iommu_ops; +	if (dev->iommu && dev->iommu->iommu_dev) { +		const struct iommu_ops *ops = dev->iommu->iommu_dev->ops; -	if (ops && ops->dev_enable_feat) -		return ops->dev_enable_feat(dev, feat); +		if (ops->dev_enable_feat) +			return ops->dev_enable_feat(dev, feat); +	}  	return -ENODEV;  } @@ -2894,10 +2877,12 @@ EXPORT_SYMBOL_GPL(iommu_dev_enable_feature);   */  int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat)  { -	const struct iommu_ops *ops = dev->bus->iommu_ops; +	if (dev->iommu && dev->iommu->iommu_dev) { +		const struct iommu_ops *ops = dev->iommu->iommu_dev->ops; -	if (ops && ops->dev_disable_feat) -		return ops->dev_disable_feat(dev, feat); +		if (ops->dev_disable_feat) +			return ops->dev_disable_feat(dev, feat); +	}  	return -EBUSY;  } @@ -2905,10 +2890,12 @@ EXPORT_SYMBOL_GPL(iommu_dev_disable_feature);  bool iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features feat)  { -	const struct iommu_ops *ops = dev->bus->iommu_ops; +	if (dev->iommu && dev->iommu->iommu_dev) { +		const struct iommu_ops *ops = dev->iommu->iommu_dev->ops; -	if (ops && ops->dev_feat_enabled) -		return ops->dev_feat_enabled(dev, feat); +		if (ops->dev_feat_enabled) +			return ops->dev_feat_enabled(dev, feat); +	}  	return false;  } | 
