drivers/iommu/intel/cache.c

Source file repositories/reference/linux-study-clean/drivers/iommu/intel/cache.c

File Facts

System
Linux kernel
Corpus path
drivers/iommu/intel/cache.c
Extension
.c
Size
14954 bytes
Lines
522
Domain
Driver Families
Bucket
drivers/iommu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (cache_tage_match(temp, did, iommu, dev, pasid, type)) {
			temp->users++;
			spin_unlock_irqrestore(&domain->cache_lock, flags);
			kfree(tag);
			trace_cache_tag_assign(temp);
			return 0;
		}
		if (temp->iommu == iommu)
			prev = &temp->node;
	}
	/*
	 * Link cache tags of same iommu unit together, so corresponding
	 * flush ops can be batched for iommu unit.
	 */
	list_add(&tag->node, prev);

	spin_unlock_irqrestore(&domain->cache_lock, flags);
	trace_cache_tag_assign(tag);

	return 0;
}

/* Unassign a cache tag with specified type from domain. */
static void cache_tag_unassign(struct dmar_domain *domain, u16 did,
			       struct device *dev, ioasid_t pasid,
			       enum cache_tag_type type)
{
	struct device_domain_info *info = dev_iommu_priv_get(dev);
	struct intel_iommu *iommu = info->iommu;
	struct cache_tag *tag;
	unsigned long flags;

	spin_lock_irqsave(&domain->cache_lock, flags);
	list_for_each_entry(tag, &domain->cache_tags, node) {
		if (cache_tage_match(tag, did, iommu, dev, pasid, type)) {
			trace_cache_tag_unassign(tag);
			if (--tag->users == 0) {
				list_del(&tag->node);
				kfree(tag);
			}
			break;
		}
	}
	spin_unlock_irqrestore(&domain->cache_lock, flags);
}

/* domain->qi_batch will be freed in iommu_free_domain() path. */
static int domain_qi_batch_alloc(struct dmar_domain *domain)
{
	unsigned long flags;
	int ret = 0;

	spin_lock_irqsave(&domain->cache_lock, flags);
	if (domain->qi_batch)
		goto out_unlock;

	domain->qi_batch = kzalloc_obj(*domain->qi_batch, GFP_ATOMIC);
	if (!domain->qi_batch)
		ret = -ENOMEM;
out_unlock:
	spin_unlock_irqrestore(&domain->cache_lock, flags);

	return ret;
}

static int __cache_tag_assign_domain(struct dmar_domain *domain, u16 did,
				     struct device *dev, ioasid_t pasid)
{
	struct device_domain_info *info = dev_iommu_priv_get(dev);
	int ret;

	ret = domain_qi_batch_alloc(domain);
	if (ret)
		return ret;

	ret = cache_tag_assign(domain, did, dev, pasid, CACHE_TAG_IOTLB);
	if (ret || !info->ats_enabled)
		return ret;

	ret = cache_tag_assign(domain, did, dev, pasid, CACHE_TAG_DEVTLB);
	if (ret)
		cache_tag_unassign(domain, did, dev, pasid, CACHE_TAG_IOTLB);

	return ret;
}

static void __cache_tag_unassign_domain(struct dmar_domain *domain, u16 did,
					struct device *dev, ioasid_t pasid)
{
	struct device_domain_info *info = dev_iommu_priv_get(dev);

Annotation

Implementation Notes