drivers/vfio/pci/virtio/legacy_io.c

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

File Facts

System
Linux kernel
Corpus path
drivers/vfio/pci/virtio/legacy_io.c
Extension
.c
Size
11293 bytes
Lines
397
Domain
Driver Families
Bucket
drivers/vfio
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

if (count != sizeof(queue_notify)) {
			ret = -EINVAL;
			goto end;
		}
		if (read) {
			ret = vfio_pci_core_ioread16(core_device, true, &queue_notify,
						     virtvdev->notify_addr);
			if (ret)
				goto end;
			if (copy_to_user(buf, &queue_notify,
					 sizeof(queue_notify))) {
				ret = -EFAULT;
				goto end;
			}
		} else {
			if (copy_from_user(&queue_notify, buf, count)) {
				ret = -EFAULT;
				goto end;
			}
			ret = vfio_pci_core_iowrite16(core_device, true, queue_notify,
						      virtvdev->notify_addr);
		}
		break;
	default:
		ret = virtiovf_issue_legacy_rw_cmd(virtvdev, pos, buf, count,
						   read);
	}

end:
	pm_runtime_put(&pdev->dev);
	return ret ? ret : count;
}

static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev,
					char __user *buf, size_t count,
					loff_t *ppos)
{
	struct virtiovf_pci_core_device *virtvdev = container_of(
		core_vdev, struct virtiovf_pci_core_device, core_device.vdev);
	loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
	size_t register_offset;
	loff_t copy_offset;
	size_t copy_count;
	__le32 val32;
	__le16 val16;
	u8 val8;
	int ret;

	ret = vfio_pci_core_read(core_vdev, buf, count, ppos);
	if (ret < 0)
		return ret;

	if (vfio_pci_core_range_intersect_range(pos, count, PCI_DEVICE_ID,
						sizeof(val16), &copy_offset,
						&copy_count, &register_offset)) {
		val16 = cpu_to_le16(VIRTIO_TRANS_ID_NET);
		if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, copy_count))
			return -EFAULT;
	}

	if ((le16_to_cpu(virtvdev->pci_cmd) & PCI_COMMAND_IO) &&
	    vfio_pci_core_range_intersect_range(pos, count, PCI_COMMAND,
						sizeof(val16), &copy_offset,
						&copy_count, &register_offset)) {
		if (copy_from_user((void *)&val16 + register_offset, buf + copy_offset,
				   copy_count))
			return -EFAULT;
		val16 |= cpu_to_le16(PCI_COMMAND_IO);
		if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset,
				 copy_count))
			return -EFAULT;
	}

	if (vfio_pci_core_range_intersect_range(pos, count, PCI_REVISION_ID,
						sizeof(val8), &copy_offset,
						&copy_count, &register_offset)) {
		/* Transional needs to have revision 0 */
		val8 = 0;
		if (copy_to_user(buf + copy_offset, &val8, copy_count))
			return -EFAULT;
	}

	if (vfio_pci_core_range_intersect_range(pos, count, PCI_BASE_ADDRESS_0,
						sizeof(val32), &copy_offset,
						&copy_count, &register_offset)) {
		u32 bar_mask = ~(virtvdev->bar0_virtual_buf_size - 1);
		u32 pci_base_addr_0 = le32_to_cpu(virtvdev->pci_base_addr_0);

		val32 = cpu_to_le32((pci_base_addr_0 & bar_mask) | PCI_BASE_ADDRESS_SPACE_IO);
		if (copy_to_user(buf + copy_offset, (void *)&val32 + register_offset, copy_count))

Annotation

Implementation Notes