drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c

Source file repositories/reference/linux-study-clean/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c

File Facts

System
Linux kernel
Corpus path
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
Extension
.c
Size
161117 bytes
Lines
5558
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 arm_smmu_option_prop {
	u32 opt;
	const char *prop;
};

DEFINE_XARRAY_ALLOC1(arm_smmu_asid_xa);
DEFINE_MUTEX(arm_smmu_asid_lock);

static struct arm_smmu_option_prop arm_smmu_options[] = {
	{ ARM_SMMU_OPT_SKIP_PREFETCH, "hisilicon,broken-prefetch-cmd" },
	{ ARM_SMMU_OPT_PAGE0_REGS_ONLY, "cavium,cn9900-broken-page1-regspace"},
	{ 0, NULL},
};

static const char * const event_str[] = {
	[EVT_ID_BAD_STREAMID_CONFIG] = "C_BAD_STREAMID",
	[EVT_ID_STE_FETCH_FAULT] = "F_STE_FETCH",
	[EVT_ID_BAD_STE_CONFIG] = "C_BAD_STE",
	[EVT_ID_STREAM_DISABLED_FAULT] = "F_STREAM_DISABLED",
	[EVT_ID_BAD_SUBSTREAMID_CONFIG] = "C_BAD_SUBSTREAMID",
	[EVT_ID_CD_FETCH_FAULT] = "F_CD_FETCH",
	[EVT_ID_BAD_CD_CONFIG] = "C_BAD_CD",
	[EVT_ID_TRANSLATION_FAULT] = "F_TRANSLATION",
	[EVT_ID_ADDR_SIZE_FAULT] = "F_ADDR_SIZE",
	[EVT_ID_ACCESS_FAULT] = "F_ACCESS",
	[EVT_ID_PERMISSION_FAULT] = "F_PERMISSION",
	[EVT_ID_VMS_FETCH_FAULT] = "F_VMS_FETCH",
};

static const char * const event_class_str[] = {
	[0] = "CD fetch",
	[1] = "Stage 1 translation table fetch",
	[2] = "Input address caused fault",
	[3] = "Reserved",
};

static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master);
static bool arm_smmu_ats_supported(struct arm_smmu_master *master);

static void parse_driver_options(struct arm_smmu_device *smmu)
{
	int i = 0;

	do {
		if (of_property_read_bool(smmu->dev->of_node,
						arm_smmu_options[i].prop)) {
			smmu->options |= arm_smmu_options[i].opt;
			dev_notice(smmu->dev, "option %s\n",
				arm_smmu_options[i].prop);
		}
	} while (arm_smmu_options[++i].opt);
}

/* Low-level queue manipulation functions */
static bool queue_has_space(struct arm_smmu_ll_queue *q, u32 n)
{
	u32 space, prod, cons;

	prod = Q_IDX(q, q->prod);
	cons = Q_IDX(q, q->cons);

	if (Q_WRP(q, q->prod) == Q_WRP(q, q->cons))
		space = (1 << q->max_n_shift) - (prod - cons);
	else
		space = cons - prod;

	return space >= n;
}

static bool queue_full(struct arm_smmu_ll_queue *q)
{
	return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) &&
	       Q_WRP(q, q->prod) != Q_WRP(q, q->cons);
}

static bool queue_empty(struct arm_smmu_ll_queue *q)
{
	return Q_IDX(q, q->prod) == Q_IDX(q, q->cons) &&
	       Q_WRP(q, q->prod) == Q_WRP(q, q->cons);
}

static bool queue_consumed(struct arm_smmu_ll_queue *q, u32 prod)
{
	return ((Q_WRP(q, q->cons) == Q_WRP(q, prod)) &&
		(Q_IDX(q, q->cons) > Q_IDX(q, prod))) ||
	       ((Q_WRP(q, q->cons) != Q_WRP(q, prod)) &&
		(Q_IDX(q, q->cons) <= Q_IDX(q, prod)));
}

static void queue_sync_cons_out(struct arm_smmu_queue *q)

Annotation

Implementation Notes