drivers/iommu/intel/perfmon.c

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

File Facts

System
Linux kernel
Corpus path
drivers/iommu/intel/perfmon.c
Extension
.c
Size
22966 bytes
Lines
791
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

for_each_set_bit(i, (unsigned long *)&status, iommu_pmu->num_cntr) {
			/*
			 * Find the assigned event of the counter.
			 * Accumulate the value into the event->count.
			 */
			event = iommu_pmu->event_list[i];
			if (!event) {
				pr_warn_once("Cannot find the assigned event for counter %d\n", i);
				continue;
			}
			iommu_pmu_event_update(event);
		}

		writeq(status, iommu_pmu->overflow);
	}
}

static irqreturn_t iommu_pmu_irq_handler(int irq, void *dev_id)
{
	struct intel_iommu *iommu = dev_id;

	if (!readl(iommu->reg + DMAR_PERFINTRSTS_REG))
		return IRQ_NONE;

	iommu_pmu_counter_overflow(iommu->pmu);

	/* Clear the status bit */
	writel(DMA_PERFINTRSTS_PIS, iommu->reg + DMAR_PERFINTRSTS_REG);

	return IRQ_HANDLED;
}

static int __iommu_pmu_register(struct intel_iommu *iommu)
{
	struct iommu_pmu *iommu_pmu = iommu->pmu;

	iommu_pmu->pmu.name		= iommu->name;
	iommu_pmu->pmu.task_ctx_nr	= perf_invalid_context;
	iommu_pmu->pmu.event_init	= iommu_pmu_event_init;
	iommu_pmu->pmu.pmu_enable	= iommu_pmu_enable;
	iommu_pmu->pmu.pmu_disable	= iommu_pmu_disable;
	iommu_pmu->pmu.add		= iommu_pmu_add;
	iommu_pmu->pmu.del		= iommu_pmu_del;
	iommu_pmu->pmu.start		= iommu_pmu_start;
	iommu_pmu->pmu.stop		= iommu_pmu_stop;
	iommu_pmu->pmu.read		= iommu_pmu_event_update;
	iommu_pmu->pmu.attr_groups	= iommu_pmu_attr_groups;
	iommu_pmu->pmu.attr_update	= iommu_pmu_attr_update;
	iommu_pmu->pmu.capabilities	= PERF_PMU_CAP_NO_EXCLUDE;
	iommu_pmu->pmu.scope		= PERF_PMU_SCOPE_SYS_WIDE;
	iommu_pmu->pmu.module		= THIS_MODULE;

	return perf_pmu_register(&iommu_pmu->pmu, iommu_pmu->pmu.name, -1);
}

static inline void __iomem *
get_perf_reg_address(struct intel_iommu *iommu, u32 offset)
{
	u32 off = readl(iommu->reg + offset);

	return iommu->reg + off;
}

int alloc_iommu_pmu(struct intel_iommu *iommu)
{
	struct iommu_pmu *iommu_pmu;
	int i, j, ret;
	u64 perfcap;
	u32 cap;

	if (!ecap_pms(iommu->ecap))
		return 0;

	/* The IOMMU PMU requires the ECMD support as well */
	if (!cap_ecmds(iommu->cap))
		return -ENODEV;

	perfcap = readq(iommu->reg + DMAR_PERFCAP_REG);
	/* The performance monitoring is not supported. */
	if (!perfcap)
		return -ENODEV;

	/* Sanity check for the number of the counters and event groups */
	if (!pcap_num_cntr(perfcap) || !pcap_num_event_group(perfcap))
		return -ENODEV;

	/* The interrupt on overflow is required */
	if (!pcap_interrupt(perfcap))
		return -ENODEV;

Annotation

Implementation Notes