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 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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. #include "etherboot.h"
  17. #include "gpxe/io.h"
  18. #include "gpxe/virtio-ring.h"
  19. #include "gpxe/virtio-pci.h"
  20. #define BUG() do { \
  21. printf("BUG: failure at %s:%d/%s()!\n", \
  22. __FILE__, __LINE__, __FUNCTION__); \
  23. while(1); \
  24. } while (0)
  25. #define BUG_ON(condition) do { if (condition) BUG(); } while (0)
  26. /*
  27. * vring_free
  28. *
  29. * put at the begin of the free list the current desc[head]
  30. */
  31. void vring_detach(struct vring_virtqueue *vq, unsigned int head)
  32. {
  33. struct vring *vr = &vq->vring;
  34. unsigned int i;
  35. /* find end of given descriptor */
  36. i = head;
  37. while (vr->desc[i].flags & VRING_DESC_F_NEXT)
  38. i = vr->desc[i].next;
  39. /* link it with free list and point to it */
  40. vr->desc[i].next = vq->free_head;
  41. wmb();
  42. vq->free_head = head;
  43. }
  44. /*
  45. * vring_get_buf
  46. *
  47. * get a buffer from the used list
  48. *
  49. */
  50. int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
  51. {
  52. struct vring *vr = &vq->vring;
  53. struct vring_used_elem *elem;
  54. u32 id;
  55. int ret;
  56. BUG_ON(!vring_more_used(vq));
  57. elem = &vr->used->ring[vq->last_used_idx % vr->num];
  58. wmb();
  59. id = elem->id;
  60. if (len != NULL)
  61. *len = elem->len;
  62. ret = vq->vdata[id];
  63. vring_detach(vq, id);
  64. vq->last_used_idx++;
  65. return ret;
  66. }
  67. void vring_add_buf(struct vring_virtqueue *vq,
  68. struct vring_list list[],
  69. unsigned int out, unsigned int in,
  70. int index, int num_added)
  71. {
  72. struct vring *vr = &vq->vring;
  73. int i, avail, head, prev;
  74. BUG_ON(out + in == 0);
  75. prev = 0;
  76. head = vq->free_head;
  77. for (i = head; out; i = vr->desc[i].next, out--) {
  78. vr->desc[i].flags = VRING_DESC_F_NEXT;
  79. vr->desc[i].addr = (u64)virt_to_phys(list->addr);
  80. vr->desc[i].len = list->length;
  81. prev = i;
  82. list++;
  83. }
  84. for ( ; in; i = vr->desc[i].next, in--) {
  85. vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
  86. vr->desc[i].addr = (u64)virt_to_phys(list->addr);
  87. vr->desc[i].len = list->length;
  88. prev = i;
  89. list++;
  90. }
  91. vr->desc[prev].flags &= ~VRING_DESC_F_NEXT;
  92. vq->free_head = i;
  93. vq->vdata[head] = index;
  94. avail = (vr->avail->idx + num_added) % vr->num;
  95. vr->avail->ring[avail] = head;
  96. wmb();
  97. }
  98. void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
  99. {
  100. struct vring *vr = &vq->vring;
  101. wmb();
  102. vr->avail->idx += num_added;
  103. mb();
  104. if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY))
  105. vp_notify(ioaddr, vq->queue_index);
  106. }