drivers/virtio/virtio_pci_modern.c

Source file repositories/reference/linux-study-clean/drivers/virtio/virtio_pci_modern.c

File Facts

System
Linux kernel
Corpus path
drivers/virtio/virtio_pci_modern.c
Extension
.c
Size
34551 bytes
Lines
1302
Domain
Driver Families
Bucket
drivers/virtio
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

while ((cmd = virtqueue_get_buf(vq, &len))) {
			/* If the number of bytes written by the device is less
			 * than the size of struct virtio_admin_cmd_status, the
			 * remaining status bytes will remain zero-initialized,
			 * since the buffer was zeroed during allocation.
			 * In this case, set the size of command_specific_result
			 * to 0.
			 */
			if (len < status_size)
				cmd->result_sg_size = 0;
			else
				cmd->result_sg_size = len - status_size;
			complete(&cmd->completion);
		}
	} while (!virtqueue_enable_cb(vq));
	spin_unlock_irqrestore(&admin_vq->lock, flags);
}

static int virtqueue_exec_admin_cmd(struct virtio_pci_admin_vq *admin_vq,
				    u16 opcode,
				    struct scatterlist **sgs,
				    unsigned int out_num,
				    unsigned int in_num,
				    struct virtio_admin_cmd *cmd)
{
	struct virtqueue *vq;
	unsigned long flags;
	int ret;

	vq = admin_vq->info->vq;
	if (!vq)
		return -EIO;

	if (opcode != VIRTIO_ADMIN_CMD_LIST_QUERY &&
	    opcode != VIRTIO_ADMIN_CMD_LIST_USE &&
	    !((1ULL << opcode) & admin_vq->supported_cmds))
		return -EOPNOTSUPP;

	init_completion(&cmd->completion);

again:
	if (virtqueue_is_broken(vq))
		return -EIO;

	spin_lock_irqsave(&admin_vq->lock, flags);
	ret = virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, GFP_KERNEL);
	if (ret < 0) {
		if (ret == -ENOSPC) {
			spin_unlock_irqrestore(&admin_vq->lock, flags);
			cpu_relax();
			goto again;
		}
		goto unlock_err;
	}
	if (!virtqueue_kick(vq))
		goto unlock_err;
	spin_unlock_irqrestore(&admin_vq->lock, flags);

	wait_for_completion(&cmd->completion);

	return cmd->ret;

unlock_err:
	spin_unlock_irqrestore(&admin_vq->lock, flags);
	return -EIO;
}

int vp_modern_admin_cmd_exec(struct virtio_device *vdev,
			     struct virtio_admin_cmd *cmd)
{
	struct scatterlist *sgs[VIRTIO_AVQ_SGS_MAX], hdr, stat;
	struct virtio_pci_device *vp_dev = to_vp_device(vdev);
	struct virtio_admin_cmd_status *va_status;
	unsigned int out_num = 0, in_num = 0;
	struct virtio_admin_cmd_hdr *va_hdr;
	u16 status;
	int ret;

	if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
		return -EOPNOTSUPP;

	va_status = kzalloc_obj(*va_status);
	if (!va_status)
		return -ENOMEM;

	va_hdr = kzalloc_obj(*va_hdr);
	if (!va_hdr) {
		ret = -ENOMEM;
		goto err_alloc;
	}

Annotation

Implementation Notes