drivers/acpi/viot.c

Source file repositories/reference/linux-study-clean/drivers/acpi/viot.c

File Facts

System
Linux kernel
Corpus path
drivers/acpi/viot.c
Extension
.c
Size
9054 bytes
Lines
374
Domain
Driver Families
Bucket
drivers/acpi
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

struct viot_iommu {
	/* Node offset within the table */
	unsigned int			offset;
	struct fwnode_handle		*fwnode;
	struct list_head		list;
};

struct viot_endpoint {
	union {
		/* PCI range */
		struct {
			u16		segment_start;
			u16		segment_end;
			u16		bdf_start;
			u16		bdf_end;
		};
		/* MMIO */
		u64			address;
	};
	u32				endpoint_id;
	struct viot_iommu		*viommu;
	struct list_head		list;
};

static struct acpi_table_viot *viot;
static LIST_HEAD(viot_iommus);
static LIST_HEAD(viot_pci_ranges);
static LIST_HEAD(viot_mmio_endpoints);

static int __init viot_check_bounds(const struct acpi_viot_header *hdr)
{
	struct acpi_viot_header *start, *end, *hdr_end;

	start = ACPI_ADD_PTR(struct acpi_viot_header, viot,
			     max_t(size_t, sizeof(*viot), viot->node_offset));
	end = ACPI_ADD_PTR(struct acpi_viot_header, viot, viot->header.length);
	hdr_end = ACPI_ADD_PTR(struct acpi_viot_header, hdr, sizeof(*hdr));

	if (hdr < start || hdr_end > end) {
		pr_err(FW_BUG "Node pointer overflows\n");
		return -EOVERFLOW;
	}
	if (hdr->length < sizeof(*hdr)) {
		pr_err(FW_BUG "Empty node\n");
		return -EINVAL;
	}
	return 0;
}

static int __init viot_get_pci_iommu_fwnode(struct viot_iommu *viommu,
					    u16 segment, u16 bdf)
{
	struct pci_dev *pdev;
	struct fwnode_handle *fwnode;

	pdev = pci_get_domain_bus_and_slot(segment, PCI_BUS_NUM(bdf),
					   bdf & 0xff);
	if (!pdev) {
		pr_err("Could not find PCI IOMMU\n");
		return -ENODEV;
	}

	fwnode = dev_fwnode(&pdev->dev);
	if (!fwnode) {
		/*
		 * PCI devices aren't necessarily described by ACPI. Create a
		 * fwnode so the IOMMU subsystem can identify this device.
		 */
		fwnode = acpi_alloc_fwnode_static();
		if (!fwnode) {
			pci_dev_put(pdev);
			return -ENOMEM;
		}
		set_primary_fwnode(&pdev->dev, fwnode);
	}
	viommu->fwnode = dev_fwnode(&pdev->dev);
	pci_dev_put(pdev);
	return 0;
}

static int __init viot_get_mmio_iommu_fwnode(struct viot_iommu *viommu,
					     u64 address)
{
	struct acpi_device *adev;
	struct resource res = {
		.start	= address,
		.end	= address,
		.flags	= IORESOURCE_MEM,
	};

Annotation

Implementation Notes