spec描述
驱动初始化探测的大致过程:
virtio_pci_probe->pci_enable_device->virtio_pci_modern_probe->register_virtio_device->virtio_dev_probe
virtio_pci_modern_probe->设置回调vp_config_vector->设置回调setup_vq
drivers/virtio/virtio_pci_common.c
virtblk_probe->init_vq(virtio_blk.c)->virtio_find_vqs->find_vqs->vp_modern_find_vqs->vp_find_vqs->vp_find_vqs_msix->vp_request_msix_vectors->vp_setup_vq->setup_vq->request_irq->vring_interrupt
virtnet_probe->init_vqs->virtnet_find_vqs->find_vqs->同上
例如virtio_net驱动中用于初始化queue,创建网络设备并初始化一些必要的数据结构
当后端模拟出virtio_net设备后,驱动扫描到virtio设备,然后调用virtio_pci_driver中virtio_pci_probe函数完成pci设备的启动。
注册一条virtio_bus,同时在virtio总线进行注册设备。当virtio总线进行注册设备register_virtio_device,设置virtio总线后将调用virtio总线的probe函数:virtio_dev_probe。
该函数遍历驱动,找到支持驱动关联到该设备并且调用
virtio_driver probe,virtnet_probe函数
static int virtio_dev_probe(struct device *_d)
{
int err, i;
struct virtio_device *dev = dev_to_virtio(_d);
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
u64 device_features;
u64 driver_features;
u64 driver_features_legacy;
/* We have a driver! */
virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER);//置位状态,知道是什么驱动
/* Figure out what features the device supports.
* 回调函数vp_get_features->vp_modern_get_features
* vp_modern_get_features 中会和后端设备协商feature
*/
device_features = dev->config->get_features(dev);
/* Figure out what features the driver supports. */
driver_features = 0;
for (i = 0; i < drv->feature_table_size; i++) {
unsigned int f = drv->feature_table[i];
BUG_ON(f >= 64);
driver_features |= (1ULL << f);
}
/* Some drivers have a separate feature table for virtio v1.0 */
if (drv->feature_table_legacy) {
driver_features_legacy = 0;
for (i = 0; i < drv->feature_table_size_legacy; i++) {
unsigned int f = drv->feature_table_legacy[i];
BUG_ON(f >= 64);
driver_features_legacy |= (1ULL << f);
}
} else {
driver_features_legacy = driver_features;
}
if (device_features & (1ULL << VIRTIO_F_VERSION_1))
dev->features = driver_features & device_features;
else
dev->features = driver_features_legacy & device_features;
/* Transport features always preserved to pass to finalize_features. */
for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++)
if (device_features & (1ULL << i))
__virtio_set_bit(dev, i);
if (drv->validate) {
err = drv->validate(dev);
if (err)
goto err;
}
// 协商结果,成功会置位VIRTIO_CONFIG_S_FEATURES_OK,表示前后端协商成功
err = virtio_finalize_features(dev);
if (err)
goto err;
err = drv->probe(dev); //virtio_drive回调函数 virtnet_probe 或者 virtblk_probe
if (err)
goto err;
/* If probe didn't do it, mark device DRIVER_OK ourselves. */
if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK))
virtio_device_ready(dev);
if (drv->scan)
drv->scan(dev);
virtio_config_enable(dev);
return 0;
err:
virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
return err;
}
下面分别描述探测过程中几个状态的前端发生过程。
VIRTIO_CONFIG_S_ACKNOWLEDGE
前端:
virtio_pci_probe ->register_virtio_device
->virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);//通知后端已发现此virtio设备
后端
todo
VIRTIO_CONFIG_S_DRIVER
virtio_dev_probe->virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER)
VIRTIO_CONFIG_S_FEATURES_OK
virtio_dev_probe->>virtio_finalize_features
virtio_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK);
VIRTIO_CONFIG_S_DRIVER_OK
virtio_dev_probe->virtio_device_ready-
dev->config->set_status(dev, status | VIRTIO_CONFIG_S_DRIVER_OK);
后端:(以qemu为例)
hw/virtio/virtio-pci.c: virtio_pci_bus_class_init->virtio_pci_device_plugged->
virtio_pci_modern_regions_init->virtio_pci_common_write->
case VIRTIO_PCI_COMMON_STATUS:
if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
virtio_pci_stop_ioeventfd(proxy);
}
virtio_set_status(vdev, val & 0xFF);
if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
virtio_pci_start_ioeventfd(proxy);//启动ioeventfd
}
if (vdev->status == 0) {
virtio_pci_reset(DEVICE(proxy));
}