drivers/iommu/intel/dmar.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iommu/intel/dmar.c
Extension
.c
Size
63723 bytes
Lines
2395
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

struct dmar_res_callback {
	dmar_res_handler_t	cb[ACPI_DMAR_TYPE_RESERVED];
	void			*arg[ACPI_DMAR_TYPE_RESERVED];
	bool			ignore_unhandled;
	bool			print_entry;
};

/*
 * Assumptions:
 * 1) The hotplug framework guarentees that DMAR unit will be hot-added
 *    before IO devices managed by that unit.
 * 2) The hotplug framework guarantees that DMAR unit will be hot-removed
 *    after IO devices managed by that unit.
 * 3) Hotplug events are rare.
 *
 * Locking rules for DMA and interrupt remapping related global data structures:
 * 1) Use dmar_global_lock in process context
 * 2) Use RCU in interrupt context
 */
DECLARE_RWSEM(dmar_global_lock);
LIST_HEAD(dmar_drhd_units);

struct acpi_table_header * __initdata dmar_tbl;
static int dmar_dev_scope_status = 1;
static DEFINE_IDA(dmar_seq_ids);

static int alloc_iommu(struct dmar_drhd_unit *drhd);
static void free_iommu(struct intel_iommu *iommu);

static void dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
{
	/*
	 * add INCLUDE_ALL at the tail, so scan the list will find it at
	 * the very end.
	 */
	if (drhd->include_all)
		list_add_tail_rcu(&drhd->list, &dmar_drhd_units);
	else
		list_add_rcu(&drhd->list, &dmar_drhd_units);
}

void *dmar_alloc_dev_scope(void *start, void *end, int *cnt)
{
	struct acpi_dmar_device_scope *scope;

	*cnt = 0;
	while (start < end) {
		scope = start;
		if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_NAMESPACE ||
		    scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
		    scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
			(*cnt)++;
		else if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_IOAPIC &&
			scope->entry_type != ACPI_DMAR_SCOPE_TYPE_HPET) {
			pr_warn("Unsupported device scope\n");
		}
		start += scope->length;
	}
	if (*cnt == 0)
		return NULL;

	return kzalloc_objs(struct dmar_dev_scope, *cnt);
}

void dmar_free_dev_scope(struct dmar_dev_scope **devices, int *cnt)
{
	int i;
	struct device *tmp_dev;

	if (*devices && *cnt) {
		for_each_active_dev_scope(*devices, *cnt, i, tmp_dev)
			put_device(tmp_dev);
		kfree(*devices);
	}

	*devices = NULL;
	*cnt = 0;
}

/* Optimize out kzalloc()/kfree() for normal cases */
static char dmar_pci_notify_info_buf[64];

static struct dmar_pci_notify_info *
dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event)
{
	int level = 0;
	size_t size;
	struct pci_dev *tmp;
	struct dmar_pci_notify_info *info;

Annotation

Implementation Notes