virtio: get class_id and pci device id by the virtio id

Add helpers to get the "Transitional PCI Device ID" and "class_id"
of the device specified by the "Virtio Device ID".

These helpers will be used to build the generic vDPA device later.

Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Longpeng <longpeng2@huawei.com>
Message-Id: <20221215134944.2809-2-longpeng2@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Longpeng 2022-12-15 21:49:40 +08:00 committed by Michael S. Tsirkin
parent ee1c08bd73
commit 2273324540
2 changed files with 93 additions and 0 deletions

View File

@ -19,6 +19,7 @@
#include "exec/memop.h"
#include "standard-headers/linux/virtio_pci.h"
#include "standard-headers/linux/virtio_ids.h"
#include "hw/boards.h"
#include "hw/virtio/virtio.h"
#include "migration/qemu-file-types.h"
@ -224,6 +225,90 @@ static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
return 0;
}
typedef struct VirtIOPCIIDInfo {
/* virtio id */
uint16_t vdev_id;
/* pci device id for the transitional device */
uint16_t trans_devid;
uint16_t class_id;
} VirtIOPCIIDInfo;
static const VirtIOPCIIDInfo virtio_pci_id_info[] = {
{
.vdev_id = VIRTIO_ID_CRYPTO,
.class_id = PCI_CLASS_OTHERS,
}, {
.vdev_id = VIRTIO_ID_FS,
.class_id = PCI_CLASS_STORAGE_OTHER,
}, {
.vdev_id = VIRTIO_ID_NET,
.trans_devid = PCI_DEVICE_ID_VIRTIO_NET,
.class_id = PCI_CLASS_NETWORK_ETHERNET,
}, {
.vdev_id = VIRTIO_ID_BLOCK,
.trans_devid = PCI_DEVICE_ID_VIRTIO_BLOCK,
.class_id = PCI_CLASS_STORAGE_SCSI,
}, {
.vdev_id = VIRTIO_ID_CONSOLE,
.trans_devid = PCI_DEVICE_ID_VIRTIO_CONSOLE,
.class_id = PCI_CLASS_COMMUNICATION_OTHER,
}, {
.vdev_id = VIRTIO_ID_SCSI,
.trans_devid = PCI_DEVICE_ID_VIRTIO_SCSI,
.class_id = PCI_CLASS_STORAGE_SCSI
}, {
.vdev_id = VIRTIO_ID_9P,
.trans_devid = PCI_DEVICE_ID_VIRTIO_9P,
.class_id = PCI_BASE_CLASS_NETWORK,
}, {
.vdev_id = VIRTIO_ID_BALLOON,
.trans_devid = PCI_DEVICE_ID_VIRTIO_BALLOON,
.class_id = PCI_CLASS_OTHERS,
}, {
.vdev_id = VIRTIO_ID_RNG,
.trans_devid = PCI_DEVICE_ID_VIRTIO_RNG,
.class_id = PCI_CLASS_OTHERS,
},
};
static const VirtIOPCIIDInfo *virtio_pci_get_id_info(uint16_t vdev_id)
{
const VirtIOPCIIDInfo *info = NULL;
int i;
for (i = 0; i < ARRAY_SIZE(virtio_pci_id_info); i++) {
if (virtio_pci_id_info[i].vdev_id == vdev_id) {
info = &virtio_pci_id_info[i];
break;
}
}
if (!info) {
/* The device id is invalid or not added to the id_info yet. */
error_report("Invalid virtio device(id %u)", vdev_id);
abort();
}
return info;
}
/*
* Get the Transitional Device ID for the specific device, return
* zero if the device is non-transitional.
*/
uint16_t virtio_pci_get_trans_devid(uint16_t device_id)
{
return virtio_pci_get_id_info(device_id)->trans_devid;
}
/*
* Get the Class ID for the specific device.
*/
uint16_t virtio_pci_get_class_id(uint16_t device_id)
{
return virtio_pci_get_id_info(device_id)->class_id;
}
static bool virtio_pci_ioeventfd_enabled(DeviceState *d)
{
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
@ -1729,6 +1814,9 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
* is set to PCI_SUBVENDOR_ID_REDHAT_QUMRANET by default.
*/
pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
if (proxy->trans_devid) {
pci_config_set_device_id(config, proxy->trans_devid);
}
} else {
/* pure virtio-1.0 */
pci_set_word(config + PCI_VENDOR_ID,

View File

@ -151,6 +151,8 @@ struct VirtIOPCIProxy {
bool disable_modern;
bool ignore_backend_features;
OnOffAuto disable_legacy;
/* Transitional device id */
uint16_t trans_devid;
uint32_t class_code;
uint32_t nvectors;
uint32_t dfselect;
@ -184,6 +186,9 @@ static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy)
proxy->disable_modern = true;
}
uint16_t virtio_pci_get_trans_devid(uint16_t device_id);
uint16_t virtio_pci_get_class_id(uint16_t device_id);
/*
* virtio-input-pci: This extends VirtioPCIProxy.
*/