// SPDX-License-Identifier: GPL-2.0-or-later /* * Virtio PCI driver - modern (virtio 1.0) device support * * This module allows virtio devices to be used over a virtual PCI device. * This can be used with QEMU based VMMs like KVM or Xen. * * Copyright IBM Corp. 2007 * Copyright Red Hat, Inc. 2014 * * Authors: * Anthony Liguori <aliguori@us.ibm.com> * Rusty Russell <rusty@rustcorp.com.au> * Michael S. Tsirkin <mst@redhat.com>
*/
spin_lock_irqsave(&admin_vq->lock, flags); do {
virtqueue_disable_cb(vq); 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);
}
/* Set the limit to the minimum value between the GET and SET values * supported by the device. Since the obj_id for VIRTIO_DEV_PARTS_CAP * is a globally unique value per PF, there is no possibility of * overlap between GET and SET operations.
*/
resource_objects_limit = min(result->get_parts_resource_objects_limit,
result->set_parts_resource_objects_limit);
result->get_parts_resource_objects_limit = resource_objects_limit;
result->set_parts_resource_objects_limit = resource_objects_limit;
memcpy(set_data->cap_specific_data, result, sizeof(*result));
sg_init_one(&data_sg, set_data, set_data_size);
cmd.data_sg = &data_sg;
cmd.result_sg = NULL;
cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_DRIVER_CAP_SET);
ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd); if (ret) goto err_set;
/* Allocate IDR to manage the dev caps objects */
ida_init(&vp_dev->admin_vq.dev_parts_ida);
vp_dev->admin_vq.max_dev_parts_objects = resource_objects_limit;
/* Give virtio_ring a chance to accept features. */
vring_transport_features(vdev);
/* Give virtio_pci a chance to accept features. */
vp_transport_features(vdev, features);
if (!__virtio_test_bit(vdev, VIRTIO_F_VERSION_1)) {
dev_err(&vdev->dev, "virtio: device uses modern interface " "but does not have VIRTIO_F_VERSION_1\n"); return -EINVAL;
}
/* We should never be setting status to 0. */
BUG_ON(status == 0);
vp_modern_set_status(&vp_dev->mdev, status); if (status & VIRTIO_CONFIG_S_DRIVER_OK)
vp_modern_avq_activate(vdev);
}
/* 0 status means a reset. */
vp_modern_set_status(mdev, 0); /* After writing 0 to device_status, the driver MUST wait for a read of * device_status to return 0 before reinitializing the device. * This will flush out the status write, and flush in device writes, * including MSI-X interrupts, if any.
*/ while (vp_modern_get_status(mdev))
msleep(1);
/* For the case where vq has an exclusive irq, call synchronize_irq() to * wait for completion. * * note: We can't use disable_irq() since it conflicts with the affinity * managed IRQ that is used by some drivers.
*/ if (vp_dev->per_vq_vectors && info->msix_vector != VIRTIO_MSI_NO_VECTOR)
synchronize_irq(pci_irq_vector(vp_dev->pci_dev, info->msix_vector));
num = vp_modern_get_queue_size(mdev, index); /* Check if queue is either not available or already active. */ if (!num || vp_modern_get_queue_enable(mdev, index)) return ERR_PTR(-ENOENT);
/* Select and activate all queues. Has to be done last: once we do * this, there's no way to go back except reset.
*/
list_for_each_entry(vq, &vdev->vqs, list)
vp_modern_set_queue_enable(&vp_dev->mdev, vq->index, true);
/* * virtio_pci_admin_mode_set - Sets the mode of a member device * @pdev: VF pci_dev * @flags: device mode's flags * * Note: caller must serialize access for the given device. * Returns 0 on success, or negative on failure.
*/ int virtio_pci_admin_mode_set(struct pci_dev *pdev, u8 flags)
{ struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev); struct virtio_admin_cmd_dev_mode_set_data *data; struct virtio_admin_cmd cmd = {}; struct scatterlist data_sg; int vf_id; int ret;
if (!virtio_dev) return -ENODEV;
vf_id = pci_iov_vf_id(pdev); if (vf_id < 0) return vf_id;
data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM;
/* * virtio_pci_admin_obj_create - Creates an object for a given type and operation, * following the max objects that can be created for that request. * @pdev: VF pci_dev * @obj_type: Object type * @operation_type: Operation type * @obj_id: Output unique object id * * Note: caller must serialize access for the given device. * Returns 0 on success, or negative on failure.
*/ int virtio_pci_admin_obj_create(struct pci_dev *pdev, u16 obj_type, u8 operation_type,
u32 *obj_id)
{ struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev);
u16 data_size = sizeof(struct virtio_admin_cmd_resource_obj_create_data); struct virtio_admin_cmd_resource_obj_create_data *obj_create_data; struct virtio_resource_obj_dev_parts obj_dev_parts = {}; struct virtio_pci_admin_vq *avq; struct virtio_admin_cmd cmd = {}; struct scatterlist data_sg; void *data; int id = -1; int vf_id; int ret;
if (!virtio_dev) return -ENODEV;
vf_id = pci_iov_vf_id(pdev); if (vf_id < 0) return vf_id;
if (obj_type != VIRTIO_RESOURCE_OBJ_DEV_PARTS) return -EOPNOTSUPP;
if (operation_type != VIRTIO_RESOURCE_OBJ_DEV_PARTS_TYPE_GET &&
operation_type != VIRTIO_RESOURCE_OBJ_DEV_PARTS_TYPE_SET) return -EINVAL;
avq = &to_vp_device(virtio_dev)->admin_vq; if (!avq->max_dev_parts_objects) return -EOPNOTSUPP;
id = ida_alloc_range(&avq->dev_parts_ida, 0,
avq->max_dev_parts_objects - 1, GFP_KERNEL); if (id < 0) return id;
*obj_id = id;
data_size += sizeof(obj_dev_parts);
data = kzalloc(data_size, GFP_KERNEL); if (!data) {
ret = -ENOMEM; goto end;
}
/* * virtio_pci_admin_obj_destroy - Destroys an object of a given type and id * @pdev: VF pci_dev * @obj_type: Object type * @id: Object id * * Note: caller must serialize access for the given device. * Returns 0 on success, or negative on failure.
*/ int virtio_pci_admin_obj_destroy(struct pci_dev *pdev, u16 obj_type, u32 id)
{ struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev); struct virtio_admin_cmd_resource_obj_cmd_hdr *data; struct virtio_pci_device *vp_dev; struct virtio_admin_cmd cmd = {}; struct scatterlist data_sg; int vf_id; int ret;
if (!virtio_dev) return -ENODEV;
vf_id = pci_iov_vf_id(pdev); if (vf_id < 0) return vf_id;
if (obj_type != VIRTIO_RESOURCE_OBJ_DEV_PARTS) return -EINVAL;
data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM;
/* * virtio_pci_admin_dev_parts_metadata_get - Gets the metadata of the device parts * identified by the below attributes. * @pdev: VF pci_dev * @obj_type: Object type * @id: Object id * @metadata_type: Metadata type * @out: Upon success holds the output for 'metadata type size' * * Note: caller must serialize access for the given device. * Returns 0 on success, or negative on failure.
*/ int virtio_pci_admin_dev_parts_metadata_get(struct pci_dev *pdev, u16 obj_type,
u32 id, u8 metadata_type, u32 *out)
{ struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev); struct virtio_admin_cmd_dev_parts_metadata_result *result; struct virtio_admin_cmd_dev_parts_metadata_data *data; struct scatterlist data_sg, result_sg; struct virtio_admin_cmd cmd = {}; int vf_id; int ret;
if (!virtio_dev) return -ENODEV;
if (metadata_type != VIRTIO_ADMIN_CMD_DEV_PARTS_METADATA_TYPE_SIZE) return -EOPNOTSUPP;
vf_id = pci_iov_vf_id(pdev); if (vf_id < 0) return vf_id;
data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM;
result = kzalloc(sizeof(*result), GFP_KERNEL); if (!result) {
ret = -ENOMEM; goto end;
}
/* * virtio_pci_admin_dev_parts_get - Gets the device parts identified by the below attributes. * @pdev: VF pci_dev * @obj_type: Object type * @id: Object id * @get_type: Get type * @res_sg: Upon success holds the output result data * @res_size: Upon success holds the output result size * * Note: caller must serialize access for the given device. * Returns 0 on success, or negative on failure.
*/ int virtio_pci_admin_dev_parts_get(struct pci_dev *pdev, u16 obj_type, u32 id,
u8 get_type, struct scatterlist *res_sg,
u32 *res_size)
{ struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev); struct virtio_admin_cmd_dev_parts_get_data *data; struct scatterlist data_sg; struct virtio_admin_cmd cmd = {}; int vf_id; int ret;
if (!virtio_dev) return -ENODEV;
if (get_type != VIRTIO_ADMIN_CMD_DEV_PARTS_GET_TYPE_ALL) return -EOPNOTSUPP;
vf_id = pci_iov_vf_id(pdev); if (vf_id < 0) return vf_id;
data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM;
/* * virtio_pci_admin_dev_parts_set - Sets the device parts identified by the below attributes. * @pdev: VF pci_dev * @data_sg: The device parts data, its layout follows struct virtio_admin_cmd_dev_parts_set_data * * Note: caller must serialize access for the given device. * Returns 0 on success, or negative on failure.
*/ int virtio_pci_admin_dev_parts_set(struct pci_dev *pdev, struct scatterlist *data_sg)
{ struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev); struct virtio_admin_cmd cmd = {}; int vf_id;
if (!virtio_dev) return -ENODEV;
vf_id = pci_iov_vf_id(pdev); if (vf_id < 0) return vf_id;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.