drivers/iommu/amd/iommu.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iommu/amd/iommu.c
Extension
.c
Size
110257 bytes
Lines
4198
Domain
Driver Families
Bucket
drivers/iommu
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

FIELD_GET(DTE_GPT_LEVEL_MASK, new->data[2])) {
		/*
		 * Both DTEs are valid and have guest page table,
		 * but have different number of levels. So, we need
		 * to upadte both upper and lower 128-bit value, which
		 * require disabling and flushing.
		 */
		struct dev_table_entry clear = {};

		/* First disable DTE */
		write_dte_lower128(ptr, &clear);
		iommu_flush_dte_sync(iommu, dev_data->devid);

		/* Then update DTE */
		write_dte_upper128(ptr, new);
		write_dte_lower128(ptr, new);
		iommu_flush_dte_sync(iommu, dev_data->devid);
	} else {
		/*
		 * Both DTEs are valid and have guest page table,
		 * and same number of levels. We just need to only
		 * update the lower 128-bit. So no need to disable DTE.
		 */
		write_dte_lower128(ptr, new);
	}

	spin_unlock_irqrestore(&dev_data->dte_lock, flags);
}

void amd_iommu_update_dte(struct amd_iommu *iommu,
			     struct iommu_dev_data *dev_data,
			     struct dev_table_entry *new)
{
	update_dte256(iommu, dev_data, new);
	clone_aliases(iommu, dev_data->dev);
	device_flush_dte(dev_data);
	iommu_completion_wait(iommu);
}

static void get_dte256(struct amd_iommu *iommu, struct iommu_dev_data *dev_data,
		      struct dev_table_entry *dte)
{
	unsigned long flags;
	struct dev_table_entry *ptr;
	struct dev_table_entry *dev_table = get_dev_table(iommu);

	ptr = &dev_table[dev_data->devid];

	spin_lock_irqsave(&dev_data->dte_lock, flags);
	dte->data128[0] = ptr->data128[0];
	dte->data128[1] = ptr->data128[1];
	spin_unlock_irqrestore(&dev_data->dte_lock, flags);
}

static inline bool pdom_is_v2_pgtbl_mode(struct protection_domain *pdom)
{
	return (pdom && (pdom->pd_mode == PD_MODE_V2));
}

static inline bool pdom_is_in_pt_mode(struct protection_domain *pdom)
{
	return (pdom->domain.type == IOMMU_DOMAIN_IDENTITY);
}

/*
 * We cannot support PASID w/ existing v1 page table in the same domain
 * since it will be nested. However, existing domain w/ v2 page table
 * or passthrough mode can be used for PASID.
 */
static inline bool pdom_is_sva_capable(struct protection_domain *pdom)
{
	return pdom_is_v2_pgtbl_mode(pdom) || pdom_is_in_pt_mode(pdom);
}

static inline int get_acpihid_device_id(struct device *dev,
					struct acpihid_map_entry **entry)
{
	struct acpi_device *adev = ACPI_COMPANION(dev);
	struct acpihid_map_entry *p, *p1 = NULL;
	int hid_count = 0;
	bool fw_bug;

	if (!adev)
		return -ENODEV;

	list_for_each_entry(p, &acpihid_map, list) {
		if (acpi_dev_hid_uid_match(adev, p->hid,
					   p->uid[0] ? p->uid : NULL)) {
			p1 = p;
			fw_bug = false;

Annotation

Implementation Notes