Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

virtio: add VIRTIO_F_NOTIFICATION_DATA feature support

According to VirtIO spec v1.2, VIRTIO_F_NOTIFICATION_DATA feature
indicates that the driver passes extra data along with the queue
notifications.

In a split queue case, the extra data is 16-bit available index. In a
packed queue case, the extra data is 1-bit wrap counter and 15-bit
available index.

Add support for this feature for MMIO, channel I/O and modern PCI
transports.

Signed-off-by: Viktor Prutyanov <viktor@daynix.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Reviewed-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Message-Id: <20230413081855.36643-2-alvaro.karsz@solid-run.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

authored by

Viktor Prutyanov and committed by
Michael S. Tsirkin
af8ececd 3616bf37

+79 -5
+19 -3
drivers/s390/virtio/virtio_ccw.c
··· 391 391 ccw_device_dma_free(vcdev->cdev, thinint_area, sizeof(*thinint_area)); 392 392 } 393 393 394 - static bool virtio_ccw_kvm_notify(struct virtqueue *vq) 394 + static inline bool virtio_ccw_do_kvm_notify(struct virtqueue *vq, u32 data) 395 395 { 396 396 struct virtio_ccw_vq_info *info = vq->priv; 397 397 struct virtio_ccw_device *vcdev; ··· 402 402 BUILD_BUG_ON(sizeof(struct subchannel_id) != sizeof(unsigned int)); 403 403 info->cookie = kvm_hypercall3(KVM_S390_VIRTIO_CCW_NOTIFY, 404 404 *((unsigned int *)&schid), 405 - vq->index, info->cookie); 405 + data, info->cookie); 406 406 if (info->cookie < 0) 407 407 return false; 408 408 return true; 409 + } 410 + 411 + static bool virtio_ccw_kvm_notify(struct virtqueue *vq) 412 + { 413 + return virtio_ccw_do_kvm_notify(vq, vq->index); 414 + } 415 + 416 + static bool virtio_ccw_kvm_notify_with_data(struct virtqueue *vq) 417 + { 418 + return virtio_ccw_do_kvm_notify(vq, vring_notification_data(vq)); 409 419 } 410 420 411 421 static int virtio_ccw_read_vq_conf(struct virtio_ccw_device *vcdev, ··· 505 495 struct ccw1 *ccw) 506 496 { 507 497 struct virtio_ccw_device *vcdev = to_vc_device(vdev); 498 + bool (*notify)(struct virtqueue *vq); 508 499 int err; 509 500 struct virtqueue *vq = NULL; 510 501 struct virtio_ccw_vq_info *info; 511 502 u64 queue; 512 503 unsigned long flags; 513 504 bool may_reduce; 505 + 506 + if (__virtio_test_bit(vdev, VIRTIO_F_NOTIFICATION_DATA)) 507 + notify = virtio_ccw_kvm_notify_with_data; 508 + else 509 + notify = virtio_ccw_kvm_notify; 514 510 515 511 /* Allocate queue. */ 516 512 info = kzalloc(sizeof(struct virtio_ccw_vq_info), GFP_KERNEL); ··· 540 524 may_reduce = vcdev->revision > 0; 541 525 vq = vring_create_virtqueue(i, info->num, KVM_VIRTIO_CCW_RING_ALIGN, 542 526 vdev, true, may_reduce, ctx, 543 - virtio_ccw_kvm_notify, callback, name); 527 + notify, callback, name); 544 528 545 529 if (!vq) { 546 530 /* For now, we fail if we can't get the requested size. */
+17 -1
drivers/virtio/virtio_mmio.c
··· 285 285 return true; 286 286 } 287 287 288 + static bool vm_notify_with_data(struct virtqueue *vq) 289 + { 290 + struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vq->vdev); 291 + u32 data = vring_notification_data(vq); 292 + 293 + writel(data, vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY); 294 + 295 + return true; 296 + } 297 + 288 298 /* Notify all virtqueues on an interrupt. */ 289 299 static irqreturn_t vm_interrupt(int irq, void *opaque) 290 300 { ··· 373 363 const char *name, bool ctx) 374 364 { 375 365 struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); 366 + bool (*notify)(struct virtqueue *vq); 376 367 struct virtio_mmio_vq_info *info; 377 368 struct virtqueue *vq; 378 369 unsigned long flags; 379 370 unsigned int num; 380 371 int err; 372 + 373 + if (__virtio_test_bit(vdev, VIRTIO_F_NOTIFICATION_DATA)) 374 + notify = vm_notify_with_data; 375 + else 376 + notify = vm_notify; 381 377 382 378 if (!name) 383 379 return NULL; ··· 413 397 414 398 /* Create the vring */ 415 399 vq = vring_create_virtqueue(index, num, VIRTIO_MMIO_VRING_ALIGN, vdev, 416 - true, true, ctx, vm_notify, callback, name); 400 + true, true, ctx, notify, callback, name); 417 401 if (!vq) { 418 402 err = -ENOMEM; 419 403 goto error_new_virtqueue;
+16 -1
drivers/virtio/virtio_pci_modern.c
··· 288 288 return vp_modern_config_vector(&vp_dev->mdev, vector); 289 289 } 290 290 291 + static bool vp_notify_with_data(struct virtqueue *vq) 292 + { 293 + u32 data = vring_notification_data(vq); 294 + 295 + iowrite32(data, (void __iomem *)vq->priv); 296 + 297 + return true; 298 + } 299 + 291 300 static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, 292 301 struct virtio_pci_vq_info *info, 293 302 unsigned int index, ··· 307 298 { 308 299 309 300 struct virtio_pci_modern_device *mdev = &vp_dev->mdev; 301 + bool (*notify)(struct virtqueue *vq); 310 302 struct virtqueue *vq; 311 303 u16 num; 312 304 int err; 305 + 306 + if (__virtio_test_bit(&vp_dev->vdev, VIRTIO_F_NOTIFICATION_DATA)) 307 + notify = vp_notify_with_data; 308 + else 309 + notify = vp_notify; 313 310 314 311 if (index >= vp_modern_get_num_queues(mdev)) 315 312 return ERR_PTR(-EINVAL); ··· 331 316 vq = vring_create_virtqueue(index, num, 332 317 SMP_CACHE_BYTES, &vp_dev->vdev, 333 318 true, true, ctx, 334 - vp_notify, callback, name); 319 + notify, callback, name); 335 320 if (!vq) 336 321 return ERR_PTR(-ENOMEM); 337 322
+19
drivers/virtio/virtio_ring.c
··· 2762 2762 } 2763 2763 EXPORT_SYMBOL_GPL(vring_del_virtqueue); 2764 2764 2765 + u32 vring_notification_data(struct virtqueue *_vq) 2766 + { 2767 + struct vring_virtqueue *vq = to_vvq(_vq); 2768 + u16 next; 2769 + 2770 + if (vq->packed_ring) 2771 + next = (vq->packed.next_avail_idx & 2772 + ~(-(1 << VRING_PACKED_EVENT_F_WRAP_CTR))) | 2773 + vq->packed.avail_wrap_counter << 2774 + VRING_PACKED_EVENT_F_WRAP_CTR; 2775 + else 2776 + next = vq->split.avail_idx_shadow; 2777 + 2778 + return next << 16 | _vq->index; 2779 + } 2780 + EXPORT_SYMBOL_GPL(vring_notification_data); 2781 + 2765 2782 /* Manipulates transport-specific feature bits. */ 2766 2783 void vring_transport_features(struct virtio_device *vdev) 2767 2784 { ··· 2797 2780 case VIRTIO_F_RING_PACKED: 2798 2781 break; 2799 2782 case VIRTIO_F_ORDER_PLATFORM: 2783 + break; 2784 + case VIRTIO_F_NOTIFICATION_DATA: 2800 2785 break; 2801 2786 default: 2802 2787 /* We don't understand this bit. */
+2
include/linux/virtio_ring.h
··· 117 117 void vring_transport_features(struct virtio_device *vdev); 118 118 119 119 irqreturn_t vring_interrupt(int irq, void *_vq); 120 + 121 + u32 vring_notification_data(struct virtqueue *_vq); 120 122 #endif /* _LINUX_VIRTIO_RING_H */
+6
include/uapi/linux/virtio_config.h
··· 100 100 #define VIRTIO_F_SR_IOV 37 101 101 102 102 /* 103 + * This feature indicates that the driver passes extra data (besides 104 + * identifying the virtqueue) in its device notifications. 105 + */ 106 + #define VIRTIO_F_NOTIFICATION_DATA 38 107 + 108 + /* 103 109 * This feature indicates that the driver can reset a queue individually. 104 110 */ 105 111 #define VIRTIO_F_RING_RESET 40