You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

virtio-ring.c 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /* virtio-pci.c - virtio ring management
  2. *
  3. * (c) Copyright 2008 Bull S.A.S.
  4. *
  5. * Author: Laurent Vivier <Laurent.Vivier@bull.net>
  6. *
  7. * some parts from Linux Virtio Ring
  8. *
  9. * Copyright Rusty Russell IBM Corporation 2007
  10. *
  11. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  12. * See the COPYING file in the top-level directory.
  13. *
  14. *
  15. */
  16. FILE_LICENCE ( GPL2_OR_LATER );
  17. #include "etherboot.h"
  18. #include "ipxe/io.h"
  19. #include "ipxe/virtio-pci.h"
  20. #include "ipxe/virtio-ring.h"
  21. #define BUG() do { \
  22. printf("BUG: failure at %s:%d/%s()!\n", \
  23. __FILE__, __LINE__, __FUNCTION__); \
  24. while(1); \
  25. } while (0)
  26. #define BUG_ON(condition) do { if (condition) BUG(); } while (0)
  27. /*
  28. * vring_free
  29. *
  30. * put at the begin of the free list the current desc[head]
  31. */
  32. void vring_detach(struct vring_virtqueue *vq, unsigned int head)
  33. {
  34. struct vring *vr = &vq->vring;
  35. unsigned int i;
  36. /* find end of given descriptor */
  37. i = head;
  38. while (vr->desc[i].flags & VRING_DESC_F_NEXT)
  39. i = vr->desc[i].next;
  40. /* link it with free list and point to it */
  41. vr->desc[i].next = vq->free_head;
  42. wmb();
  43. vq->free_head = head;
  44. }
  45. /*
  46. * vring_get_buf
  47. *
  48. * get a buffer from the used list
  49. *
  50. */
  51. void *vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
  52. {
  53. struct vring *vr = &vq->vring;
  54. struct vring_used_elem *elem;
  55. u32 id;
  56. void *opaque;
  57. BUG_ON(!vring_more_used(vq));
  58. elem = &vr->used->ring[vq->last_used_idx % vr->num];
  59. wmb();
  60. id = elem->id;
  61. if (len != NULL)
  62. *len = elem->len;
  63. opaque = vq->vdata[id];
  64. vring_detach(vq, id);
  65. vq->last_used_idx++;
  66. return opaque;
  67. }
  68. void vring_add_buf(struct vring_virtqueue *vq,
  69. struct vring_list list[],
  70. unsigned int out, unsigned int in,
  71. void *opaque, int num_added)
  72. {
  73. struct vring *vr = &vq->vring;
  74. int i, avail, head, prev;
  75. BUG_ON(out + in == 0);
  76. prev = 0;
  77. head = vq->free_head;
  78. for (i = head; out; i = vr->desc[i].next, out--) {
  79. vr->desc[i].flags = VRING_DESC_F_NEXT;
  80. vr->desc[i].addr = (u64)virt_to_phys(list->addr);
  81. vr->desc[i].len = list->length;
  82. prev = i;
  83. list++;
  84. }
  85. for ( ; in; i = vr->desc[i].next, in--) {
  86. vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
  87. vr->desc[i].addr = (u64)virt_to_phys(list->addr);
  88. vr->desc[i].len = list->length;
  89. prev = i;
  90. list++;
  91. }
  92. vr->desc[prev].flags &= ~VRING_DESC_F_NEXT;
  93. vq->free_head = i;
  94. vq->vdata[head] = opaque;
  95. avail = (vr->avail->idx + num_added) % vr->num;
  96. vr->avail->ring[avail] = head;
  97. wmb();
  98. }
  99. void vring_kick(struct virtio_pci_modern_device *vdev, unsigned int ioaddr,
  100. struct vring_virtqueue *vq, int num_added)
  101. {
  102. struct vring *vr = &vq->vring;
  103. wmb();
  104. vr->avail->idx += num_added;
  105. mb();
  106. if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY)) {
  107. if (vdev) {
  108. /* virtio 1.0 */
  109. vpm_notify(vdev, vq);
  110. } else {
  111. /* legacy virtio */
  112. vp_notify(ioaddr, vq->queue_index);
  113. }
  114. }
  115. }