drivers/vfio/pci/vfio_pci_config.c

Source file repositories/reference/linux-study-clean/drivers/vfio/pci/vfio_pci_config.c

File Facts

System
Linux kernel
Corpus path
drivers/vfio/pci/vfio_pci_config.c
Extension
.c
Size
56871 bytes
Lines
2042
Domain
Driver Families
Bucket
drivers/vfio
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 perm_bits {
	u8	*virt;		/* read/write virtual data, not hw */
	u8	*write;		/* writeable bits */
	int	(*readfn)(struct vfio_pci_core_device *vdev, int pos, int count,
			  struct perm_bits *perm, int offset, __le32 *val);
	int	(*writefn)(struct vfio_pci_core_device *vdev, int pos, int count,
			   struct perm_bits *perm, int offset, __le32 val);
};

#define	NO_VIRT		0
#define	ALL_VIRT	0xFFFFFFFFU
#define	NO_WRITE	0
#define	ALL_WRITE	0xFFFFFFFFU

static int vfio_user_config_read(struct pci_dev *pdev, int offset,
				 __le32 *val, int count)
{
	int ret = -EINVAL;
	u32 tmp_val = 0;

	switch (count) {
	case 1:
	{
		u8 tmp;
		ret = pci_user_read_config_byte(pdev, offset, &tmp);
		tmp_val = tmp;
		break;
	}
	case 2:
	{
		u16 tmp;
		ret = pci_user_read_config_word(pdev, offset, &tmp);
		tmp_val = tmp;
		break;
	}
	case 4:
		ret = pci_user_read_config_dword(pdev, offset, &tmp_val);
		break;
	}

	*val = cpu_to_le32(tmp_val);

	return ret;
}

static int vfio_user_config_write(struct pci_dev *pdev, int offset,
				  __le32 val, int count)
{
	int ret = -EINVAL;
	u32 tmp_val = le32_to_cpu(val);

	switch (count) {
	case 1:
		ret = pci_user_write_config_byte(pdev, offset, tmp_val);
		break;
	case 2:
		ret = pci_user_write_config_word(pdev, offset, tmp_val);
		break;
	case 4:
		ret = pci_user_write_config_dword(pdev, offset, tmp_val);
		break;
	}

	return ret;
}

static int vfio_default_config_read(struct vfio_pci_core_device *vdev, int pos,
				    int count, struct perm_bits *perm,
				    int offset, __le32 *val)
{
	__le32 virt = 0;

	memcpy(val, vdev->vconfig + pos, count);

	memcpy(&virt, perm->virt + offset, count);

	/* Any non-virtualized bits? */
	if (cpu_to_le32(~0U >> (32 - (count * 8))) != virt) {
		struct pci_dev *pdev = vdev->pdev;
		__le32 phys_val = 0;
		int ret;

		ret = vfio_user_config_read(pdev, pos, &phys_val, count);
		if (ret)
			return ret;

		*val = (phys_val & ~virt) | (*val & virt);
	}

	return count;

Annotation

Implementation Notes